You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/11/23 15:07:14 UTC

ignite git commit: IGNITE-4016: ODBC: Example now uses DML. This closes #1265.

Repository: ignite
Updated Branches:
  refs/heads/ignite-1.8 f4524a6a7 -> 83363d8e0


IGNITE-4016: ODBC: Example now uses DML. This closes #1265.


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

Branch: refs/heads/ignite-1.8
Commit: 83363d8e0cab93b62f674ce0215082364881254b
Parents: f4524a6
Author: isapego <ig...@gmail.com>
Authored: Wed Nov 23 18:07:06 2016 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Wed Nov 23 18:07:06 2016 +0300

----------------------------------------------------------------------
 .../odbc-example/config/example-odbc.xml        |  30 +-
 .../project/vs/odbc-example.vcxproj             |   7 +-
 .../project/vs/odbc-example.vcxproj.filters     |   8 +
 .../examples/odbc-example/src/odbc_example.cpp  | 514 ++++++++++++++++---
 4 files changed, 466 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/83363d8e/modules/platforms/cpp/examples/odbc-example/config/example-odbc.xml
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/examples/odbc-example/config/example-odbc.xml b/modules/platforms/cpp/examples/odbc-example/config/example-odbc.xml
index db4c390..864f950 100644
--- a/modules/platforms/cpp/examples/odbc-example/config/example-odbc.xml
+++ b/modules/platforms/cpp/examples/odbc-example/config/example-odbc.xml
@@ -39,26 +39,30 @@
                     <property name="cacheMode" value="PARTITIONED"/>
                     <property name="atomicityMode" value="TRANSACTIONAL"/>
                     <property name="writeSynchronizationMode" value="FULL_SYNC"/>
-            
-                    <!-- Configure type metadata to enable queries. -->
-                    <property name="typeMetadata">
+
+                    <property name="queryEntities">
                         <list>
-                            <bean class="org.apache.ignite.cache.CacheTypeMetadata">
+                            <bean class="org.apache.ignite.cache.QueryEntity">
                                 <property name="keyType" value="java.lang.Long"/>
                                 <property name="valueType" value="Person"/>
-                                <property name="ascendingFields">
+
+                                <property name="fields">
                                     <map>
                                         <entry key="orgId" value="java.lang.Long"/>
-                                    </map>
-                                </property>
-                                <property name="queryFields">
-                                    <map>
                                         <entry key="firstName" value="java.lang.String"/>
                                         <entry key="lastName" value="java.lang.String"/>
                                         <entry key="resume" value="java.lang.String"/>
                                         <entry key="salary" value="java.lang.Double"/>
                                     </map>
                                 </property>
+
+                                <property name="indexes">
+                                    <list>
+                                        <bean class="org.apache.ignite.cache.QueryIndex">
+                                            <constructor-arg value="orgId"/>
+                                        </bean>
+                                    </list>
+                                </property>
                             </bean>
                         </list>
                     </property>
@@ -70,13 +74,13 @@
                     <property name="atomicityMode" value="TRANSACTIONAL"/>
                     <property name="writeSynchronizationMode" value="FULL_SYNC"/>
             
-                    <!-- Configure type metadata to enable queries. -->
-                    <property name="typeMetadata">
+                    <property name="queryEntities">
                         <list>
-                            <bean class="org.apache.ignite.cache.CacheTypeMetadata">
+                            <bean class="org.apache.ignite.cache.QueryEntity">
                                 <property name="keyType" value="java.lang.Long"/>
                                 <property name="valueType" value="Organization"/>
-                                <property name="ascendingFields">
+
+                                <property name="fields">
                                     <map>
                                         <entry key="name" value="java.lang.String"/>
                                     </map>

http://git-wip-us.apache.org/repos/asf/ignite/blob/83363d8e/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj b/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj
index e7bdd08..9f7cf3a 100644
--- a/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj
+++ b/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj
@@ -54,7 +54,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;..\..\..\include;..\..\..\..\common\os\win\include;..\..\..\..\common\include;..\..\..\..\jni\os\win\include;..\..\..\..\jni\include;..\..\..\..\binary\include;..\..\..\..\core\os\win\include;..\..\..\..\core\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -78,7 +78,7 @@ copy "$(ProjectDir)..\..\..\..\project\vs\$(Platform)\$(Configuration)\ignite.co
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;..\..\..\include;..\..\..\..\common\os\win\include;..\..\..\..\common\include;..\..\..\..\jni\os\win\include;..\..\..\..\jni\include;..\..\..\..\binary\include;..\..\..\..\core\os\win\include;..\..\..\..\core\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -102,6 +102,9 @@ copy "$(ProjectDir)..\..\..\..\project\vs\$(Platform)\$(Configuration)\ignite.co
     <ClInclude Include="..\..\..\include\ignite\examples\organization.h" />
     <ClInclude Include="..\..\..\include\ignite\examples\person.h" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\config\example-odbc.xml" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

http://git-wip-us.apache.org/repos/asf/ignite/blob/83363d8e/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj.filters b/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj.filters
index 44fff7c..aa4427f 100644
--- a/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj.filters
+++ b/modules/platforms/cpp/examples/odbc-example/project/vs/odbc-example.vcxproj.filters
@@ -8,6 +8,9 @@
     <Filter Include="Header Files">
       <UniqueIdentifier>{6400d7ba-6390-4cdb-aa25-9525f8a71444}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Config">
+      <UniqueIdentifier>{d054b826-ae5e-4a0c-833f-ae0b975f57d8}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\odbc_example.cpp">
@@ -25,4 +28,9 @@
       <Filter>Header Files</Filter>
     </ClInclude>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\config\example-odbc.xml">
+      <Filter>Config</Filter>
+    </None>
+  </ItemGroup>
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/83363d8e/modules/platforms/cpp/examples/odbc-example/src/odbc_example.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/examples/odbc-example/src/odbc_example.cpp b/modules/platforms/cpp/examples/odbc-example/src/odbc_example.cpp
index 39648d2..38e7426 100644
--- a/modules/platforms/cpp/examples/odbc-example/src/odbc_example.cpp
+++ b/modules/platforms/cpp/examples/odbc-example/src/odbc_example.cpp
@@ -35,7 +35,6 @@
 #include "ignite/examples/organization.h"
 
 using namespace ignite;
-using namespace cache;
 
 using namespace examples;
 
@@ -48,6 +47,16 @@ using namespace examples;
  *
  * After all pre-requirements are fulfilled just build project as described
  * in README and run resulting file.
+ *
+ * Note, that all fields which used in queries must be listed in config file
+ * under queryEntities property of the caches. You can find config file in
+ * config directory: cpp/examples/odbc-example/config/example-odbc.xml
+ *
+ * In addition to all the fields listed under QueryEntity bean, each table
+ * have two special predefined fields: _key and _val, which represent links
+ * to whole key and value objects. In some queries _key column is used. Key
+ * in our case works like an ID for the row and it should always present in
+ * INSERT statements.
  */
 
 /** Read buffer size. */
@@ -118,101 +127,424 @@ std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle)
 }
 
 /**
+ * Extract error from ODBC handle and throw it as IgniteError.
+ *
+ * @param handleType Type of the handle.
+ * @param handle Handle.
+ * @param msg Error message.
+ */
+void ThrowOdbcError(SQLSMALLINT handleType, SQLHANDLE handle, std::string msg)
+{
+    std::stringstream builder;
+
+    builder << msg << ": " << GetOdbcErrorMessage(handleType, handle);
+
+    std::string errorMsg = builder.str();
+
+    throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, errorMsg.c_str());
+}
+
+/**
  * Fetch cache data using ODBC interface.
  */
-void GetDataWithOdbc(const std::string& query)
+void GetDataWithOdbc(SQLHDBC dbc, const std::string& query)
 {
-    SQLHENV env;
+    SQLHSTMT stmt;
 
-    // Allocate an environment handle
-    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
+    // Allocate a statement handle
+    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
 
-    // We want ODBC 3 support
-    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
+    std::vector<SQLCHAR> buf(query.begin(), query.end());
 
-    SQLHDBC dbc;
+    SQLRETURN ret = SQLExecDirect(stmt, &buf[0], static_cast<SQLSMALLINT>(buf.size()));
 
-    // Allocate a connection handle
-    SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+    if (SQL_SUCCEEDED(ret))
+        PrintOdbcResultSet(stmt);
+    else
+        std::cerr << "Failed to execute query: " << GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt) << std::endl;
 
-    // Combining connect string
-    std::string connectStr = "DRIVER={Apache Ignite};SERVER=localhost;PORT=10800;CACHE=Person;";
+    // Releasing statement handle.
+    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+}
 
-    SQLCHAR outstr[ODBC_BUFFER_SIZE];
-    SQLSMALLINT outstrlen;
+/**
+ * Populate Person cache with sample data.
+ * 
+ * @param dbc Database connection.
+ */
+void PopulatePerson(SQLHDBC dbc)
+{
+    SQLHSTMT stmt;
 
-    // Connecting to ODBC server.
-    SQLRETURN ret = SQLDriverConnect(dbc, NULL, reinterpret_cast<SQLCHAR*>(&connectStr[0]),
-        static_cast<SQLSMALLINT>(connectStr.size()), outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+    // Allocate a statement handle
+    SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
 
     if (!SQL_SUCCEEDED(ret))
+        ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle");
+
+    try
     {
-        std::cerr << "Failed to connect: " << GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc) << std::endl;
+        SQLCHAR query[] =
+            "INSERT INTO Person (_key, orgId, firstName, lastName, resume, salary) "
+            "VALUES (?, ?, ?, ?, ?, ?)";
+
+        ret = SQLPrepare(stmt, query, static_cast<SQLSMALLINT>(sizeof(query)));
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to prepare query");
+
+        // Binding columns.
+
+        int64_t key = 0;
+        int64_t orgId = 0;
+        char firstName[1024] = { 0 };
+        SQLLEN firstNameLen = SQL_NTS;
+        char lastName[1024] = { 0 };
+        SQLLEN lastNameLen = SQL_NTS;
+        char resume[1024] = { 0 };
+        SQLLEN resumeLen = SQL_NTS;
+        double salary = 0.0;
+
+        ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &orgId, 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
+            sizeof(firstName), sizeof(firstName), firstName, 0, &firstNameLen);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
+            sizeof(lastName), sizeof(lastName), lastName, 0, &lastNameLen);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
+            sizeof(resume), sizeof(resume), resume, 0, &resumeLen);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &salary, 0, 0);
 
-        return;
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        // Filling cache.
+
+        key = 1;
+        orgId = 1;
+        strncpy(firstName, "John", sizeof(firstName));
+        strncpy(lastName, "Doe", sizeof(lastName));
+        strncpy(resume, "Master Degree.", sizeof(resume));
+        salary = 2200.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 1;
+        strncpy(firstName, "Jane", sizeof(firstName));
+        strncpy(lastName, "Doe", sizeof(lastName));
+        strncpy(resume, "Bachelor Degree.", sizeof(resume));
+        salary = 1300.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 2;
+        strncpy(firstName, "John", sizeof(firstName));
+        strncpy(lastName, "Smith", sizeof(lastName));
+        strncpy(resume, "Bachelor Degree.", sizeof(resume));
+        salary = 1700.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 2;
+        strncpy(firstName, "Jane", sizeof(firstName));
+        strncpy(lastName, "Smith", sizeof(lastName));
+        strncpy(resume, "Master Degree.", sizeof(resume));
+        salary = 2500.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 2;
+        strncpy(firstName, "John", sizeof(firstName));
+        strncpy(lastName, "Roe", sizeof(lastName));
+        strncpy(resume, "Bachelor Degree.", sizeof(resume));
+        salary = 1500.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 2;
+        strncpy(firstName, "Jane", sizeof(firstName));
+        strncpy(lastName, "Roe", sizeof(lastName));
+        strncpy(resume, "Bachelor Degree.", sizeof(resume));
+        salary = 1000.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 1;
+        strncpy(firstName, "Richard", sizeof(firstName));
+        strncpy(lastName, "Miles", sizeof(lastName));
+        strncpy(resume, "Master Degree.", sizeof(resume));
+        salary = 2400.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+
+        ret = SQLMoreResults(stmt);
+
+        if (ret != SQL_NO_DATA)
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected");
+
+        ++key;
+        orgId = 2;
+        strncpy(firstName, "Mary", sizeof(firstName));
+        strncpy(lastName, "Major", sizeof(lastName));
+        strncpy(resume, "Bachelor Degree.", sizeof(resume));
+        salary = 900.0;
+
+        ret = SQLExecute(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement");
+    }
+    catch(...)
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+        // Re-throwing expection.
+        throw;
     }
 
+    // Releasing statement handle.
+    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+}
+
+/**
+ * Populate Organization cache with sample data.
+ * 
+ * @param dbc Database connection.
+ */
+void PopulateOrganization(SQLHDBC dbc)
+{
     SQLHSTMT stmt;
 
     // Allocate a statement handle
-    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+    SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
 
-    std::vector<SQLCHAR> buf(query.begin(), query.end());
+    if (!SQL_SUCCEEDED(ret))
+        ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle");
 
-    ret = SQLExecDirect(stmt, &buf[0], static_cast<SQLSMALLINT>(buf.size()));
+    try
+    {
+        SQLCHAR query1[] = "INSERT INTO \"Organization\".Organization (_key, name) VALUES (1L, 'Microsoft')";
 
-    if (SQL_SUCCEEDED(ret))
-        PrintOdbcResultSet(stmt);
-    else
-        std::cerr << "Failed to execute query: " << GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt) << std::endl;
+        ret = SQLExecDirect(stmt, query1, static_cast<SQLSMALLINT>(sizeof(query1)));
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query");
+
+        SQLFreeStmt(stmt, SQL_CLOSE);
+
+        SQLCHAR query2[] = "INSERT INTO \"Organization\".Organization (_key, name) VALUES (2L, 'Red Cross')";
+
+        ret = SQLExecDirect(stmt, query2, static_cast<SQLSMALLINT>(sizeof(query2)));
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query");
+    }
+    catch (...)
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+        // Re-throwing expection.
+        throw;
+    }
 
     // Releasing statement handle.
     SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+}
+
+/**
+ * Adjust salary for specified employee.
+ *
+ * @param dbc Database connection.
+ * @param key Person key.
+ * @param salary New salary.
+ */
+void AdjustSalary(SQLHDBC dbc, int64_t key, double salary)
+{
+    SQLHSTMT stmt;
+
+    // Allocate a statement handle
+    SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+
+    if (!SQL_SUCCEEDED(ret))
+        ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle");
+
+    try
+    {
+        SQLCHAR query[] = "UPDATE Person SET salary=? WHERE _key=?";
+
+        ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &salary, 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLExecDirect(stmt, query, static_cast<SQLSMALLINT>(sizeof(query)));
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query");
+    }
+    catch (...)
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 
-    // Disconneting from the server.
-    SQLDisconnect(dbc);
+        // Re-throwing expection.
+        throw;
+    }
 
-    // Releasing allocated handles.
-    SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-    SQLFreeHandle(SQL_HANDLE_ENV, env);
+    // Releasing statement handle.
+    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 }
 
 /**
- * Populate Person cache with sample data.
- * 
- * @param cache Cache instance.
+ * Remove specified person.
+ *
+ * @param dbc Database connection.
+ * @param key Person key.
  */
-void Populate(Cache<int64_t, Person>& cache)
+void DeletePerson(SQLHDBC dbc, int64_t key)
 {
-    std::map<int64_t, Person> persons;
-
-    int64_t key = 0;
-    persons[++key] = Person(1, "John", "Doe", "Master Degree.", 2200.0);
-    persons[++key] = Person(1, "Jane", "Doe", "Bachelor Degree.", 1300.0);
-    persons[++key] = Person(2, "John", "Smith", "Bachelor Degree.", 1700.0);
-    persons[++key] = Person(2, "Jane", "Smith", "Master Degree.", 2500.0);
-    persons[++key] = Person(2, "John", "Roe", "Bachelor Degree.", 1500.0);
-    persons[++key] = Person(2, "Jane", "Roe", "Bachelor Degree.", 1000.0);
-    persons[++key] = Person(1, "Richard", "Miles", "Master Degree.", 2400.0);
-    persons[++key] = Person(2, "Mary", "Major", "Bachelor Degree.", 900.0);
-
-    cache.PutAll(persons);
+    SQLHSTMT stmt;
+
+    // Allocate a statement handle
+    SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+
+    if (!SQL_SUCCEEDED(ret))
+        ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle");
+
+    try
+    {
+        SQLCHAR query[] = "DELETE FROM Person WHERE _key=?";
+
+        ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter");
+
+        ret = SQLExecDirect(stmt, query, static_cast<SQLSMALLINT>(sizeof(query)));
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query");
+    }
+    catch (...)
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+        // Re-throwing expection.
+        throw;
+    }
+
+    // Releasing statement handle.
+    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 }
 
 /**
- * Populate Organization cache with sample data.
+ * Query tables.
  * 
- * @param cache Cache instance.
+ * @param dbc Database connection.
  */
-void Populate(Cache<int64_t, Organization>& cache)
+void QueryData(SQLHDBC dbc)
 {
-    std::map<int64_t, Organization> orgs;
+    std::cout << std::endl;
+    std::cout << ">>> Getting list of persons:" << std::endl;
 
-    int64_t key = 0;
-    orgs[++key] = Organization("Microsoft", Address("1096 Eddy Street, San Francisco, CA", 94109));
-    orgs[++key] = Organization("Red Cross", Address("184 Fidler Drive, San Antonio, TX", 78205));
+    GetDataWithOdbc(dbc, "SELECT firstName, lastName, resume, salary FROM Person");
+
+    std::cout << std::endl;
+    std::cout << ">>> Getting average salary by degree:" << std::endl;
+
+    GetDataWithOdbc(dbc, "SELECT resume, AVG(salary) FROM Person GROUP BY resume");
+
+    std::cout << std::endl;
+    std::cout << ">>> Getting people with organizations:" << std::endl;
 
-    cache.PutAll(orgs);
+    GetDataWithOdbc(dbc, "SELECT firstName, lastName, Organization.name FROM Person "
+        "INNER JOIN \"Organization\".Organization ON Person.orgId = Organization._KEY");
 }
 
 /**
@@ -225,7 +557,7 @@ int main()
     IgniteConfiguration cfg;
 
     cfg.jvmInitMem = 512;
-    cfg.jvmMaxMem = 512;
+    cfg.jvmMaxMem = 1024;
 
     cfg.springCfgPath = "platforms/cpp/examples/odbc-example/config/example-odbc.xml";
 
@@ -234,39 +566,65 @@ int main()
         // Start a node.
         Ignite grid = Ignition::Start(cfg);
 
-        std::cout << std::endl;
-        std::cout << ">>> Cache ODBC example started." << std::endl;
-        std::cout << std::endl;
+        SQLHENV env;
 
-        // Get Person cache instance.
-        Cache<int64_t, Person> personCache = grid.GetCache<int64_t, Person>("Person");
+        // Allocate an environment handle
+        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
 
-        // Get Organization cache instance.
-        Cache<int64_t, Organization> orgCache = grid.GetCache<int64_t, Organization>("Organization");
+        // We want ODBC 3 support
+        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
 
-        // Clear caches.
-        personCache.Clear();
-        orgCache.Clear();
+        SQLHDBC dbc;
 
-        // Populate caches.
-        Populate(personCache);
-        Populate(orgCache);
+        // Allocate a connection handle
+        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+
+        // Combining connect string
+        std::string connectStr = "DRIVER={Apache Ignite};SERVER=localhost;PORT=10800;CACHE=Person;";
+
+        SQLCHAR outstr[ODBC_BUFFER_SIZE];
+        SQLSMALLINT outstrlen;
+
+        // Connecting to ODBC server.
+        SQLRETURN ret = SQLDriverConnect(dbc, NULL, reinterpret_cast<SQLCHAR*>(&connectStr[0]),
+            static_cast<SQLSMALLINT>(connectStr.size()), outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+        if (!SQL_SUCCEEDED(ret))
+            ThrowOdbcError(SQL_HANDLE_DBC, dbc, "Failed to connect");
 
         std::cout << std::endl;
-        std::cout << ">>> Getting list of persons:" << std::endl;
+        std::cout << ">>> Cache ODBC example started." << std::endl;
+        std::cout << std::endl;
+
+        // Populate caches.
+        PopulatePerson(dbc);
+        PopulateOrganization(dbc);
 
-        GetDataWithOdbc("SELECT firstName, lastName, resume, salary FROM Person");
+        QueryData(dbc);
 
         std::cout << std::endl;
-        std::cout << ">>> Getting average salary by degree:" << std::endl;
+        std::cout << std::endl;
+        std::cout << ">>> Adjusted salary for Mary Major. Querying again." << std::endl;
+
+        AdjustSalary(dbc, 8, 1200.0);
 
-        GetDataWithOdbc("SELECT resume, AVG(salary) FROM Person GROUP BY resume");
+        QueryData(dbc);
 
         std::cout << std::endl;
-        std::cout << ">>> Getting people with organizations:" << std::endl;
+        std::cout << std::endl;
+        std::cout << ">>> Removing several employees. Querying again." << std::endl;
+
+        DeletePerson(dbc, 4);
+        DeletePerson(dbc, 5);
+
+        QueryData(dbc);
+
+        // Disconneting from the server.
+        SQLDisconnect(dbc);
 
-        GetDataWithOdbc("SELECT firstName, lastName, Organization.name FROM Person "
-            "INNER JOIN \"Organization\".Organization ON Person.orgId = Organization._KEY");
+        // Releasing allocated handles.
+        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
+        SQLFreeHandle(SQL_HANDLE_ENV, env);
 
         // Stop node.
         Ignition::StopAll(false);
@@ -277,7 +635,7 @@ int main()
     }
 
     std::cout << std::endl;
-    std::cout << ">>> Example finished, press any key to exit ..." << std::endl;
+    std::cout << ">>> Example finished, press 'Enter' to exit ..." << std::endl;
     std::cout << std::endl;
 
     std::cin.get();