Repository: ignite
Updated Branches:
  refs/heads/master 82504a0e5 -> 00902afbb


IGNITE-3587: ODBC: Added distributed joins support. This closes #908.


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

Branch: refs/heads/master
Commit: 311428eee8d52640a6efdac721335f63a4244d38
Parents: a596e67
Author: isapego <isap...@gridgain.com>
Authored: Fri Aug 5 10:38:50 2016 +0300
Committer: vozerov-gridgain <voze...@gridgain.com>
Committed: Fri Aug 5 10:38:50 2016 +0300

----------------------------------------------------------------------
 .../processors/odbc/OdbcHandshakeRequest.java   |  42 +++-
 .../processors/odbc/OdbcHandshakeResult.java    |  17 +-
 .../processors/odbc/OdbcMessageParser.java      |  34 ++-
 .../processors/odbc/OdbcProtocolVersion.java    | 125 +++++++++++
 .../processors/odbc/OdbcRequestHandler.java     |  26 ++-
 modules/platforms/cpp/odbc-test/Makefile.am     |   1 +
 .../odbc-test/config/queries-test-noodbc.xml    | 103 +++++++++
 .../cpp/odbc-test/config/queries-test.xml       |  45 ++--
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   3 +
 .../cpp/odbc-test/src/configuration_test.cpp    | 148 +++++++++++--
 .../cpp/odbc-test/src/queries_test.cpp          | 218 +++++++++++++++++--
 modules/platforms/cpp/odbc/Makefile.am          |   1 +
 modules/platforms/cpp/odbc/include/Makefile.am  |   1 +
 .../cpp/odbc/include/ignite/odbc/common_types.h |   3 +
 .../include/ignite/odbc/config/configuration.h  |  67 +++++-
 .../cpp/odbc/include/ignite/odbc/connection.h   |  16 +-
 .../cpp/odbc/include/ignite/odbc/message.h      |  35 ++-
 .../cpp/odbc/include/ignite/odbc/parser.h       |   3 -
 .../odbc/include/ignite/odbc/protocol_version.h | 172 +++++++++++++++
 .../platforms/cpp/odbc/project/vs/odbc.vcxproj  |   2 +
 .../cpp/odbc/project/vs/odbc.vcxproj.filters    |   6 +
 .../cpp/odbc/src/config/configuration.cpp       |  92 ++++++--
 modules/platforms/cpp/odbc/src/connection.cpp   |  23 +-
 .../odbc/src/diagnostic/diagnostic_record.cpp   |   6 +
 .../platforms/cpp/odbc/src/protocol_version.cpp | 134 ++++++++++++
 26 files changed, 1204 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeRequest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeRequest.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeRequest.java
index 5e09041..55ff21f 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeRequest.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeRequest.java
@@ -24,24 +24,58 @@ import org.apache.ignite.internal.util.typedef.internal.S;
  */
 public class OdbcHandshakeRequest extends OdbcRequest {
     /** Protocol version. */
-    private final long ver;
+    private final OdbcProtocolVersion ver;
+
+    /** Distributed joins flag. */
+    private boolean distributedJoins = false;
+
+    /** Enforce join order flag. */
+    private boolean enforceJoinOrder = false;
 
     /**
-     * @param ver Protocol version.
+     * @param ver Long value for protocol version.
      */
     public OdbcHandshakeRequest(long ver) {
         super(HANDSHAKE);
 
-        this.ver = ver;
+        this.ver = OdbcProtocolVersion.fromLong(ver);
     }
 
     /**
      * @return Protocol version.
      */
-    public long version() {
+    public OdbcProtocolVersion version() {
         return ver;
     }
 
+    /**
+     * @return Distributed joins flag.
+     */
+    public boolean distributedJoins() {
+        return distributedJoins;
+    }
+
+    /**
+     * @param distributedJoins Distributed joins flag.
+     */
+    public void distributedJoins(boolean distributedJoins) {
+        this.distributedJoins = distributedJoins;
+    }
+
+    /**
+     * @return Enforce join order flag.
+     */
+    public boolean enforceJoinOrder() {
+        return enforceJoinOrder;
+    }
+
+    /**
+     * @param enforceJoinOrder Enforce join order flag.
+     */
+    public void enforceJoinOrder(boolean enforceJoinOrder) {
+        this.enforceJoinOrder = enforceJoinOrder;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(OdbcHandshakeRequest.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeResult.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeResult.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeResult.java
index bf1c61e..74c5bd4 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeResult.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcHandshakeResult.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.internal.processors.odbc;
 
-import org.jetbrains.annotations.Nullable;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 /**
  * ODBC handshake result.
@@ -33,11 +33,13 @@ public class OdbcHandshakeResult {
     private final String curVer;
 
     /**
-     * @param accepted Handshake accepted.
+     * Constructor.
+     *
+     * @param accepted Indicates whether handshake accepted or not.
      * @param protoVerSince Apache Ignite version when protocol version has 
been introduced.
      * @param curVer Current Apache Ignite version.
      */
-    public OdbcHandshakeResult(boolean accepted, @Nullable String 
protoVerSince, @Nullable String curVer) {
+    public OdbcHandshakeResult(boolean accepted, String protoVerSince, String 
curVer) {
         this.accepted = accepted;
         this.protoVerSince = protoVerSince;
         this.curVer = curVer;
@@ -53,14 +55,19 @@ public class OdbcHandshakeResult {
     /**
      * @return Apache Ignite version when protocol version has been introduced.
      */
-    @Nullable public String protoVerSince() {
+    public String protocolVersionSince() {
         return protoVerSince;
     }
 
     /**
      * @return Current Apache Ignite version.
      */
-    @Nullable public String currentVer() {
+    public String currentVersion() {
         return curVer;
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(OdbcHandshakeResult.class, this);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcMessageParser.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcMessageParser.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcMessageParser.java
index fce8b1b..e8b594e 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcMessageParser.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcMessageParser.java
@@ -34,12 +34,6 @@ import java.util.Collection;
  * ODBC message parser.
  */
 public class OdbcMessageParser {
-    /** Current ODBC communication protocol version. */
-    public static final long PROTO_VER = 1;
-
-    /** Apache Ignite version when ODBC communication protocol version has 
been introduced. */
-    public static final String PROTO_VER_SINCE = "1.6.0";
-
     /** Initial output stream capacity. */
     private static final int INIT_CAP = 1024;
 
@@ -82,10 +76,26 @@ public class OdbcMessageParser {
         // we has not confirmed that the remote client uses the same protocol 
version.
         if (!verConfirmed) {
             if (cmd == OdbcRequest.HANDSHAKE)
-                return new OdbcHandshakeRequest(reader.readLong());
+            {
+                long longVersion = reader.readLong();
+
+                OdbcHandshakeRequest res = new 
OdbcHandshakeRequest(longVersion);
+
+                OdbcProtocolVersion version = res.version();
+
+                if (version.isUnknown())
+                    return res;
+
+                if (version.isDistributedJoinsSupported()) {
+                    res.distributedJoins(reader.readBoolean());
+                    res.enforceJoinOrder(reader.readBoolean());
+                }
+
+                return res;
+            }
             else
-                throw new IgniteException("Unexpected ODBC command (first 
message is not a handshake request): [cmd=" +
-                    cmd + ']');
+                throw new IgniteException("Unexpected ODBC command " +
+                        "(first message is not a handshake request): [cmd=" + 
cmd + ']');
         }
 
         OdbcRequest res;
@@ -174,6 +184,8 @@ public class OdbcMessageParser {
 
         Object res0 = msg.response();
 
+        if (res0 == null)
+            return writer.array();
         if (res0 instanceof OdbcHandshakeResult) {
             OdbcHandshakeResult res = (OdbcHandshakeResult) res0;
 
@@ -189,8 +201,8 @@ public class OdbcMessageParser {
             }
             else {
                 writer.writeBoolean(false);
-                writer.writeString(res.protoVerSince());
-                writer.writeString(res.currentVer());
+                writer.writeString(res.protocolVersionSince());
+                writer.writeString(res.currentVersion());
             }
         }
         else if (res0 instanceof OdbcQueryExecuteResult) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcProtocolVersion.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcProtocolVersion.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcProtocolVersion.java
new file mode 100644
index 0000000..57efa02
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcProtocolVersion.java
@@ -0,0 +1,125 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ODBC protocol version.
+ */
+public enum OdbcProtocolVersion {
+    /** First version of the ODBC. Released with Ignite 1.6 */
+    VERSION_1_6_0(1),
+
+    /** Second version of the ODBC. Released with Ignite 1.8 */
+    VERSION_1_8_0(makeVersion(1,8,0)),
+
+    /** Unknown version. */
+    VERSION_UNKNOWN(Long.MIN_VALUE);
+
+    /** Mask to get 2 lowest bytes of the value and cast to long. */
+    private static final long LONG_MASK = 0x000000000000FFFFL;
+
+    /** Long value to enum map. */
+    private static final Map<Long, OdbcProtocolVersion> versions = new 
HashMap<>();
+
+    /** Enum value to Ignite version map */
+    private static final Map<OdbcProtocolVersion, String> since = new 
HashMap<>();
+
+    /**
+     * Map long values to version.
+     */
+    static {
+        for (OdbcProtocolVersion version : values())
+            versions.put(version.longValue(), version);
+
+        since.put(VERSION_1_6_0, "1.6.0");
+        since.put(VERSION_1_8_0, "1.8.0");
+    }
+
+    /** Long value for version. */
+    private final long longVal;
+
+    /**
+     * @param longVal Long value.
+     */
+    OdbcProtocolVersion(long longVal) {
+        this.longVal = longVal;
+    }
+
+    /**
+     * Make long value for the version.
+     *
+     * @param major Major version.
+     * @param minor Minor version.
+     * @param maintenance Maintenance version.
+     * @return Long value for the version.
+     */
+    private static long makeVersion(int major, int minor, int maintenance) {
+        return ((major & LONG_MASK) << 48) | ((minor & LONG_MASK) << 32) | 
((maintenance & LONG_MASK) << 16);
+    }
+
+    /**
+     * @param longVal Long value.
+     * @return Protocol version.
+     */
+    public static OdbcProtocolVersion fromLong(long longVal) {
+        OdbcProtocolVersion res = versions.get(longVal);
+
+        return res == null ? VERSION_UNKNOWN : res;
+    }
+
+    /**
+     * @return Current version.
+     */
+    public static OdbcProtocolVersion current() {
+        return VERSION_1_8_0;
+    }
+
+    /**
+     * @return Long value.
+     */
+    public long longValue() {
+        return longVal;
+    }
+
+    /**
+     * @return {@code true} if this version is unknown.
+     */
+    public boolean isUnknown() {
+        return longVal == VERSION_UNKNOWN.longVal;
+    }
+
+    /**
+     * @return {@code true} if this version supports distributed joins.
+     */
+    public boolean isDistributedJoinsSupported() {
+        assert !isUnknown();
+
+        return longVal >= VERSION_1_8_0.longVal;
+    }
+
+    /**
+     * @return Ignite version when introduced.
+     */
+    public String since() {
+        assert !isUnknown();
+
+        return since.get(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java
index 43a1fa4..8f2d092 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java
@@ -54,6 +54,12 @@ public class OdbcRequestHandler {
     /** Current queries cursors. */
     private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, 
Iterator>> qryCursors = new ConcurrentHashMap<>();
 
+    /** Distributed joins flag. */
+    private boolean distributedJoins = false;
+
+    /** Enforce join order flag. */
+    private boolean enforceJoinOrder = false;
+
     /**
      * Constructor.
      *
@@ -115,16 +121,23 @@ public class OdbcRequestHandler {
      * @return Response.
      */
     private OdbcResponse performHandshake(OdbcHandshakeRequest req) {
-        OdbcHandshakeResult res;
+        OdbcProtocolVersion version = req.version();
 
-        if (req.version() == OdbcMessageParser.PROTO_VER)
-            res = new OdbcHandshakeResult(true, null, null);
-        else {
+        if (version.isUnknown()) {
             IgniteProductVersion ver = ctx.grid().version();
 
             String verStr = Byte.toString(ver.major()) + '.' + ver.minor() + 
'.' + ver.maintenance();
 
-            res = new OdbcHandshakeResult(false, 
OdbcMessageParser.PROTO_VER_SINCE, verStr);
+            OdbcHandshakeResult res = new OdbcHandshakeResult(false, 
OdbcProtocolVersion.current().since(), verStr);
+
+            return new OdbcResponse(res);
+        }
+
+        OdbcHandshakeResult res = new OdbcHandshakeResult(true, null, null);
+
+        if (version.isDistributedJoinsSupported()) {
+            distributedJoins = req.distributedJoins();
+            enforceJoinOrder = req.enforceJoinOrder();
         }
 
         return new OdbcResponse(res);
@@ -151,6 +164,9 @@ public class OdbcRequestHandler {
 
             qry.setArgs(req.arguments());
 
+            qry.setDistributedJoins(distributedJoins);
+            qry.setEnforceJoinOrder(enforceJoinOrder);
+
             IgniteCache<Object, Object> cache = 
ctx.grid().cache(req.cacheName());
 
             if (cache == null)

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/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 48b193a..a878d02 100644
--- a/modules/platforms/cpp/odbc-test/Makefile.am
+++ b/modules/platforms/cpp/odbc-test/Makefile.am
@@ -66,6 +66,7 @@ ignite_odbc_tests_SOURCES = \
     ../odbc/src/app/application_data_buffer.cpp \
     ../odbc/src/config/configuration.cpp \
     ../odbc/src/row.cpp \
+    ../odbc/src/protocol_version.cpp \
     ../odbc/src/column.cpp \
     ../odbc/src/utility.cpp \
     ../odbc/src/result_page.cpp

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml 
b/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml
new file mode 100644
index 0000000..18447c2
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:util="http://www.springframework.org/schema/util";
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd";>
+    <bean id="grid.cfg" 
class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="localHost" value="127.0.0.1"/>
+        <property name="connectorConfiguration"><null/></property>
+
+        <property name="cacheConfiguration">
+            <list>
+                <bean 
class="org.apache.ignite.configuration.CacheConfiguration">
+                    <property name="name" value="cache"/>
+                    <property name="cacheMode" value="PARTITIONED"/>
+                    <property name="atomicityMode" value="TRANSACTIONAL"/>
+                    <property name="writeSynchronizationMode" 
value="FULL_SYNC"/>
+
+                    <!-- Configure type metadata to enable queries. -->
+                                       <property name="queryEntities">
+                                               <list>
+                                                       <bean 
class="org.apache.ignite.cache.QueryEntity">
+                                                               <property 
name="keyType" value="java.lang.Long"/>
+                                                               <property 
name="valueType" value="TestType"/>
+
+                                                               <property 
name="fields">
+                                                                       <map>
+                                        <entry key="i8Field" 
value="java.lang.Byte"/>
+                                        <entry key="i16Field" 
value="java.lang.Short"/>
+                                        <entry key="i32Field" 
value="java.lang.Integer"/>
+                                        <entry key="i64Field" 
value="java.lang.Long"/>
+                                        <entry key="strField" 
value="java.lang.String"/>
+                                        <entry key="floatField" 
value="java.lang.Float"/>
+                                        <entry key="doubleField" 
value="java.lang.Double"/>
+                                        <entry key="boolField" 
value="java.lang.Boolean"/>
+                                        <entry key="guidField" 
value="java.util.UUID"/>
+                                        <entry key="dateField" 
value="java.util.Date"/>
+                                        <entry key="timestampField" 
value="java.sql.Timestamp"/>
+                                                                       </map>
+                                                               </property>
+
+                                                               <property 
name="indexes">
+                                                                       <list>
+                                                                               
<bean class="org.apache.ignite.cache.QueryIndex">
+                                                                               
        <constructor-arg value="i32Field"/>
+                                                                               
</bean>
+                                                                               
<bean class="org.apache.ignite.cache.QueryIndex">
+                                                                               
        <constructor-arg value="i64Field"/>
+                                                                               
</bean>
+                                                                       </list>
+                                                               </property>
+                                                       </bean>
+                                               </list>
+                                       </property>
+                </bean>
+            </list>
+        </property>
+
+        <!-- Explicitly configure TCP discovery SPI to provide list of initial 
nodes. -->
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="ipFinder">
+                    <!--
+                        Ignite provides several options for automatic 
discovery that can be used
+                        instead os static IP based discovery.
+                    -->
+                    <!-- Uncomment static IP finder to enable static-based 
discovery of initial nodes. -->
+                    <!--<bean 
class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
+                    <bean 
class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
+                        <property name="addresses">
+                            <list>
+                                <!-- In distributed environment, replace with 
actual host IP address. -->
+                                <value>127.0.0.1:47500</value>
+                            </list>
+                        </property>
+                    </bean>
+                </property>
+                <property name="socketTimeout" value="300" />
+            </bean>
+        </property>
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc-test/config/queries-test.xml
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/config/queries-test.xml 
b/modules/platforms/cpp/odbc-test/config/queries-test.xml
index 054da42..54cb9be 100644
--- a/modules/platforms/cpp/odbc-test/config/queries-test.xml
+++ b/modules/platforms/cpp/odbc-test/config/queries-test.xml
@@ -41,17 +41,18 @@
                 <bean 
class="org.apache.ignite.configuration.CacheConfiguration">
                     <property name="name" value="cache"/>
                     <property name="cacheMode" value="PARTITIONED"/>
-                    <property name="atomicityMode" value="ATOMIC"/>
-                    <property name="writeSynchronizationMode" 
value="PRIMARY_SYNC"/>
+                    <property name="atomicityMode" value="TRANSACTIONAL"/>
+                    <property name="writeSynchronizationMode" 
value="FULL_SYNC"/>
             
                     <!-- Configure type metadata to enable queries. -->
-                    <property name="typeMetadata">
-                        <list>
-                            <bean 
class="org.apache.ignite.cache.CacheTypeMetadata">
-                                <property name="keyType" 
value="java.lang.Long"/>
-                                <property name="valueType" value="TestType"/>
-                                <property name="queryFields">
-                                    <map>
+                                       <property name="queryEntities">
+                                               <list>
+                                                       <bean 
class="org.apache.ignite.cache.QueryEntity">
+                                                               <property 
name="keyType" value="java.lang.Long"/>
+                                                               <property 
name="valueType" value="TestType"/>
+
+                                                               <property 
name="fields">
+                                                                       <map>
                                         <entry key="i8Field" 
value="java.lang.Byte"/>
                                         <entry key="i16Field" 
value="java.lang.Short"/>
                                         <entry key="i32Field" 
value="java.lang.Integer"/>
@@ -63,11 +64,22 @@
                                         <entry key="guidField" 
value="java.util.UUID"/>
                                         <entry key="dateField" 
value="java.util.Date"/>
                                         <entry key="timestampField" 
value="java.sql.Timestamp"/>
-                                    </map>
-                                </property>
-                            </bean>
-                        </list>
-                    </property>
+                                                                       </map>
+                                                               </property>
+
+                                                               <property 
name="indexes">
+                                                                       <list>
+                                                                               
<bean class="org.apache.ignite.cache.QueryIndex">
+                                                                               
        <constructor-arg value="i32Field"/>
+                                                                               
</bean>
+                                                                               
<bean class="org.apache.ignite.cache.QueryIndex">
+                                                                               
        <constructor-arg value="i64Field"/>
+                                                                               
</bean>
+                                                                       </list>
+                                                               </property>
+                                                       </bean>
+                                               </list>
+                                       </property>
                 </bean>
             </list>
         </property>
@@ -81,12 +93,11 @@
                         instead os static IP based discovery.
                     -->
                     <!-- Uncomment static IP finder to enable static-based 
discovery of initial nodes. -->
-                    <!--<bean 
class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
-                    <bean 
class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
+                    <bean 
class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
                         <property name="addresses">
                             <list>
                                 <!-- In distributed environment, replace with 
actual host IP address. -->
-                                <value>127.0.0.1:47500..47501</value>
+                                <value>127.0.0.1:47500</value>
                             </list>
                         </property>
                     </bean>

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/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 fbc0929..833904e 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -157,6 +157,7 @@
     <ClCompile Include="..\..\..\odbc\src\config\configuration.cpp" />
     <ClCompile Include="..\..\..\odbc\src\config\connection_info.cpp" />
     <ClCompile Include="..\..\..\odbc\src\cursor.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\protocol_version.cpp" />
     <ClCompile Include="..\..\..\odbc\src\result_page.cpp" />
     <ClCompile Include="..\..\..\odbc\src\row.cpp" />
     <ClCompile Include="..\..\..\odbc\src\utility.cpp" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/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 2e38c24..aead2af 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
@@ -76,6 +76,9 @@
     <ClCompile Include="..\..\src\queries_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\protocol_version.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp 
b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
index 10fd137..c0bb439 100644
--- a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
@@ -20,6 +20,7 @@
 #endif
 
 #include <iostream>
+#include <set>
 
 #include <boost/test/unit_test.hpp>
 
@@ -36,6 +37,8 @@ namespace
     const uint16_t testServerPort = 4242;
     const std::string testCacheName = "TestCache";
     const std::string testDsn = "Ignite DSN";
+    const bool testDistributedJoins = true;
+    const bool testEnforceJoinOrder = true;
 
     const std::string testAddress = testServerHost + ':' + 
ignite::common::LexicalCast<std::string>(testServerPort);
 }
@@ -49,6 +52,42 @@ void CheckValidAddress(const char* connectStr, uint16_t port)
     BOOST_CHECK_EQUAL(cfg.GetPort(), port);
 }
 
+void CheckValidProtocolVersion(const char* connectStr, 
ignite::odbc::ProtocolVersion version)
+{
+    Configuration cfg;
+
+    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+
+    BOOST_CHECK(cfg.GetProtocolVersion() == version);
+}
+
+void CheckInvalidProtocolVersion(const char* connectStr)
+{
+    Configuration cfg;
+
+    cfg.FillFromConnectString(connectStr);
+
+    BOOST_CHECK_THROW(cfg.GetProtocolVersion(), ignite::IgniteError);
+}
+
+void CheckValidBoolValue(const std::string& connectStr, const std::string& 
key, bool val)
+{
+    Configuration cfg;
+
+    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+
+    BOOST_CHECK_EQUAL(cfg.GetBoolValue(key, val), val);
+}
+
+void CheckInvalidBoolValue(const std::string& connectStr, const std::string& 
key)
+{
+    Configuration cfg;
+
+    cfg.FillFromConnectString(connectStr);
+
+    BOOST_CHECK_THROW(cfg.GetBoolValue(key, false), ignite::IgniteError);
+}
+
 void CheckConnectionConfig(const Configuration& cfg)
 {
     BOOST_CHECK_EQUAL(cfg.GetDriver(), testDriverName);
@@ -57,16 +96,20 @@ void CheckConnectionConfig(const Configuration& cfg)
     BOOST_CHECK_EQUAL(cfg.GetAddress(), testAddress);
     BOOST_CHECK_EQUAL(cfg.GetCache(), testCacheName);
     BOOST_CHECK_EQUAL(cfg.GetDsn(), std::string());
+    BOOST_CHECK_EQUAL(cfg.IsDistributedJoins(), testDistributedJoins);
+    BOOST_CHECK_EQUAL(cfg.IsEnforceJoinOrder(), testEnforceJoinOrder);
 
     std::stringstream constructor;
 
     constructor << "address=" << testAddress << ';'
                 << "cache=" << testCacheName << ';'
-                << "driver={" << testDriverName << "};";
+                << "distributed_joins=" << (testDistributedJoins ? "true" : 
"false") << ';'
+                << "driver={" << testDriverName << "};"
+                << "enforce_join_order=" << (testEnforceJoinOrder ? "true" : 
"false") << ';';
 
     const std::string& expectedStr = constructor.str();
 
-    BOOST_CHECK_EQUAL(cfg.ToConnectString(), expectedStr);
+    BOOST_CHECK_EQUAL(ignite::common::ToLower(cfg.ToConnectString()), 
ignite::common::ToLower(expectedStr));
 }
 
 void CheckDsnConfig(const Configuration& cfg)
@@ -76,7 +119,9 @@ void CheckDsnConfig(const Configuration& cfg)
     BOOST_CHECK_EQUAL(cfg.GetCache(), Configuration::DefaultValue::cache);
     BOOST_CHECK_EQUAL(cfg.GetAddress(), Configuration::DefaultValue::address);
     BOOST_CHECK_EQUAL(cfg.GetHost(), std::string());
-    BOOST_CHECK_EQUAL(cfg.GetPort(), Configuration::DefaultValue::uintPort);
+    BOOST_CHECK_EQUAL(cfg.GetPort(), Configuration::DefaultValue::port);
+    BOOST_CHECK_EQUAL(cfg.IsDistributedJoins(), false);
+    BOOST_CHECK_EQUAL(cfg.IsEnforceJoinOrder(), false);
 }
 
 BOOST_AUTO_TEST_SUITE(ConfigurationTestSuite)
@@ -85,9 +130,11 @@ BOOST_AUTO_TEST_CASE(CheckTestValuesNotEquealDefault)
 {
     BOOST_CHECK_NE(testDriverName, Configuration::DefaultValue::driver);
     BOOST_CHECK_NE(testAddress, Configuration::DefaultValue::address);
-    BOOST_CHECK_NE(testServerPort, Configuration::DefaultValue::uintPort);
+    BOOST_CHECK_NE(testServerPort, Configuration::DefaultValue::port);
     BOOST_CHECK_NE(testCacheName, Configuration::DefaultValue::cache);
     BOOST_CHECK_NE(testDsn, Configuration::DefaultValue::dsn);
+    BOOST_CHECK_NE(testDistributedJoins, 
Configuration::DefaultValue::distributedJoins);
+    BOOST_CHECK_NE(testEnforceJoinOrder, 
Configuration::DefaultValue::enforceJoinOrder);
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringUppercase)
@@ -98,7 +145,9 @@ BOOST_AUTO_TEST_CASE(TestConnectStringUppercase)
 
     constructor << "DRIVER={" << testDriverName << "};"
                 << "ADDRESS=" << testAddress << ';'
-                << "CACHE=" << testCacheName;
+                << "CACHE=" << testCacheName << ';'
+                << "DISTRIBUTED_JOINS=" << (testDistributedJoins ? "TRUE" : 
"FALSE") << ';'
+                << "ENFORCE_JOIN_ORDER=" << (testEnforceJoinOrder ? "TRUE" : 
"FALSE");
 
     const std::string& connectStr = constructor.str();
 
@@ -115,7 +164,9 @@ BOOST_AUTO_TEST_CASE(TestConnectStringLowercase)
 
     constructor << "driver={" << testDriverName << "};"
                 << "address=" << testAddress << ';'
-                << "cache=" << testCacheName;
+                << "cache=" << testCacheName << ';'
+                << "distributed_joins=" << (testDistributedJoins ? "true" : 
"false") << ';'
+                << "enforce_join_order=" << (testEnforceJoinOrder ? "true" : 
"false");
 
     const std::string& connectStr = constructor.str();
 
@@ -132,7 +183,9 @@ BOOST_AUTO_TEST_CASE(TestConnectStringZeroTerminated)
 
     constructor << "driver={" << testDriverName << "};"
                 << "address=" << testAddress << ';'
-                << "cache=" << testCacheName;
+                << "cache=" << testCacheName << ';'
+                << "distributed_joins=" << (testDistributedJoins ? "true" : 
"false") << ';'
+                << "enforce_join_order=" << (testEnforceJoinOrder ? "true" : 
"false");
 
     const std::string& connectStr = constructor.str();
 
@@ -149,7 +202,9 @@ BOOST_AUTO_TEST_CASE(TestConnectStringMixed)
 
     constructor << "Driver={" << testDriverName << "};"
                 << "Address=" << testAddress << ';'
-                << "Cache=" << testCacheName;
+                << "Cache=" << testCacheName << ';'
+                << "Distributed_Joins=" << (testDistributedJoins ? "True" : 
"False") << ';'
+                << "Enforce_Join_Order=" << (testEnforceJoinOrder ? "True" : 
"False");
 
     const std::string& connectStr = constructor.str();
 
@@ -166,7 +221,9 @@ BOOST_AUTO_TEST_CASE(TestConnectStringWhitepaces)
 
     constructor << "DRIVER = {" << testDriverName << "} ;\n"
                 << " ADDRESS =" << testAddress << "; "
-                << "CACHE = \n\r" << testCacheName;
+                << "CACHE = \n\r" << testCacheName << ';'
+                << "   DISTRIBUTED_JOINS=" << (testDistributedJoins ? "TRUE" : 
"FALSE") << ';'
+                << "ENFORCE_JOIN_ORDER=   " << (testEnforceJoinOrder ? "TRUE  
" : "FALSE  ");
 
     const std::string& connectStr = constructor.str();
 
@@ -190,13 +247,74 @@ BOOST_AUTO_TEST_CASE(TestConnectStringInvalidAddress)
 
 BOOST_AUTO_TEST_CASE(TestConnectStringValidAddress)
 {
-    Configuration cfg;
-
     CheckValidAddress("Address=example.com:1;", 1);
     CheckValidAddress("Address=example.com:31242;", 31242);
     CheckValidAddress("Address=example.com:55555;", 55555);
     CheckValidAddress("Address=example.com:110;", 110);
-    CheckValidAddress("Address=example.com;", 
Configuration::DefaultValue::uintPort);
+    CheckValidAddress("Address=example.com;", 
Configuration::DefaultValue::port);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringInvalidVersion)
+{
+    CheckInvalidProtocolVersion("Protocol_Version=0;");
+    CheckInvalidProtocolVersion("Protocol_Version=1;");
+    CheckInvalidProtocolVersion("Protocol_Version=2;");
+    CheckInvalidProtocolVersion("Protocol_Version=1.6.1;");
+    CheckInvalidProtocolVersion("Protocol_Version=1.7.0;");
+    CheckInvalidProtocolVersion("Protocol_Version=1.8.1;");
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringValidVersion)
+{
+    CheckValidProtocolVersion("Protocol_Version=1.6.0;", 
ignite::odbc::ProtocolVersion::VERSION_1_6_0);
+    CheckValidProtocolVersion("Protocol_Version=1.8.0;", 
ignite::odbc::ProtocolVersion::VERSION_1_8_0);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringInvalidBoolKeys)
+{
+    typedef std::set<std::string> Set;
+
+    Set keys;
+
+    keys.insert("distributed_joins");
+    keys.insert("enforce_join_order");
+
+    for (Set::const_iterator it = keys.begin(); it != keys.end(); ++it)
+    {
+        const std::string& key = *it;
+
+        CheckInvalidBoolValue(key + "=1;", key);
+        CheckInvalidBoolValue(key + "=0;", key);
+        CheckInvalidBoolValue(key + "=42;", key);
+        CheckInvalidBoolValue(key + "=truee;", key);
+        CheckInvalidBoolValue(key + "=flase;", key);
+        CheckInvalidBoolValue(key + "=falsee;", key);
+        CheckInvalidBoolValue(key + "=yes;", key);
+        CheckInvalidBoolValue(key + "=no;", key);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringValidBoolKeys)
+{
+    typedef std::set<std::string> Set;
+
+    Set keys;
+
+    keys.insert("distributed_joins");
+    keys.insert("enforce_join_order");
+
+    for (Set::const_iterator it = keys.begin(); it != keys.end(); ++it)
+    {
+        const std::string& key = *it;
+
+        CheckValidBoolValue(key + "=true;", key, true);
+        CheckValidBoolValue(key + "=True;", key, true);
+        CheckValidBoolValue(key + "=TRUE;", key, true);
+
+        CheckValidBoolValue(key + "=false;", key, false);
+        CheckValidBoolValue(key + "=False;", key, false);
+        CheckValidBoolValue(key + "=FALSE;", key, false);
+    }
 }
 
 BOOST_AUTO_TEST_CASE(TestDsnStringUppercase)
@@ -215,7 +333,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStringUppercase)
     CheckDsnConfig(cfg);
 }
 
-BOOST_AUTO_TEST_CASE(TestDsnStrinLowercase)
+BOOST_AUTO_TEST_CASE(TestDsnStringLowercase)
 {
     Configuration cfg;
 
@@ -231,7 +349,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStrinLowercase)
     CheckDsnConfig(cfg);
 }
 
-BOOST_AUTO_TEST_CASE(TestDsnStrinMixed)
+BOOST_AUTO_TEST_CASE(TestDsnStringMixed)
 {
     Configuration cfg;
 
@@ -247,7 +365,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStrinMixed)
     CheckDsnConfig(cfg);
 }
 
-BOOST_AUTO_TEST_CASE(TestDsnStrinWhitespaces)
+BOOST_AUTO_TEST_CASE(TestDsnStringWhitespaces)
 {
     Configuration cfg;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc-test/src/queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp 
b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
index ccb3a4d..58b5f64 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
@@ -122,6 +122,44 @@ struct QueriesTestSuiteFixture
         BOOST_REQUIRE(stmt != NULL);
     }
 
+    void Disconnect()
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+        // Disconneting from the server.
+        SQLDisconnect(dbc);
+
+        // Releasing allocated handles.
+        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
+        SQLFreeHandle(SQL_HANDLE_ENV, env);
+    }
+
+    static Ignite StartAdditionalNode(const char* name)
+    {
+        IgniteConfiguration cfg;
+
+        cfg.jvmOpts.push_back("-Xdebug");
+        cfg.jvmOpts.push_back("-Xnoagent");
+        cfg.jvmOpts.push_back("-Djava.compiler=NONE");
+        
cfg.jvmOpts.push_back("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005");
+        cfg.jvmOpts.push_back("-XX:+HeapDumpOnOutOfMemoryError");
+
+#ifdef IGNITE_TESTS_32
+        cfg.jvmInitMem = 256;
+        cfg.jvmMaxMem = 768;
+#else
+        cfg.jvmInitMem = 1024;
+        cfg.jvmMaxMem = 4096;
+#endif
+
+        
cfg.springCfgPath.assign(getenv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH")).append("/queries-test-noodbc.xml");
+
+        IgniteError err;
+
+        return Ignition::Start(cfg, name);
+    }
+
     /**
      * Constructor.
      */
@@ -143,16 +181,11 @@ struct QueriesTestSuiteFixture
         cfg.jvmMaxMem = 4096;
 #endif
 
-        char* cfgPath = getenv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH");
-
-        cfg.springCfgPath = 
std::string(cfgPath).append("/").append("queries-test.xml");
+        
cfg.springCfgPath.assign(getenv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH")).append("/queries-test.xml");
 
         IgniteError err;
 
-        grid = Ignition::Start(cfg, &err);
-
-        if (err.GetCode() != IgniteError::IGNITE_SUCCESS)
-            BOOST_FAIL(err.GetText());
+        grid = Ignition::Start(cfg, "NodeMain");
 
         testCache = grid.GetCache<int64_t, TestType>("cache");
     }
@@ -162,17 +195,9 @@ struct QueriesTestSuiteFixture
      */
     ~QueriesTestSuiteFixture()
     {
-        // Releasing statement handle.
-        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-
-        // Disconneting from the server.
-        SQLDisconnect(dbc);
-
-        // Releasing allocated handles.
-        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-        SQLFreeHandle(SQL_HANDLE_ENV, env);
+        Disconnect();
 
-        Ignition::Stop(grid.GetName(), true);
+        Ignition::StopAll(true);
     }
 
     template<typename T>
@@ -269,6 +294,28 @@ struct QueriesTestSuiteFixture
         BOOST_CHECK(ret == SQL_NO_DATA);
     }
 
+    int CountRows(SQLHSTMT stmt)
+    {
+        int res = 0;
+
+        SQLRETURN ret = SQL_SUCCESS;
+
+        while (ret == SQL_SUCCESS)
+        {
+            ret = SQLFetch(stmt);
+
+            if (ret == SQL_NO_DATA)
+                break;
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            ++res;
+        }
+
+        return res;
+    }
+
     /** Node started during the test. */
     Ignite grid;
 
@@ -292,6 +339,16 @@ BOOST_AUTO_TEST_CASE(TestLegacyConnection)
     Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;CACHE=cache");
 }
 
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_1_6_0)
+{
+    Connect("DRIVER={Apache 
Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;PROTOCOL_VERSION=1.6.0");
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_1_8_0)
+{
+    Connect("DRIVER={Apache 
Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;PROTOCOL_VERSION=1.8.0");
+}
+
 BOOST_AUTO_TEST_CASE(TestTwoRowsInt8)
 {
     CheckTwoRowsInt<int8_t>(SQL_C_STINYINT);
@@ -538,4 +595,131 @@ BOOST_AUTO_TEST_CASE(TestOneRowStringLen)
     BOOST_CHECK(ret == SQL_NO_DATA);
 }
 
+BOOST_AUTO_TEST_CASE(TestDistributedJoins)
+{
+    // Starting additional node.
+    Ignite node1 = StartAdditionalNode("Node1");
+    Ignite node2 = StartAdditionalNode("Node2");
+
+    const int entriesNum = 1000;
+
+    // Filling cache with data.
+    for (int i = 0; i < entriesNum; ++i)
+    {
+        TestType entry;
+
+        entry.i32Field = i;
+        entry.i64Field = entriesNum - i - 1;
+
+        testCache.Put(i, entry);
+    }
+
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache");
+
+    SQLRETURN ret;
+
+    const size_t columnsCnt = 2;
+
+    SQLBIGINT columns[columnsCnt] = { 0 };
+
+    // Binding colums.
+    for (SQLSMALLINT i = 0; i < columnsCnt; ++i)
+    {
+        ret = SQLBindCol(stmt, i + 1, SQL_C_SLONG, &columns[i], 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+    }
+
+    SQLCHAR request[] =
+        "SELECT T0.i32Field, T1.i64Field FROM TestType AS T0 "
+        "INNER JOIN TestType AS T1 "
+        "ON (T0.i32Field = T1.i64Field)";
+
+    ret = SQLExecDirect(stmt, request, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    int rowsNum = CountRows(stmt);
+
+    BOOST_CHECK_GT(rowsNum, 0);
+    BOOST_CHECK_LT(rowsNum, entriesNum);
+
+    Disconnect();
+
+    Connect("DRIVER={Apache 
Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;DISTRIBUTED_JOINS=true;");
+
+    // Binding colums.
+    for (SQLSMALLINT i = 0; i < columnsCnt; ++i)
+    {
+        ret = SQLBindCol(stmt, i + 1, SQL_C_SLONG, &columns[i], 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+    }
+
+    ret = SQLExecDirect(stmt, request, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    rowsNum = CountRows(stmt);
+
+    BOOST_CHECK_EQUAL(rowsNum, entriesNum);
+}
+
+BOOST_AUTO_TEST_CASE(TestDistributedJoinsWithOldVersion)
+{
+    // Starting additional node.
+    Ignite node1 = StartAdditionalNode("Node1");
+    Ignite node2 = StartAdditionalNode("Node2");
+
+    const int entriesNum = 1000;
+
+    // Filling cache with data.
+    for (int i = 0; i < entriesNum; ++i)
+    {
+        TestType entry;
+
+        entry.i32Field = i;
+        entry.i64Field = entriesNum - i - 1;
+
+        testCache.Put(i, entry);
+    }
+
+    Connect("DRIVER={Apache 
Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;DISTRIBUTED_JOINS=true;PROTOCOL_VERSION=1.6.0");
+
+    SQLRETURN ret;
+
+    const size_t columnsCnt = 2;
+
+    SQLBIGINT columns[columnsCnt] = { 0 };
+
+    // Binding colums.
+    for (SQLSMALLINT i = 0; i < columnsCnt; ++i)
+    {
+        ret = SQLBindCol(stmt, i + 1, SQL_C_SLONG, &columns[i], 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+    }
+
+    SQLCHAR request[] =
+        "SELECT T0.i32Field, T1.i64Field FROM TestType AS T0 "
+        "INNER JOIN TestType AS T1 "
+        "ON (T0.i32Field = T1.i64Field)";
+
+    ret = SQLExecDirect(stmt, request, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    int rowsNum = CountRows(stmt);
+
+    BOOST_CHECK_GT(rowsNum, 0);
+    BOOST_CHECK_LT(rowsNum, entriesNum);
+}
+
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/Makefile.am 
b/modules/platforms/cpp/odbc/Makefile.am
index 29f0ef4..9faa999 100644
--- a/modules/platforms/cpp/odbc/Makefile.am
+++ b/modules/platforms/cpp/odbc/Makefile.am
@@ -69,6 +69,7 @@ libignite_odbc_la_SOURCES = \
     src/query/table_metadata_query.cpp \
     src/query/type_info_query.cpp \
     src/query/special_columns_query.cpp \
+    src/protocol_version.cpp \
     src/result_page.cpp \
     src/row.cpp \
     src/column.cpp \

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/Makefile.am 
b/modules/platforms/cpp/odbc/include/Makefile.am
index 192021d..0776548 100644
--- a/modules/platforms/cpp/odbc/include/Makefile.am
+++ b/modules/platforms/cpp/odbc/include/Makefile.am
@@ -27,6 +27,7 @@ noinst_HEADERS = \
     ignite/odbc/query/column_metadata_query.h \
     ignite/odbc/query/query.h \
     ignite/odbc/query/primary_keys_query.h \
+    ignite/odbc/protocol_version.h \
     ignite/odbc/statement.h \
     ignite/odbc/config/configuration.h \
     ignite/odbc/config/connection_info.h \

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
index 6636ca4..250eaf2 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
@@ -60,6 +60,9 @@ namespace ignite
             /** Output data has been truncated. */
             SQL_STATE_01004_DATA_TRUNCATED,
 
+            /** Invalid connection string attribute. */
+            SQL_STATE_01S00_INVALID_CONNECTION_STRING_ATTRIBUTE,
+
             /** Error in row. */
             SQL_STATE_01S01_ERROR_IN_ROW,
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
----------------------------------------------------------------------
diff --git 
a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
index 05fe8bf..30f9ad6 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
@@ -24,6 +24,7 @@
 
 #include <ignite/common/common.h>
 #include <ignite/common/utils.h>
+#include "ignite/odbc/protocol_version.h"
 
 namespace ignite
 {
@@ -60,6 +61,15 @@ namespace ignite
 
                     /** Connection attribute keyword for port attribute. */
                     static const std::string port;
+
+                    /** Connection attribute keyword for distributed joins 
attribute. */
+                    static const std::string distributedJoins;
+
+                    /** Connection attribute keyword for enforce join order 
attribute. */
+                    static const std::string enforceJoinOrder;
+
+                    /** Connection attribute keyword for protocol version 
attribute. */
+                    static const std::string protocolVersion;
                 };
 
                 /** Default values for configuration. */
@@ -80,11 +90,17 @@ namespace ignite
                     /** Default value for server attribute. */
                     static const std::string server;
 
+                    /** Default value for protocol version. */
+                    static const ProtocolVersion& protocolVersion;
+
                     /** Default value for port attribute. */
-                    static const std::string port;
+                    static const uint16_t port;
 
-                    /** Default value for port attribute. Uint16 value. */
-                    static const uint16_t uintPort;
+                    /** Default value for distributed joins attribute. */
+                    static const bool distributedJoins;
+
+                    /** Default value for enforce join order attribute. */
+                    static const bool enforceJoinOrder;
                 };
 
                 /**
@@ -200,6 +216,33 @@ namespace ignite
                 }
 
                 /**
+                 * Check distributed joins flag.
+                 *
+                 * @return True if distributed joins are enabled.
+                 */
+                bool IsDistributedJoins() const
+                {
+                    return GetBoolValue(Key::distributedJoins, 
DefaultValue::distributedJoins);
+                }
+
+                /**
+                 * Check enforce join order flag.
+                 *
+                 * @return True if enforcing of join order is enabled.
+                 */
+                bool IsEnforceJoinOrder() const
+                {
+                    return GetBoolValue(Key::enforceJoinOrder, 
DefaultValue::enforceJoinOrder);
+                }
+
+                /**
+                 * Get protocol version.
+                 *
+                 * @return Protocol version.
+                 */
+                ProtocolVersion GetProtocolVersion() const;
+
+                /**
                  * Get string value from the config.
                  *
                  * @param key Configuration key.
@@ -208,6 +251,24 @@ namespace ignite
                  */
                 const std::string& GetStringValue(const std::string& key, 
const std::string& dflt) const;
 
+                /**
+                 * Get int value from the config.
+                 *
+                 * @param key Configuration key.
+                 * @param dflt Default value to be returned if there is no 
value stored.
+                 * @return Found or default value.
+                 */
+                int64_t GetIntValue(const std::string& key, int64_t dflt) 
const;
+
+                /**
+                 * Get bool value from the config.
+                 *
+                 * @param key Configuration key.
+                 * @param dflt Default value to be returned if there is no 
value stored.
+                 * @return Found or default value.
+                 */
+                bool GetBoolValue(const std::string& key, bool dflt) const;
+
             private:
                 /**
                  * Parse connect string into key-value storage.

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
index 00bdfc8..9fe46df 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
@@ -41,15 +41,6 @@ namespace ignite
         {
             friend class Environment;
         public:
-            /** ODBC communication protocol version. */
-            enum { PROTOCOL_VERSION = 1 };
-
-            /**
-             * Apache Ignite version when the current ODBC communication
-             * protocol version has been introduced.
-             */
-            static const std::string PROTOCOL_VERSION_SINCE;
-
             /**
              * Destructor.
              */
@@ -263,6 +254,13 @@ namespace ignite
             SqlResult MakeRequestHandshake();
 
             /**
+             * Perform configure request.
+             *
+             * @return Operation result.
+             */
+            SqlResult MakeRequestConfigure();
+
+            /**
              * Constructor.
              */
             Connection();

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/message.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
index f0b40e2..03fa627 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
@@ -66,8 +66,13 @@ namespace ignite
              * Constructor.
              *
              * @param version Protocol version.
+             * @param distributedJoins Distributed joins flag.
+             * @param enforceJoinOrder Enforce join order flag.
              */
-            HandshakeRequest(int64_t version) : version(version)
+            HandshakeRequest(int64_t version, bool distributedJoins, bool 
enforceJoinOrder) :
+                version(version),
+                distributedJoins(distributedJoins),
+                enforceJoinOrder(enforceJoinOrder)
             {
                 // No-op.
             }
@@ -89,11 +94,20 @@ namespace ignite
                 writer.WriteInt8(REQUEST_TYPE_HANDSHAKE);
 
                 writer.WriteInt64(version);
+
+                writer.WriteBool(distributedJoins);
+                writer.WriteBool(enforceJoinOrder);
             }
 
         private:
             /** Protocol version. */
             int64_t version;
+
+            /** Distributed joins flag. */
+            bool distributedJoins;
+
+            /** Enforce join order flag. */
+            bool enforceJoinOrder;
         };
 
         /**
@@ -153,6 +167,7 @@ namespace ignite
             const app::ParameterBindingMap& params;
         };
 
+
         /**
          * Query close request.
          */
@@ -348,13 +363,13 @@ namespace ignite
         /**
          * Query close response.
          */
-        class QueryResponse
+        class Response
         {
         public:
             /**
              * Constructor.
              */
-            QueryResponse() : status(RESPONSE_STATUS_FAILED), error()
+            Response() : status(RESPONSE_STATUS_FAILED), error()
             {
                 // No-op.
             }
@@ -362,7 +377,7 @@ namespace ignite
             /**
              * Destructor.
              */
-            ~QueryResponse()
+            virtual ~Response()
             {
                 // No-op.
             }
@@ -426,7 +441,7 @@ namespace ignite
         /**
          * Handshake response.
          */
-        class HandshakeResponse : public QueryResponse
+        class HandshakeResponse : public Response
         {
         public:
             /**
@@ -504,7 +519,7 @@ namespace ignite
         /**
          * Query close response.
          */
-        class QueryCloseResponse : public QueryResponse
+        class QueryCloseResponse : public Response
         {
         public:
             /**
@@ -549,7 +564,7 @@ namespace ignite
         /**
          * Query execute response.
          */
-        class QueryExecuteResponse : public QueryResponse
+        class QueryExecuteResponse : public Response
         {
         public:
             /**
@@ -608,7 +623,7 @@ namespace ignite
         /**
          * Query fetch response.
          */
-        class QueryFetchResponse : public QueryResponse
+        class QueryFetchResponse : public Response
         {
         public:
             /**
@@ -659,7 +674,7 @@ namespace ignite
         /**
          * Query get column metadata response.
          */
-        class QueryGetColumnsMetaResponse : public QueryResponse
+        class QueryGetColumnsMetaResponse : public Response
         {
         public:
             /**
@@ -704,7 +719,7 @@ namespace ignite
         /**
          * Query get table metadata response.
          */
-        class QueryGetTablesMetaResponse : public QueryResponse
+        class QueryGetTablesMetaResponse : public Response
         {
         public:
             /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/parser.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/parser.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/parser.h
index c19e08c..a91af22 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/parser.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/parser.h
@@ -42,9 +42,6 @@ namespace ignite
             /** Default initial size of operational memory. */
             enum { DEFAULT_MEM_ALLOCATION = 4096 };
 
-            /** ODBC communication protocol version. */
-            enum { PROTOCOL_VERSION = 1 };
-
             /**
              * Constructor.
              */

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h 
b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
new file mode 100644
index 0000000..747d78d
--- /dev/null
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
@@ -0,0 +1,172 @@
+/*
+ * 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 _IGNITE_ODBC_PROTOCOL_VERSION
+#define _IGNITE_ODBC_PROTOCOL_VERSION
+
+#include <stdint.h>
+
+#include <string>
+#include <map>
+
+namespace ignite
+{
+    namespace odbc
+    {
+        /** Protocol version. */
+        class ProtocolVersion
+        {
+        public:
+            /** String to version map type alias. */
+            typedef std::map<std::string, ProtocolVersion> StringToVersionMap;
+
+            /** Version to string map type alias. */
+            typedef std::map<ProtocolVersion, std::string> VersionToStringMap;
+
+            /** First version of the protocol that was introduced in Ignite 
1.6.0. */
+            static const ProtocolVersion VERSION_1_6_0;
+
+            /** First version of the protocol that was introduced in Ignite 
1.8.0. */
+            static const ProtocolVersion VERSION_1_8_0;
+
+            /** Unknown version of the protocol. */
+            static const ProtocolVersion VERSION_UNKNOWN;
+
+            /**
+             * Get current version.
+             *
+             * @return Current version.
+             */
+            static const ProtocolVersion& GetCurrent();
+
+            /**
+             * Parse string and extract protocol version.
+             *
+             * @throw IgniteException if version can not be parsed.
+             * @param version Version string to parse.
+             * @return Protocol version.
+             */
+            static ProtocolVersion FromString(const std::string& version);
+
+            /**
+             * Convert to string value.
+             *
+             * @throw IgniteException if version is unknow parsed.
+             * @param version Version string to parse.
+             * @return Protocol version.
+             */
+            const std::string& ToString() const;
+
+            /**
+             * Get int value.
+             *
+             * @return Integer value.
+             */
+            int64_t GetIntValue() const;
+
+            /**
+             * Check if the version is unknown.
+             *
+             * @return True if the version is unknown.
+             */
+            bool IsUnknown() const;
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if equal.
+             */
+            friend bool operator==(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if not equal.
+             */
+            friend bool operator!=(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if less.
+             */
+            friend bool operator<(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if less or equal.
+             */
+            friend bool operator<=(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if gretter.
+             */
+            friend bool operator>(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+            /**
+             * Comparison operator.
+             *
+             * @param val1 First value.
+             * @param val2 Second value.
+             * @return True if gretter or equal.
+             */
+            friend bool operator>=(const ProtocolVersion& val1, const 
ProtocolVersion& val2);
+
+        private:
+            /**
+             * Constructor.
+             *
+             * @param val Underlying value.
+             */
+            explicit ProtocolVersion(int64_t val);
+            
+            /**
+             * Make int value for the version.
+             *
+             * @param major Major version.
+             * @param minor Minor version.
+             * @param maintenance Maintenance version.
+             * @return Int value for the version.
+             */
+            static int64_t MakeVersion(uint16_t major, uint16_t minor, 
uint16_t maintenance);
+
+            /** String to version map. */
+            static const StringToVersionMap stringToVersionMap;
+
+            /** Version to string map. */
+            static const VersionToStringMap versionToStringMap;
+
+            /** Underlying int value. */
+            int64_t val;
+        };
+    }
+}
+
+#endif //_IGNITE_ODBC_PROTOCOL_VERSION
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj 
b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
index 5820030..0e0f0d3 100644
--- a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
+++ b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
@@ -170,6 +170,7 @@
     <ClCompile Include="..\..\src\meta\column_meta.cpp" />
     <ClCompile Include="..\..\src\meta\table_meta.cpp" />
     <ClCompile Include="..\..\src\odbc.cpp" />
+    <ClCompile Include="..\..\src\protocol_version.cpp" />
     <ClCompile Include="..\..\src\query\data_query.cpp" />
     <ClCompile Include="..\..\src\query\column_metadata_query.cpp" />
     <ClCompile Include="..\..\src\query\foreign_keys_query.cpp" />
@@ -206,6 +207,7 @@
     <ClInclude Include="..\..\include\ignite\odbc\meta\primary_key_meta.h" />
     <ClInclude Include="..\..\include\ignite\odbc\meta\table_meta.h" />
     <ClInclude Include="..\..\include\ignite\odbc\parser.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\protocol_version.h" />
     <ClInclude Include="..\..\include\ignite\odbc\query\data_query.h" />
     <ClInclude 
Include="..\..\include\ignite\odbc\query\column_metadata_query.h" />
     <ClInclude Include="..\..\include\ignite\odbc\query\foreign_keys_query.h" 
/>

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters 
b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
index 6ca58e2..9caf483 100644
--- a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
+++ b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
@@ -115,6 +115,9 @@
     <ClCompile Include="..\..\src\entry_points.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\protocol_version.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="module.def">
@@ -224,5 +227,8 @@
     <ClInclude Include="..\..\include\ignite\odbc.h">
       <Filter>Code</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\protocol_version.h">
+      <Filter>Code</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/src/config/configuration.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/config/configuration.cpp 
b/modules/platforms/cpp/odbc/src/config/configuration.cpp
index 45b0507..24c2bdf 100644
--- a/modules/platforms/cpp/odbc/src/config/configuration.cpp
+++ b/modules/platforms/cpp/odbc/src/config/configuration.cpp
@@ -20,6 +20,9 @@
 #include <algorithm>
 #include <iterator>
 
+#include "ignite/common/common.h"
+#include "ignite/common/utils.h"
+
 #include "ignite/odbc/utility.h"
 #include "ignite/odbc/config/configuration.h"
 
@@ -29,20 +32,29 @@ namespace ignite
     {
         namespace config
         {
-            const std::string Configuration::Key::dsn     = "dsn";
-            const std::string Configuration::Key::driver  = "driver";
-            const std::string Configuration::Key::cache   = "cache";
-            const std::string Configuration::Key::address = "address";
-            const std::string Configuration::Key::server  = "server";
-            const std::string Configuration::Key::port    = "port";
-
-            const std::string Configuration::DefaultValue::dsn     = "Apache 
Ignite DSN";
-            const std::string Configuration::DefaultValue::driver  = "Apache 
Ignite";
-            const std::string Configuration::DefaultValue::cache   = "";
-            const std::string Configuration::DefaultValue::address = "";
-            const std::string Configuration::DefaultValue::server  = "";
-            const std::string Configuration::DefaultValue::port    = "10800";
-            const uint16_t Configuration::DefaultValue::uintPort = 
common::LexicalCast<uint16_t>(port);
+            const std::string Configuration::Key::dsn               = "dsn";
+            const std::string Configuration::Key::driver            = "driver";
+            const std::string Configuration::Key::cache             = "cache";
+            const std::string Configuration::Key::address           = 
"address";
+            const std::string Configuration::Key::server            = "server";
+            const std::string Configuration::Key::port              = "port";
+            const std::string Configuration::Key::distributedJoins  = 
"distributed_joins";
+            const std::string Configuration::Key::enforceJoinOrder  = 
"enforce_join_order";
+            const std::string Configuration::Key::protocolVersion   = 
"protocol_version";
+
+            const std::string Configuration::DefaultValue::dsn             = 
"Apache Ignite DSN";
+            const std::string Configuration::DefaultValue::driver          = 
"Apache Ignite";
+            const std::string Configuration::DefaultValue::cache           = 
"";
+            const std::string Configuration::DefaultValue::address         = 
"";
+            const std::string Configuration::DefaultValue::server          = 
"";
+
+            const uint16_t Configuration::DefaultValue::port = 10800;
+
+            const bool Configuration::DefaultValue::distributedJoins = false;
+            const bool Configuration::DefaultValue::enforceJoinOrder = false;
+
+            const ProtocolVersion& 
Configuration::DefaultValue::protocolVersion = ProtocolVersion::GetCurrent();
+
 
             Configuration::Configuration() :
                 arguments()
@@ -80,7 +92,7 @@ namespace ignite
                 else
                 {
                     endPoint.host = GetStringValue(Key::server, 
DefaultValue::server);
-                    endPoint.port = 
common::LexicalCast<uint16_t>(GetStringValue(Key::port, DefaultValue::port));
+                    endPoint.port = 
static_cast<uint16_t>(GetIntValue(Key::port, DefaultValue::port));
                 }
             }
 
@@ -134,10 +146,20 @@ namespace ignite
                 else
                 {
                     endPoint.host = GetStringValue(Key::server, 
DefaultValue::server);
-                    endPoint.port = 
common::LexicalCast<uint16_t>(GetStringValue(Key::port, DefaultValue::port));
+                    endPoint.port = 
static_cast<uint16_t>(GetIntValue(Key::port, DefaultValue::port));
                 }
             }
 
+            ProtocolVersion Configuration::GetProtocolVersion() const
+            {
+                ArgumentMap::const_iterator it = 
arguments.find(Key::protocolVersion);
+
+                if (it != arguments.end())
+                    return ProtocolVersion::FromString(it->second);
+
+                return DefaultValue::protocolVersion;
+            }
+
             const std::string& Configuration::GetStringValue(const 
std::string& key, const std::string& dflt) const
             {
                 ArgumentMap::const_iterator it = 
arguments.find(common::ToLower(key));
@@ -148,6 +170,42 @@ namespace ignite
                 return dflt;
             }
 
+            int64_t Configuration::GetIntValue(const std::string& key, int64_t 
dflt) const
+            {
+                ArgumentMap::const_iterator it = 
arguments.find(common::ToLower(key));
+
+                if (it != arguments.end())
+                {
+                    const std::string& val = it->second;
+
+                    if (!common::AllOf(val.begin(), val.end(), isdigit))
+                        
IGNITE_ERROR_FORMATTED_1(IgniteError::IGNITE_ERR_GENERIC,
+                            "Invalid argument value: Integer value is 
expected.", "key", key);
+
+                    return common::LexicalCast<int64_t>(val);
+                }
+
+                return dflt;
+            }
+
+            bool Configuration::GetBoolValue(const std::string& key, bool 
dflt) const
+            {
+                ArgumentMap::const_iterator it = 
arguments.find(common::ToLower(key));
+
+                if (it != arguments.end())
+                {
+                    std::string lowercaseVal = common::ToLower(it->second);
+
+                    if (lowercaseVal != "true" && lowercaseVal != "false")
+                        
IGNITE_ERROR_FORMATTED_1(IgniteError::IGNITE_ERR_GENERIC,
+                            "Invalid argument value: Boolean value is expected 
(true or false).", "key", key);
+
+                    return lowercaseVal == "true";
+                }
+
+                return dflt;
+            }
+
             void Configuration::ParseAttributeList(const char * str, size_t 
len, char delimeter, ArgumentMap & args)
             {
                 std::string connect_str(str, len);
@@ -199,7 +257,7 @@ namespace ignite
                 if (colonNum == 0)
                 {
                     res.host = address;
-                    res.port = DefaultValue::uintPort;
+                    res.port = DefaultValue::port;
                 }
                 else if (colonNum == 1)
                 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/src/connection.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/connection.cpp 
b/modules/platforms/cpp/odbc/src/connection.cpp
index 844ad70..4315698 100644
--- a/modules/platforms/cpp/odbc/src/connection.cpp
+++ b/modules/platforms/cpp/odbc/src/connection.cpp
@@ -39,8 +39,6 @@ namespace ignite
 {
     namespace odbc
     {
-        const std::string Connection::PROTOCOL_VERSION_SINCE = "1.6.0";
-
         Connection::Connection() :
             socket(),
             connected(false),
@@ -309,7 +307,24 @@ namespace ignite
 
         SqlResult Connection::MakeRequestHandshake()
         {
-            HandshakeRequest req(PROTOCOL_VERSION);
+            bool distributedJoins = false;
+            bool enforceJoinOrder = false;
+            int64_t protocolVersion = 0;
+
+            try
+            {
+                distributedJoins = config.IsDistributedJoins();
+                enforceJoinOrder = config.IsEnforceJoinOrder();
+                protocolVersion = config.GetProtocolVersion().GetIntValue();
+            }
+            catch (const IgniteError& err)
+            {
+                
AddStatusRecord(SQL_STATE_01S00_INVALID_CONNECTION_STRING_ATTRIBUTE, 
err.GetText());
+
+                return SQL_RESULT_ERROR;
+            }
+
+            HandshakeRequest req(protocolVersion, distributedJoins, 
enforceJoinOrder);
             HandshakeResponse rsp;
 
             try
@@ -343,7 +358,7 @@ namespace ignite
                 constructor << "Node rejected handshake message. "
                     << "Current node Apache Ignite version: " << 
rsp.CurrentVer() << ", "
                     << "node protocol version introduced in version: " << 
rsp.ProtoVerSince() << ", "
-                    << "driver protocol version introduced in version: " << 
PROTOCOL_VERSION_SINCE << ".";
+                    << "driver protocol version introduced in version: " << 
config.GetProtocolVersion().ToString() << ".";
 
                 AddStatusRecord(SQL_STATE_08001_CANNOT_CONNECT, 
constructor.str());
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp 
b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
index 568c125..0fdfbc8 100644
--- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
+++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
@@ -34,6 +34,9 @@ namespace
     /** SQL state 01004 constant. */
     const std::string STATE_01004 = "01004";
 
+    /** SQL state 01S00 constant. */
+    const std::string STATE_01S00 = "01S00";
+
     /** SQL state 01S01 constant. */
     const std::string STATE_01S01 = "01S01";
 
@@ -190,6 +193,9 @@ namespace ignite
                     case SQL_STATE_01004_DATA_TRUNCATED:
                         return STATE_01004;
 
+                    case SQL_STATE_01S00_INVALID_CONNECTION_STRING_ATTRIBUTE:
+                        return STATE_01S00;
+
                     case SQL_STATE_01S01_ERROR_IN_ROW:
                         return STATE_01S01;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/311428ee/modules/platforms/cpp/odbc/src/protocol_version.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/protocol_version.cpp 
b/modules/platforms/cpp/odbc/src/protocol_version.cpp
new file mode 100644
index 0000000..c65099d
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/protocol_version.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#include "ignite/odbc/protocol_version.h"
+#include <ignite/common/concurrent.h>
+#include <ignite/common/utils.h>
+#include <ignite/ignite_error.h>
+
+namespace ignite
+{
+    namespace odbc
+    {
+        const ProtocolVersion ProtocolVersion::VERSION_1_6_0(1);
+        const ProtocolVersion 
ProtocolVersion::VERSION_1_8_0(MakeVersion(1,8,0));
+        const ProtocolVersion ProtocolVersion::VERSION_UNKNOWN(INT64_MIN);
+
+        ProtocolVersion::StringToVersionMap::value_type s2vInitVals[] = {
+            std::make_pair("1.6.0", ProtocolVersion::VERSION_1_6_0),
+            std::make_pair("1.8.0", ProtocolVersion::VERSION_1_8_0)
+        };
+
+        const ProtocolVersion::StringToVersionMap 
ProtocolVersion::stringToVersionMap(s2vInitVals,
+            s2vInitVals + (sizeof(s2vInitVals) / sizeof(s2vInitVals[0])));
+
+        ProtocolVersion::VersionToStringMap::value_type v2sInitVals[] = {
+            std::make_pair(ProtocolVersion::VERSION_1_6_0, "1.6.0"),
+            std::make_pair(ProtocolVersion::VERSION_1_8_0, "1.8.0")
+        };
+
+        const ProtocolVersion::VersionToStringMap 
ProtocolVersion::versionToStringMap(v2sInitVals,
+            v2sInitVals + (sizeof(v2sInitVals) / sizeof(v2sInitVals[0])));
+
+        ProtocolVersion::ProtocolVersion(int64_t val) :
+            val(val)
+        {
+            // No-op.
+        }
+
+        int64_t ProtocolVersion::MakeVersion(uint16_t major, uint16_t minor, 
uint16_t maintenance)
+        {
+            const static int64_t MASK = 0x000000000000FFFFLL;
+            return ((major & MASK) << 48) | ((minor & MASK) << 32) | 
((maintenance & MASK) << 16);
+        }
+
+        const ProtocolVersion& ProtocolVersion::GetCurrent()
+        {
+            return VERSION_1_8_0;
+        }
+
+        ProtocolVersion ProtocolVersion::FromString(const std::string& version)
+        {
+            StringToVersionMap::const_iterator it = 
stringToVersionMap.find(common::ToLower(version));
+
+            if (it == stringToVersionMap.end())
+            {
+                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                    "Invalid version format. Valid format is X.Y.Z, where X, Y 
and Z are major, "
+                    "minor and maintenance versions of Ignite since which 
protocol is introduced.");
+            }
+
+            return it->second;
+        }
+
+        const std::string& ProtocolVersion::ToString() const
+        {
+            VersionToStringMap::const_iterator it = 
versionToStringMap.find(*this);
+
+            if (it == versionToStringMap.end())
+            {
+                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                    "Unknown protocol version can not be converted to 
string.");
+            }
+
+            return it->second;
+        }
+
+        int64_t ProtocolVersion::GetIntValue() const
+        {
+            assert(!IsUnknown());
+
+            return val;
+        }
+
+        bool ProtocolVersion::IsUnknown() const
+        {
+            return *this == VERSION_UNKNOWN;
+        }
+
+        bool operator==(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val == val2.val;
+        }
+
+        bool operator!=(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val != val2.val;
+        }
+
+        bool operator<(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val < val2.val;
+        }
+
+        bool operator<=(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val <= val2.val;
+        }
+
+        bool operator>(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val > val2.val;
+        }
+
+        bool operator>=(const ProtocolVersion& val1, const ProtocolVersion& 
val2)
+        {
+            return val1.val >= val2.val;
+        }
+    }
+}
+

Reply via email to