You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/12/22 11:11:11 UTC

[02/13] ignite git commit: IGNITE-7143: Fixed Decimal serialization issue.

IGNITE-7143: Fixed Decimal serialization issue.

This closes #3207


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

Branch: refs/heads/ignite-zk
Commit: e9702a520cde61c6479ab843f356f1b2bd4b531c
Parents: b0f6d19
Author: Igor Sapego <is...@gridgain.com>
Authored: Tue Dec 19 18:53:56 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Wed Dec 20 14:30:41 2017 +0300

----------------------------------------------------------------------
 .../cpp/common/src/common/big_integer.cpp       |  24 +-
 modules/platforms/cpp/odbc-test/Makefile.am     |   2 +
 .../cpp/odbc-test/include/odbc_test_suite.h     | 123 +++++
 .../odbc-test/include/sql_test_suite_fixture.h  |   1 -
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   3 +
 .../project/vs/odbc-test.vcxproj.filters        |  11 +-
 .../cpp/odbc-test/src/odbc_test_suite.cpp       | 526 +++++++++++++++++++
 .../cpp/odbc-test/src/queries_test.cpp          | 512 +-----------------
 .../platforms/cpp/odbc-test/src/types_test.cpp  | 165 ++++++
 9 files changed, 860 insertions(+), 507 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/modules/platforms/cpp/common/src/common/big_integer.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/src/common/big_integer.cpp b/modules/platforms/cpp/common/src/common/big_integer.cpp
index 6aa6614..2ff3478 100644
--- a/modules/platforms/cpp/common/src/common/big_integer.cpp
+++ b/modules/platforms/cpp/common/src/common/big_integer.cpp
@@ -56,7 +56,7 @@ namespace ignite
             mag()
         {
             assert(val != 0);
-            assert(len > 0);
+            assert(len >= 0);
             assert(sign == 1 || sign == 0 || sign == -1);
 
             if (bigEndian)
@@ -65,6 +65,13 @@ namespace ignite
                 while (firstNonZero < len && val[firstNonZero] == 0)
                     ++firstNonZero;
 
+                if (firstNonZero == len)
+                {
+                    AssignInt64(0);
+
+                    return;
+                }
+
                 int32_t intLength = (len - firstNonZero + 3) / 4;
 
                 mag.Resize(intLength);
@@ -106,9 +113,17 @@ namespace ignite
             else
             {
                 int32_t firstNonZero = len - 1;
+
                 while (firstNonZero >= 0 && val[firstNonZero] == 0)
                     --firstNonZero;
 
+                if (firstNonZero == -1)
+                {
+                    AssignInt64(0);
+
+                    return;
+                }
+
                 int32_t intLength = (firstNonZero + 4) / 4;
 
                 mag.Resize(intLength);
@@ -269,6 +284,13 @@ namespace ignite
         {
             int32_t bytesNum = static_cast<int32_t>((GetBitLength() + 7) / 8);
 
+            if (bytesNum == 0)
+            {
+                buffer.Reset(1);
+
+                return;
+            }
+
             buffer.Reset(bytesNum);
 
             int32_t i;

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/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 7cccf4c..b025e2c 100644
--- a/modules/platforms/cpp/odbc-test/Makefile.am
+++ b/modules/platforms/cpp/odbc-test/Makefile.am
@@ -81,6 +81,8 @@ ignite_odbc_tests_SOURCES = \
     src/api_robustness_test.cpp \
     src/attributes_test.cpp \
     src/errors_test.cpp \
+	src/odbc_test_suite.cpp \
+	src/types_test.cpp \
     ../odbc/src/cursor.cpp \
     ../odbc/src/config/connection_info.cpp \
     ../odbc/src/app/application_data_buffer.cpp \

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
new file mode 100644
index 0000000..f79d65f
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
@@ -0,0 +1,123 @@
+/*
+ * 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 ODBC_TEST_ODBC_TEST_SUITE
+#define ODBC_TEST_ODBC_TEST_SUITE
+
+#ifdef _WIN32
+#   include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include <string>
+
+#include "ignite/ignite.h"
+
+#include "test_type.h"
+#include "complex_type.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        /**
+         * Test setup fixture.
+         */
+        struct OdbcTestSuite
+        {
+            /**
+             * Establish connection to node.
+             *
+             * @param connectStr Connection string.
+             */
+            void Connect(const std::string& connectStr);
+
+            /**
+             * Disconnect.
+             */
+            void Disconnect();
+
+            /**
+             * Start additional with the specified name and config.
+             * 
+             * @param cfg Config path.
+             * @param name Instance name.
+             */
+            static Ignite StartTestNode(const char* cfg, const char* name);
+
+            /**
+             * Constructor.
+             */
+            OdbcTestSuite();
+
+            /**
+             * Destructor.
+             */
+            virtual ~OdbcTestSuite();
+
+            /**
+             * Insert requested number of TestType values with all defaults except
+             * for the strFields, which are generated using getTestString().
+             *
+             * @param recordsNum Number of records to insert.
+             * @param merge Set to true to use merge instead.
+             */
+            void InsertTestStrings(int recordsNum, bool merge = false);
+
+            /**
+             * Insert requested number of TestType values in a batch.
+             *
+             * @param from Index to start from.
+             * @param to Index to stop.
+             * @param expectedToAffect Expected number of affected records.
+             * @param merge Set to true to use merge instead of insert.
+             * @return Records inserted.
+             */
+            int InsertTestBatch(int from, int to, int expectedToAffect, bool merge = false);
+
+            /**
+             * Insert requested number of TestType values in a batch,
+             * select them and check all the values.
+             *
+             * @param recordsNum Number of records.
+             */
+            void InsertBatchSelect(int recordsNum);
+
+            /**
+             * Insert values in two batches, select them and check all the values.
+             * @param recordsNum Number of records.
+             * @param splitAt Point where two batches are separated.
+             */
+            void InsertNonFullBatchSelect(int recordsNum, int splitAt);
+
+            static std::string getTestString(int64_t ind);
+
+            /** ODBC Environment. */
+            SQLHENV env;
+
+            /** ODBC Connect. */
+            SQLHDBC dbc;
+
+            /** ODBC Statement. */
+            SQLHSTMT stmt;
+        };
+    }
+}
+
+#endif //ODBC_TEST_ODBC_TEST_SUITE

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/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 bbcc0ad..8a76a67 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
@@ -112,7 +112,6 @@ namespace ignite
          * Run query returning single result and check it to be equal to expected.
          *
          * @param request SQL request.
-         * @param expected Expected result.
          * @param type Result type.
          */
         template<typename T>

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/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 e11a3ba..d565306 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -171,6 +171,7 @@
     <ClCompile Include="..\..\src\cursor_test.cpp" />
     <ClCompile Include="..\..\src\errors_test.cpp" />
     <ClCompile Include="..\..\src\meta_queries_test.cpp" />
+    <ClCompile Include="..\..\src\odbc_test_suite.cpp" />
     <ClCompile Include="..\..\src\queries_test.cpp" />
     <ClCompile Include="..\..\src\parser_test.cpp" />
     <ClCompile Include="..\..\src\row_test.cpp" />
@@ -189,10 +190,12 @@
     <ClCompile Include="..\..\src\teamcity\teamcity_boost.cpp" />
     <ClCompile Include="..\..\src\teamcity\teamcity_messages.cpp" />
     <ClCompile Include="..\..\src\test_utils.cpp" />
+    <ClCompile Include="..\..\src\types_test.cpp" />
     <ClCompile Include="..\..\src\utility_test.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\complex_type.h" />
+    <ClInclude Include="..\..\include\odbc_test_suite.h" />
     <ClInclude Include="..\..\include\sql_test_suite_fixture.h" />
     <ClInclude Include="..\..\include\teamcity\teamcity_messages.h" />
     <ClInclude Include="..\..\include\test_type.h" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/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 ebdf7d3..58cf045 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
@@ -133,6 +133,12 @@
     <ClCompile Include="..\..\src\sql_get_info_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\types_test.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\odbc_test_suite.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">
@@ -150,6 +156,9 @@
     <ClInclude Include="..\..\include\complex_type.h">
       <Filter>Code\CacheTypes</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\odbc_test_suite.h">
+      <Filter>Code</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\config\queries-test-32.xml">
@@ -171,4 +180,4 @@
       <Filter>Configs</Filter>
     </None>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
new file mode 100644
index 0000000..a967b4f
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
@@ -0,0 +1,526 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#   include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+#ifndef _MSC_VER
+#   define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+#include "ignite/ignition.h"
+
+#include "test_utils.h"
+#include "odbc_test_suite.h"
+
+using namespace ignite_test;
+using namespace boost::unit_test;
+
+namespace ignite
+{
+    namespace odbc
+    {
+        void OdbcTestSuite::Connect(const std::string& connectStr)
+        {
+            // Allocate an environment handle
+            SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
+
+            BOOST_REQUIRE(env != NULL);
+
+            // We want ODBC 3 support
+            SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
+
+            // Allocate a connection handle
+            SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+
+            BOOST_REQUIRE(dbc != NULL);
+
+            // Connect string
+            std::vector<SQLCHAR> connectStr0;
+
+            connectStr0.reserve(connectStr.size() + 1);
+            std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
+
+            SQLCHAR outstr[ODBC_BUFFER_SIZE];
+            SQLSMALLINT outstrlen;
+
+            // Connecting to ODBC server.
+            SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
+                                             outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+            if (!SQL_SUCCEEDED(ret))
+            {
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
+            }
+
+            // Allocate a statement handle
+            SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+
+            BOOST_REQUIRE(stmt != NULL);
+        }
+
+        void OdbcTestSuite::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);
+        }
+
+        Ignite OdbcTestSuite::StartTestNode(const char* cfg, const char* name)
+        {
+            std::string config(cfg);
+
+#ifdef IGNITE_TESTS_32
+            // Cutting off the ".xml" part.
+            config.resize(config.size() - 4);
+            config += "-32.xml";
+#endif //IGNITE_TESTS_32
+
+            return StartNode(config.c_str(), name);
+        }
+
+        OdbcTestSuite::OdbcTestSuite():
+            env(NULL),
+            dbc(NULL),
+            stmt(NULL)
+        {
+            // No-op.
+        }
+
+        OdbcTestSuite::~OdbcTestSuite()
+        {
+            Disconnect();
+
+            Ignition::StopAll(true);
+        }
+
+        std::string OdbcTestSuite::getTestString(int64_t ind)
+        {
+            std::stringstream builder;
+
+            builder << "String#" << ind;
+
+            return builder.str();
+        }
+
+        void OdbcTestSuite::InsertTestStrings(int recordsNum, bool merge)
+        {
+            SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)";
+            SQLCHAR mergeReq[] = "MERGE INTO TestType(_key, strField) VALUES(?, ?)";
+
+            SQLRETURN ret;
+
+            ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            int64_t key = 0;
+            char strField[1024] = {0};
+            SQLLEN strFieldLen = 0;
+
+            // Binding parameters.
+            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));
+
+            ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(strField),
+                                   sizeof(strField), &strField, sizeof(strField), &strFieldLen);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            // Inserting values.
+            for (SQLSMALLINT i = 0; i < recordsNum; ++i)
+            {
+                key = i + 1;
+                std::string val = getTestString(i);
+
+                strncpy(strField, val.c_str(), sizeof(strField));
+                strFieldLen = SQL_NTS;
+
+                ret = SQLExecute(stmt);
+
+                if (!SQL_SUCCEEDED(ret))
+                    BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+                SQLLEN affected = 0;
+                ret = SQLRowCount(stmt, &affected);
+
+                if (!SQL_SUCCEEDED(ret))
+                    BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+                BOOST_CHECK_EQUAL(affected, 1);
+
+                ret = SQLMoreResults(stmt);
+
+                if (ret != SQL_NO_DATA)
+                    BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            }
+
+            // Resetting parameters.
+            ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        }
+
+        int OdbcTestSuite::InsertTestBatch(int from, int to, int expectedToAffect, bool merge)
+        {
+            using common::FixedSizeArray;
+
+            SQLCHAR insertReq[] = "INSERT "
+                "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, "
+                "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+            SQLCHAR mergeReq[] = "MERGE "
+                "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, "
+                "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+            SQLRETURN ret;
+
+            int recordsNum = to - from;
+
+            ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            FixedSizeArray<int64_t> keys(recordsNum);
+            FixedSizeArray<int8_t> i8Fields(recordsNum);
+            FixedSizeArray<int16_t> i16Fields(recordsNum);
+            FixedSizeArray<int32_t> i32Fields(recordsNum);
+            FixedSizeArray<char> strFields(recordsNum * 1024);
+            FixedSizeArray<float> floatFields(recordsNum);
+            FixedSizeArray<double> doubleFields(recordsNum);
+            FixedSizeArray<bool> boolFields(recordsNum);
+            FixedSizeArray<SQL_DATE_STRUCT> dateFields(recordsNum);
+            FixedSizeArray<SQL_TIME_STRUCT> timeFields(recordsNum);
+            FixedSizeArray<SQL_TIMESTAMP_STRUCT> timestampFields(recordsNum);
+            FixedSizeArray<int8_t> i8ArrayFields(recordsNum * 42);
+
+            FixedSizeArray<SQLLEN> strFieldsLen(recordsNum);
+            FixedSizeArray<SQLLEN> i8ArrayFieldsLen(recordsNum);
+
+            BOOST_CHECKPOINT("Filling param data");
+
+            for (int i = 0; i < recordsNum; ++i)
+            {
+                int seed = from + i;
+
+                keys[i] = seed;
+                i8Fields[i] = seed * 8;
+                i16Fields[i] = seed * 16;
+                i32Fields[i] = seed * 32;
+
+                std::string val = getTestString(seed);
+                strncpy(strFields.GetData() + 1024 * i, val.c_str(), 1023);
+                strFieldsLen[i] = val.size();
+
+                floatFields[i] = seed * 0.5f;
+                doubleFields[i] = seed * 0.25f;
+                boolFields[i] = seed % 2 == 0;
+
+                dateFields[i].year = 2017 + seed / 365;
+                dateFields[i].month = ((seed / 28) % 12) + 1;
+                dateFields[i].day = (seed % 28) + 1;
+
+                timeFields[i].hour = (seed / 3600) % 24;
+                timeFields[i].minute = (seed / 60) % 60;
+                timeFields[i].second = seed % 60;
+
+                timestampFields[i].year = dateFields[i].year;
+                timestampFields[i].month = dateFields[i].month;
+                timestampFields[i].day = dateFields[i].day;
+                timestampFields[i].hour = timeFields[i].hour;
+                timestampFields[i].minute = timeFields[i].minute;
+                timestampFields[i].second = timeFields[i].second;
+                timestampFields[i].fraction = std::abs(seed * 914873) % 1000000000;
+
+                for (int j = 0; j < 42; ++j)
+                    i8ArrayFields[i * 42 + j] = seed * 42 + j;
+                i8ArrayFieldsLen[i] = 42;
+            }
+
+            SQLULEN setsProcessed = 0;
+
+            BOOST_CHECKPOINT("Setting processed pointer");
+            ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &setsProcessed, SQL_IS_POINTER);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding keys");
+            ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, keys.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding i8Fields");
+            ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_STINYINT, SQL_TINYINT, 0, 0, i8Fields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding i16Fields");
+            ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_SMALLINT, 0, 0, i16Fields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding i32Fields");
+            ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, i32Fields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding strFields");
+            ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 1024, 0, strFields.GetData(), 1024, strFieldsLen.GetData());
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding floatFields");
+            ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, floatFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding doubleFields");
+            ret = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, doubleFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding boolFields");
+            ret = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 0, 0, boolFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding dateFields");
+            ret = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE, 0, 0, dateFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding timeFields");
+            ret = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIME, 0, 0, timeFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding timestampFields");
+            ret = SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, 0, 0, timestampFields.GetData(), 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Binding i8ArrayFields");
+            ret = SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, 42, 0, i8ArrayFields.GetData(), 42, i8ArrayFieldsLen.GetData());
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Setting paramset size");
+            ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, reinterpret_cast<SQLPOINTER>(recordsNum), 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Executing query");
+            ret = SQLExecute(stmt);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            SQLLEN totallyAffected = 0;
+
+            do
+            {
+                SQLLEN affected = 0;
+                ret = SQLRowCount(stmt, &affected);
+
+                if (!SQL_SUCCEEDED(ret))
+                    BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+                totallyAffected += affected;
+
+                BOOST_CHECKPOINT("Getting next result set");
+
+                ret = SQLMoreResults(stmt);
+
+                if (ret != SQL_SUCCESS && ret != SQL_NO_DATA)
+                    BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            }
+            while (ret != SQL_NO_DATA);
+
+            BOOST_CHECK_EQUAL(totallyAffected, expectedToAffect);
+
+            BOOST_CHECKPOINT("Resetting parameters.");
+            ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            BOOST_CHECKPOINT("Setting paramset size");
+            ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, reinterpret_cast<SQLPOINTER>(1), 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            return static_cast<int>(setsProcessed);
+        }
+
+        void OdbcTestSuite::InsertBatchSelect(int recordsNum)
+        {
+            Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+            // Inserting values.
+            int inserted = InsertTestBatch(0, recordsNum, recordsNum);
+
+            BOOST_REQUIRE_EQUAL(inserted, recordsNum);
+
+            int64_t key = 0;
+            char strField[1024] = {0};
+            SQLLEN strFieldLen = 0;
+
+            // Binding columns.
+            SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            // Binding columns.
+            ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            // Just selecting everything to make sure everything is OK
+            SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key";
+
+            ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            int selectedRecordsNum = 0;
+
+            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));
+
+                std::string expectedStr = getTestString(selectedRecordsNum);
+                int64_t expectedKey = selectedRecordsNum;
+
+                BOOST_CHECK_EQUAL(key, expectedKey);
+
+                BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
+
+                ++selectedRecordsNum;
+            }
+
+            BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum);
+        }
+
+        void OdbcTestSuite::InsertNonFullBatchSelect(int recordsNum, int splitAt)
+        {
+            Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+            // Inserting values.
+            int inserted = InsertTestBatch(splitAt, recordsNum, recordsNum - splitAt);
+
+            BOOST_REQUIRE_EQUAL(inserted, recordsNum - splitAt);
+
+            inserted = InsertTestBatch(0, recordsNum, splitAt);
+
+            BOOST_REQUIRE_EQUAL(inserted, splitAt);
+
+            int64_t key = 0;
+            char strField[1024] = {0};
+            SQLLEN strFieldLen = 0;
+
+            // Binding columns.
+            SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            // Binding columns.
+            ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            // Just selecting everything to make sure everything is OK
+            SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key";
+
+            ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
+
+            if (!SQL_SUCCEEDED(ret))
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+            int selectedRecordsNum = 0;
+
+            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));
+
+                std::string expectedStr = getTestString(selectedRecordsNum);
+                int64_t expectedKey = selectedRecordsNum;
+
+                BOOST_CHECK_EQUAL(key, expectedKey);
+
+                BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
+
+                ++selectedRecordsNum;
+            }
+
+            BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/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 dafab1a..b11c8b1 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
@@ -42,6 +42,7 @@
 #include "test_type.h"
 #include "complex_type.h"
 #include "test_utils.h"
+#include "odbc_test_suite.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -59,91 +60,16 @@ using ignite::impl::binary::BinaryUtils;
 /**
  * Test setup fixture.
  */
-struct QueriesTestSuiteFixture 
+struct QueriesTestSuiteFixture : odbc::OdbcTestSuite
 {
     /**
-     * Establish connection to node.
-     *
-     * @param connectStr Connection string.
-     */
-    void Connect(const std::string& connectStr)
-    {
-        // Allocate an environment handle
-        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
-
-        BOOST_REQUIRE(env != NULL);
-
-        // We want ODBC 3 support
-        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
-
-        // Allocate a connection handle
-        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
-
-        BOOST_REQUIRE(dbc != NULL);
-
-        // Connect string
-        std::vector<SQLCHAR> connectStr0;
-
-        connectStr0.reserve(connectStr.size() + 1);
-        std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
-
-        SQLCHAR outstr[ODBC_BUFFER_SIZE];
-        SQLSMALLINT outstrlen;
-
-        // Connecting to ODBC server.
-        SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
-            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
-
-        if (!SQL_SUCCEEDED(ret))
-        {
-            Ignition::Stop(grid.GetName(), true);
-
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
-        }
-
-        // Allocate a statement handle
-        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
-
-        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)
-    {
-#ifdef IGNITE_TESTS_32
-        return StartNode("queries-test-noodbc-32.xml", name);
-#else
-        return StartNode("queries-test-noodbc.xml", name);
-#endif
-    }
-
-    /**
      * Constructor.
      */
     QueriesTestSuiteFixture() :
         cache1(0),
-        cache2(0),
-        env(NULL),
-        dbc(NULL),
-        stmt(NULL)
+        cache2(0)
     {
-#ifdef IGNITE_TESTS_32
-        grid = StartNode("queries-test-32.xml", "NodeMain");
-#else
-        grid = StartNode("queries-test.xml", "NodeMain");
-#endif
+        grid = StartTestNode("queries-test.xml", "NodeMain");
 
         cache1 = grid.GetCache<int64_t, TestType>("cache");
         cache2 = grid.GetCache<int64_t, ComplexType>("cache2");
@@ -152,11 +78,9 @@ struct QueriesTestSuiteFixture
     /**
      * Destructor.
      */
-    ~QueriesTestSuiteFixture()
+    virtual ~QueriesTestSuiteFixture()
     {
-        Disconnect();
-
-        Ignition::StopAll(true);
+        // No-op.
     }
 
     template<typename T>
@@ -302,420 +226,9 @@ struct QueriesTestSuiteFixture
         return res;
     }
 
-    static std::string getTestString(int64_t ind)
-    {
-        std::stringstream builder;
-
-        builder << "String#" << ind;
-
-        return builder.str();
-    }
-
-    /**
-     * Insert requested number of TestType values with all defaults except
-     * for the strFields, which are generated using getTestString().
-     *
-     * @param recordsNum Number of records to insert.
-     * @param merge Set to true to use merge instead.
-     */
-    void InsertTestStrings(int recordsNum, bool merge = false)
-    {
-        SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)";
-        SQLCHAR mergeReq[] = "MERGE INTO TestType(_key, strField) VALUES(?, ?)";
-
-        SQLRETURN ret;
-
-        ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        int64_t key = 0;
-        char strField[1024] = { 0 };
-        SQLLEN strFieldLen = 0;
-
-        // Binding parameters.
-        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));
-
-        ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(strField),
-            sizeof(strField), &strField, sizeof(strField), &strFieldLen);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        // Inserting values.
-        for (SQLSMALLINT i = 0; i < recordsNum; ++i)
-        {
-            key = i + 1;
-            std::string val = getTestString(i);
-
-            strncpy(strField, val.c_str(), sizeof(strField));
-            strFieldLen = SQL_NTS;
-
-            ret = SQLExecute(stmt);
-
-            if (!SQL_SUCCEEDED(ret))
-                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-            SQLLEN affected = 0;
-            ret = SQLRowCount(stmt, &affected);
-
-            if (!SQL_SUCCEEDED(ret))
-                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-            BOOST_CHECK_EQUAL(affected, 1);
-
-            ret = SQLMoreResults(stmt);
-
-            if (ret != SQL_NO_DATA)
-                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-        }
-
-        // Resetting parameters.
-        ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-    }
-
-    /**
-     * Insert requested number of TestType values in a batch.
-     *
-     * @param from Index to start from.
-     * @param to Index to stop.
-     * @param expectedToAffect Expected number of affected records.
-     * @param merge Set to true to use merge instead of insert.
-     * @return Records inserted.
-     */
-    int InsertTestBatch(int from, int to, int expectedToAffect, bool merge = false)
-    {
-        SQLCHAR insertReq[] = "INSERT "
-            "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, "
-            "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
-
-        SQLCHAR mergeReq[] = "MERGE "
-            "INTO TestType(_key, i8Field, i16Field, i32Field, strField, floatField, doubleField, boolField, dateField, "
-            "timeField, timestampField, i8ArrayField) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
-
-        SQLRETURN ret;
-
-        int recordsNum = to - from;
-
-        ret = SQLPrepare(stmt, merge ? mergeReq : insertReq, SQL_NTS);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        FixedSizeArray<int64_t> keys(recordsNum);
-        FixedSizeArray<int8_t> i8Fields(recordsNum);
-        FixedSizeArray<int16_t> i16Fields(recordsNum);
-        FixedSizeArray<int32_t> i32Fields(recordsNum);
-        FixedSizeArray<char> strFields(recordsNum * 1024);
-        FixedSizeArray<float> floatFields(recordsNum);
-        FixedSizeArray<double> doubleFields(recordsNum);
-        FixedSizeArray<bool> boolFields(recordsNum);
-        FixedSizeArray<SQL_DATE_STRUCT> dateFields(recordsNum);
-        FixedSizeArray<SQL_TIME_STRUCT> timeFields(recordsNum);
-        FixedSizeArray<SQL_TIMESTAMP_STRUCT> timestampFields(recordsNum);
-        FixedSizeArray<int8_t> i8ArrayFields(recordsNum * 42);
-
-        FixedSizeArray<SQLLEN> strFieldsLen(recordsNum);
-        FixedSizeArray<SQLLEN> i8ArrayFieldsLen(recordsNum);
-
-        BOOST_CHECKPOINT("Filling param data");
-
-        for (int i = 0; i < recordsNum; ++i)
-        {
-            int seed = from + i;
-
-            keys[i] = seed;
-            i8Fields[i] = seed * 8;
-            i16Fields[i] = seed * 16;
-            i32Fields[i] = seed * 32;
-
-            std::string val = getTestString(seed);
-            strncpy(strFields.GetData() + 1024 * i, val.c_str(), 1023);
-            strFieldsLen[i] = val.size();
-
-            floatFields[i] = seed * 0.5f;
-            doubleFields[i] = seed * 0.25f;
-            boolFields[i] = seed % 2 == 0;
-
-            dateFields[i].year = 2017 + seed / 365;
-            dateFields[i].month = ((seed / 28) % 12) + 1;
-            dateFields[i].day = (seed % 28) + 1;
-
-            timeFields[i].hour = (seed / 3600) % 24;
-            timeFields[i].minute = (seed / 60) % 60;
-            timeFields[i].second = seed % 60;
-
-            timestampFields[i].year = dateFields[i].year;
-            timestampFields[i].month = dateFields[i].month;
-            timestampFields[i].day = dateFields[i].day;
-            timestampFields[i].hour = timeFields[i].hour;
-            timestampFields[i].minute = timeFields[i].minute;
-            timestampFields[i].second = timeFields[i].second;
-            timestampFields[i].fraction = std::abs(seed * 914873) % 1000000000;
-
-            for (int j = 0; j < 42; ++j)
-                i8ArrayFields[i * 42 + j] = seed * 42 + j;
-            i8ArrayFieldsLen[i] = 42;
-        }
-
-        SQLULEN setsProcessed = 0;
-
-        BOOST_CHECKPOINT("Setting processed pointer");
-        ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &setsProcessed, SQL_IS_POINTER);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding keys");
-        ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, keys.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding i8Fields");
-        ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_STINYINT, SQL_TINYINT, 0, 0, i8Fields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding i16Fields");
-        ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_SMALLINT, 0, 0, i16Fields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding i32Fields");
-        ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, i32Fields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding strFields");
-        ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 1024, 0, strFields.GetData(), 1024, strFieldsLen.GetData());
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding floatFields");
-        ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, floatFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding doubleFields");
-        ret = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, doubleFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding boolFields");
-        ret = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 0, 0, boolFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding dateFields");
-        ret = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE, 0, 0, dateFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding timeFields");
-        ret = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIME, 0, 0, timeFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding timestampFields");
-        ret = SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, 0, 0, timestampFields.GetData(), 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Binding i8ArrayFields");
-        ret = SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, 42, 0, i8ArrayFields.GetData(), 42, i8ArrayFieldsLen.GetData());
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Setting paramset size");
-        ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, reinterpret_cast<SQLPOINTER>(recordsNum), 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Executing query");
-        ret = SQLExecute(stmt);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        SQLLEN totallyAffected = 0;
-
-        do
-        {
-            SQLLEN affected = 0;
-            ret = SQLRowCount(stmt, &affected);
-
-            if (!SQL_SUCCEEDED(ret))
-                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-            totallyAffected += affected;
-
-            BOOST_CHECKPOINT("Getting next result set");
-
-            ret = SQLMoreResults(stmt);
-
-            if (ret != SQL_SUCCESS && ret != SQL_NO_DATA)
-                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-        } while (ret != SQL_NO_DATA);
-
-        BOOST_CHECK_EQUAL(totallyAffected, expectedToAffect);
-
-        BOOST_CHECKPOINT("Resetting parameters.");
-        ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        BOOST_CHECKPOINT("Setting paramset size");
-        ret = SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, reinterpret_cast<SQLPOINTER>(1), 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        return static_cast<int>(setsProcessed);
-    }
-
-    void InsertBatchSelect(int recordsNum)
-    {
-        Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
-
-        // Inserting values.
-        int inserted = InsertTestBatch(0, recordsNum, recordsNum);
-
-        BOOST_REQUIRE_EQUAL(inserted, recordsNum);
-
-        int64_t key = 0;
-        char strField[1024] = { 0 };
-        SQLLEN strFieldLen = 0;
-
-        // Binding columns.
-        SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        // Binding columns.
-        ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        // Just selecting everything to make sure everything is OK
-        SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key";
-
-        ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        int selectedRecordsNum = 0;
-
-        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));
-
-            std::string expectedStr = getTestString(selectedRecordsNum);
-            int64_t expectedKey = selectedRecordsNum;
-
-            BOOST_CHECK_EQUAL(key, expectedKey);
-
-            BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
-
-            ++selectedRecordsNum;
-        }
-
-        BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum);
-    }
-
-    void InsertNonFullBatchSelect(int recordsNum, int splitAt)
+    static Ignite StartAdditionalNode(const char* name)
     {
-        Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
-
-        // Inserting values.
-        int inserted = InsertTestBatch(splitAt, recordsNum, recordsNum - splitAt);
-
-        BOOST_REQUIRE_EQUAL(inserted, recordsNum - splitAt);
-
-        inserted = InsertTestBatch(0, recordsNum, splitAt);
-
-        BOOST_REQUIRE_EQUAL(inserted, splitAt);
-
-        int64_t key = 0;
-        char strField[1024] = { 0 };
-        SQLLEN strFieldLen = 0;
-
-        // Binding columns.
-        SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &key, 0, 0);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        // Binding columns.
-        ret = SQLBindCol(stmt, 2, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        // Just selecting everything to make sure everything is OK
-        SQLCHAR selectReq[] = "SELECT _key, strField FROM TestType ORDER BY _key";
-
-        ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
-
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-
-        int selectedRecordsNum = 0;
-
-        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));
-
-            std::string expectedStr = getTestString(selectedRecordsNum);
-            int64_t expectedKey = selectedRecordsNum;
-
-            BOOST_CHECK_EQUAL(key, expectedKey);
-
-            BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expectedStr);
-
-            ++selectedRecordsNum;
-        }
-
-        BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum);
+        return StartTestNode("queries-test-noodbc.xml", name);
     }
 
     /** Node started during the test. */
@@ -726,15 +239,6 @@ struct QueriesTestSuiteFixture
 
     /** Second cache instance. */
     Cache<int64_t, ComplexType> cache2;
-
-    /** ODBC Environment. */
-    SQLHENV env;
-
-    /** ODBC Connect. */
-    SQLHDBC dbc;
-
-    /** ODBC Statement. */
-    SQLHSTMT stmt;
 };
 
 BOOST_FIXTURE_TEST_SUITE(QueriesTestSuite, QueriesTestSuiteFixture)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e9702a52/modules/platforms/cpp/odbc-test/src/types_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/types_test.cpp b/modules/platforms/cpp/odbc-test/src/types_test.cpp
new file mode 100644
index 0000000..d5c7834
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/src/types_test.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#   include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#ifndef _MSC_VER
+#   define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+#include "ignite/ignite.h"
+#include "test_type.h"
+#include "test_utils.h"
+#include "odbc_test_suite.h"
+
+using namespace ignite;
+using namespace ignite_test;
+
+using namespace boost::unit_test;
+
+/**
+ * Test setup fixture.
+ */
+struct TypesTestSuiteFixture : odbc::OdbcTestSuite
+{
+    /**
+     * Constructor.
+     */
+    TypesTestSuiteFixture() :
+        cache1(0)
+    {
+        node = StartTestNode("queries-test.xml", "NodeMain");
+
+        cache1 = node.GetCache<int64_t, TestType>("cache");
+    }
+
+    /**
+     * Destructor.
+     */
+    virtual ~TypesTestSuiteFixture()
+    {
+        // No-op.
+    }
+
+    /** Node started during the test. */
+    Ignite node;
+
+    /** Cache instance. */
+    cache::Cache<int64_t, TestType> cache1;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TypesTestSuite, TypesTestSuiteFixture)
+
+BOOST_AUTO_TEST_CASE(TestZeroDecimal)
+{
+    Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;SCHEMA=PUBLIC");
+
+    SQLCHAR ddl[] = "CREATE TABLE IF NOT EXISTS TestTable "
+        "(RecId varchar PRIMARY KEY, RecValue DECIMAL(4,2))"
+        "WITH \"template=replicated, cache_name=TestTable_Cache\";";
+
+    SQLRETURN ret = SQLExecDirect(stmt, ddl, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQLCHAR dml[] = "INSERT INTO TestTable (RecId, RecValue) VALUES ('1', ?)";
+
+    ret = SQLPrepare(stmt, dml, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQL_NUMERIC_STRUCT num;
+
+    memset(&num, 0, sizeof(num));
+
+    num.sign = 1;
+    num.precision = 1;
+
+    ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_DECIMAL, 0, 0, &num, 0, 0);
+
+    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));
+
+    ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQL_NUMERIC_STRUCT num0;
+    SQLLEN num0Len = static_cast<SQLLEN>(sizeof(num0));
+
+    // Filling data to avoid acidental equality
+    memset(&num0, 0xFF, sizeof(num0));
+
+    ret = SQLBindCol(stmt, 1, SQL_C_NUMERIC, &num0, sizeof(num0), &num0Len);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQLCHAR qry[] = "SELECT RecValue FROM TestTable WHERE RecId = '1'";
+
+    ret = SQLExecDirect(stmt, qry, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    ret = SQLFetch(stmt);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    BOOST_CHECK_EQUAL(num.precision, num0.precision);
+    BOOST_CHECK_EQUAL(num.scale, num0.scale);
+    BOOST_CHECK_EQUAL(num.sign, num0.sign);
+
+    BOOST_CHECK_EQUAL(num.val[0], num0.val[0]);
+    BOOST_CHECK_EQUAL(num.val[1], num0.val[1]);
+    BOOST_CHECK_EQUAL(num.val[2], num0.val[2]);
+    BOOST_CHECK_EQUAL(num.val[3], num0.val[3]);
+    BOOST_CHECK_EQUAL(num.val[4], num0.val[4]);
+    BOOST_CHECK_EQUAL(num.val[5], num0.val[5]);
+    BOOST_CHECK_EQUAL(num.val[6], num0.val[6]);
+    BOOST_CHECK_EQUAL(num.val[7], num0.val[7]);
+    BOOST_CHECK_EQUAL(num.val[8], num0.val[8]);
+    BOOST_CHECK_EQUAL(num.val[9], num0.val[9]);
+    BOOST_CHECK_EQUAL(num.val[10], num0.val[10]);
+    BOOST_CHECK_EQUAL(num.val[11], num0.val[11]);
+    BOOST_CHECK_EQUAL(num.val[12], num0.val[12]);
+    BOOST_CHECK_EQUAL(num.val[13], num0.val[13]);
+    BOOST_CHECK_EQUAL(num.val[14], num0.val[14]);
+    BOOST_CHECK_EQUAL(num.val[15], num0.val[15]);
+}
+
+BOOST_AUTO_TEST_SUITE_END()