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/01/27 11:39:46 UTC

[13/28] ignite git commit: IGNITE-2442: ODBC projects moved to main cpp solution.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/odbc.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp
new file mode 100644
index 0000000..84e312a
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -0,0 +1,1687 @@
+/*
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+
+#include "ignite/odbc/utility.h"
+#include "ignite/odbc/system/odbc_constants.h"
+
+#include "ignite/odbc/config/configuration.h"
+#include "ignite/odbc/type_traits.h"
+#include "ignite/odbc/environment.h"
+#include "ignite/odbc/connection.h"
+#include "ignite/odbc/statement.h"
+
+#ifdef ODBC_DEBUG
+
+FILE* log_file = NULL;
+
+void logInit(const char* path)
+{
+    if (!log_file)
+    {
+        log_file = fopen(path, "w");
+    }
+}
+
+#endif //ODBC_DEBUG
+
+BOOL INSTAPI ConfigDSN(HWND     hwndParent,
+                       WORD     req,
+                       LPCSTR   driver,
+                       LPCSTR   attributes)
+{
+    LOG_MSG("ConfigDSN called\n");
+
+    ignite::odbc::config::Configuration config;
+
+    config.FillFromConfigAttributes(attributes);
+
+    if (!SQLValidDSN(config.GetDsn().c_str()))
+        return SQL_FALSE;
+
+    LOG_MSG("Driver: %s\n", driver);
+    LOG_MSG("Attributes: %s\n", attributes);
+
+    LOG_MSG("DSN: %s\n", config.GetDsn().c_str());
+
+    switch (req)
+    {
+        case ODBC_ADD_DSN:
+        {
+            LOG_MSG("ODBC_ADD_DSN\n");
+
+            return SQLWriteDSNToIni(config.GetDsn().c_str(), driver);
+        }
+
+        case ODBC_CONFIG_DSN:
+        {
+            LOG_MSG("ODBC_CONFIG_DSN\n");
+            break;
+        }
+
+        case ODBC_REMOVE_DSN:
+        {
+            LOG_MSG("ODBC_REMOVE_DSN\n");
+
+            return SQLRemoveDSNFromIni(config.GetDsn().c_str());
+        }
+
+        default:
+        {
+            return SQL_FALSE;
+        }
+    }
+
+    return SQL_TRUE;
+}
+
+SQLRETURN SQL_API SQLGetInfo(SQLHDBC        conn,
+                             SQLUSMALLINT   infoType,
+                             SQLPOINTER     infoValue,
+                             SQLSMALLINT    infoValueMax,
+                             SQLSMALLINT*   length)
+{
+    using ignite::odbc::Connection;
+    using ignite::odbc::config::ConnectionInfo;
+
+    LOG_MSG("SQLGetInfo called: %d (%s)\n", infoType, ConnectionInfo::InfoTypeToString(infoType));
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    connection->GetInfo(infoType, infoValue, infoValueMax, length);
+
+    return connection->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result)
+{
+    //LOG_MSG("SQLAllocHandle called\n");
+    switch (type)
+    {
+        case SQL_HANDLE_ENV:
+            return SQLAllocEnv(result);
+
+        case SQL_HANDLE_DBC:
+            return SQLAllocConnect(parent, result);
+
+        case SQL_HANDLE_STMT:
+            return SQLAllocStmt(parent, result);
+
+        case SQL_HANDLE_DESC:
+        default:
+            break;
+    }
+
+    *result = 0;
+    return SQL_ERROR;
+}
+
+SQLRETURN SQL_API SQLAllocEnv(SQLHENV* env)
+{
+    using ignite::odbc::Environment;
+
+    LOG_MSG("SQLAllocEnv called\n");
+
+    *env = reinterpret_cast<SQLHENV>(new Environment());
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLAllocConnect(SQLHENV env, SQLHDBC* conn)
+{
+    using ignite::odbc::Environment;
+    using ignite::odbc::Connection;
+
+    LOG_MSG("SQLAllocConnect called\n");
+
+    *conn = SQL_NULL_HDBC;
+
+    Environment *environment = reinterpret_cast<Environment*>(env);
+
+    if (!environment)
+        return SQL_INVALID_HANDLE;
+
+    Connection *connection = environment->CreateConnection();
+
+    if (!connection)
+        return environment->GetDiagnosticRecords().GetReturnCode();
+
+    *conn = reinterpret_cast<SQLHDBC>(connection);
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLAllocStmt(SQLHDBC conn, SQLHSTMT* stmt)
+{
+    using ignite::odbc::Connection;
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLAllocStmt called\n");
+
+    *stmt = SQL_NULL_HDBC;
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    Statement *statement = connection->CreateStatement();
+
+    *stmt = reinterpret_cast<SQLHSTMT>(statement);
+
+    return connection->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle)
+{
+    switch (type)
+    {
+        case SQL_HANDLE_ENV:
+            return SQLFreeEnv(handle);
+
+        case SQL_HANDLE_DBC:
+            return SQLFreeConnect(handle);
+
+        case SQL_HANDLE_STMT:
+            return SQLFreeStmt(handle, SQL_DROP);
+
+        case SQL_HANDLE_DESC:
+        default:
+            break;
+    }
+
+    return SQL_ERROR;
+}
+
+SQLRETURN SQL_API SQLFreeEnv(SQLHENV env)
+{
+    using ignite::odbc::Environment;
+
+    LOG_MSG("SQLFreeEnv called\n");
+
+    Environment *environment = reinterpret_cast<Environment*>(env);
+
+    if (!environment)
+        return SQL_INVALID_HANDLE;
+
+    delete environment;
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLFreeConnect(SQLHDBC conn)
+{
+    using ignite::odbc::Connection;
+
+    LOG_MSG("SQLFreeConnect called\n");
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    delete connection;
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLFreeStmt called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    switch (option)
+    {
+        case SQL_DROP:
+        {
+            delete statement;
+
+            break;
+        }
+
+        case SQL_CLOSE:
+        {
+            return SQLCloseCursor(stmt);
+        }
+
+        case SQL_UNBIND:
+        {
+            statement->UnbindAllColumns();
+
+            break;
+        }
+
+        case SQL_RESET_PARAMS:
+        {
+            statement->UnbindAllParameters();
+
+            break;
+        }
+
+        default:
+            return SQL_ERROR;
+    }
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT stmt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLCloseCursor called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    statement->Close();
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLDriverConnect(SQLHDBC      conn,
+                                   SQLHWND      windowHandle,
+                                   SQLCHAR*     inConnectionString,
+                                   SQLSMALLINT  inConnectionStringLen,
+                                   SQLCHAR*     outConnectionString,
+                                   SQLSMALLINT  outConnectionStringBufferLen,
+                                   SQLSMALLINT* outConnectionStringLen,
+                                   SQLUSMALLINT driverCompletion)
+{
+    using ignite::odbc::Connection;
+    using ignite::odbc::diagnostic::DiagnosticRecordStorage;
+    using ignite::utility::SqlStringToString;
+    using ignite::utility::CopyStringToBuffer;
+
+    UNREFERENCED_PARAMETER(windowHandle);
+
+    LOG_MSG("SQLDriverConnect called\n");
+    LOG_MSG("Connection String: [%s]\n", inConnectionString);
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    std::string connectStr = SqlStringToString(inConnectionString, inConnectionStringLen);
+
+    ignite::odbc::config::Configuration config;
+
+    config.FillFromConnectString(connectStr);
+
+    connection->Establish(config.GetHost(), config.GetPort(), config.GetCache());
+
+    const DiagnosticRecordStorage& diag = connection->GetDiagnosticRecords();
+
+    if (!diag.IsSuccessful())
+        return diag.GetReturnCode();
+
+    std::string outConnectStr = config.ToConnectString();
+
+    size_t reslen = CopyStringToBuffer(outConnectStr,
+        reinterpret_cast<char*>(outConnectionString),
+        static_cast<size_t>(outConnectionStringBufferLen));
+
+    if (outConnectionStringLen)
+        *outConnectionStringLen = static_cast<SQLSMALLINT>(reslen);
+
+    LOG_MSG("%s\n", outConnectionString);
+
+    return diag.GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLConnect(SQLHDBC        conn,
+                             SQLCHAR*       serverName,
+                             SQLSMALLINT    serverNameLen,
+                             SQLCHAR*       userName,
+                             SQLSMALLINT    userNameLen,
+                             SQLCHAR*       auth,
+                             SQLSMALLINT    authLen)
+{
+    using ignite::odbc::Connection;
+    using ignite::odbc::diagnostic::DiagnosticRecordStorage;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLConnect called\n");
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    std::string server = SqlStringToString(serverName, serverNameLen);
+
+    connection->Establish(server);
+
+    return connection->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLDisconnect(SQLHDBC conn)
+{
+    using ignite::odbc::Connection;
+
+    LOG_MSG("SQLDisconnect called\n");
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    connection->Release();
+
+    return connection->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLPrepare(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLPrepare called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string sql = SqlStringToString(query, queryLen);
+
+    LOG_MSG("SQL: %s\n", sql.c_str());
+
+    statement->PrepareSqlQuery(sql);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLExecute(SQLHSTMT stmt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLExecute called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    statement->ExecuteSqlQuery();
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLExecDirect(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLExecDirect called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string sql = SqlStringToString(query, queryLen);
+
+    LOG_MSG("SQL: %s\n", sql.c_str());
+
+    statement->ExecuteSqlQuery(sql);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLBindCol(SQLHSTMT       stmt,
+                             SQLUSMALLINT   colNum,
+                             SQLSMALLINT    targetType,
+                             SQLPOINTER     targetValue,
+                             SQLLEN         bufferLength,
+                             SQLLEN*        strLengthOrIndicator)
+{
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::Statement;
+    using ignite::odbc::app::ApplicationDataBuffer;
+
+    LOG_MSG("SQLBindCol called: index=%d, type=%d\n", colNum, targetType);
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    IgniteSqlType driverType = ToDriverType(targetType);
+
+    if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED)
+        return SQL_ERROR;
+
+    if (bufferLength < 0)
+        return SQL_ERROR;
+
+    if (targetValue || strLengthOrIndicator)
+    {
+        ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator);
+
+        statement->BindColumn(colNum, dataBuffer);
+    }
+    else
+        statement->UnbindColumn(colNum);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLFetch(SQLHSTMT stmt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLFetch called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    statement->FetchRow();
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLFetchScroll(SQLHSTMT       stmt,
+                                 SQLSMALLINT    orientation,
+                                 SQLLEN         offset)
+{
+    LOG_MSG("SQLFetchScroll called\n");
+    LOG_MSG("Orientation: %d, Offset: %d\n", orientation, offset);
+
+    if (orientation != SQL_FETCH_NEXT)
+        return SQL_ERROR;
+
+    return SQLFetch(stmt);
+}
+
+SQLRETURN SQL_API SQLExtendedFetch(SQLHSTMT         stmt,
+                                   SQLUSMALLINT     orientation,
+                                   SQLLEN           offset,
+                                   SQLULEN*         rowCount,
+                                   SQLUSMALLINT*    rowStatusArray)
+{
+    LOG_MSG("SQLExtendedFetch called\n");
+
+    SQLRETURN res = SQLFetchScroll(stmt, orientation, offset);
+
+    if (res == SQL_SUCCESS || res == SQL_NO_DATA)
+    {
+        if (rowCount)
+            *rowCount = 1;
+
+        if (rowStatusArray)
+            rowStatusArray[0] = SQL_ROW_SUCCESS;
+    }
+
+    return res;
+}
+
+SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *columnNum)
+{
+    using ignite::odbc::Statement;
+    using ignite::odbc::meta::ColumnMetaVector;
+
+    LOG_MSG("SQLNumResultCols called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+    
+    int32_t res = statement->GetColumnNumber();
+
+    *columnNum = static_cast<SQLSMALLINT>(res);
+
+    LOG_MSG("columnNum: %d\n", *columnNum);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLTables(SQLHSTMT    stmt,
+                            SQLCHAR*    catalogName,
+                            SQLSMALLINT catalogNameLen,
+                            SQLCHAR*    schemaName,
+                            SQLSMALLINT schemaNameLen,
+                            SQLCHAR*    tableName,
+                            SQLSMALLINT tableNameLen,
+                            SQLCHAR*    tableType,
+                            SQLSMALLINT tableTypeLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLTables called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string catalog = SqlStringToString(catalogName, catalogNameLen);
+    std::string schema = SqlStringToString(schemaName, schemaNameLen);
+    std::string table = SqlStringToString(tableName, tableNameLen);
+    std::string tableTypeStr = SqlStringToString(tableType, tableTypeLen);
+
+    LOG_MSG("catalog: %s\n", catalog.c_str());
+    LOG_MSG("schema: %s\n", schema.c_str());
+    LOG_MSG("table: %s\n", table.c_str());
+    LOG_MSG("tableType: %s\n", tableTypeStr.c_str());
+
+    statement->ExecuteGetTablesMetaQuery(catalog, schema, table, tableTypeStr);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLColumns(SQLHSTMT       stmt,
+                             SQLCHAR*       catalogName,
+                             SQLSMALLINT    catalogNameLen,
+                             SQLCHAR*       schemaName,
+                             SQLSMALLINT    schemaNameLen,
+                             SQLCHAR*       tableName,
+                             SQLSMALLINT    tableNameLen,
+                             SQLCHAR*       columnName,
+                             SQLSMALLINT    columnNameLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLColumns called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string catalog = SqlStringToString(catalogName, catalogNameLen);
+    std::string schema = SqlStringToString(schemaName, schemaNameLen);
+    std::string table = SqlStringToString(tableName, tableNameLen);
+    std::string column = SqlStringToString(columnName, columnNameLen);
+
+    LOG_MSG("catalog: %s\n", catalog.c_str());
+    LOG_MSG("schema: %s\n", schema.c_str());
+    LOG_MSG("table: %s\n", table.c_str());
+    LOG_MSG("column: %s\n", column.c_str());
+
+    statement->ExecuteGetColumnsMetaQuery(schema, table, column);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLMoreResults(SQLHSTMT stmt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLMoreResults called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    //TODO: reset diagnostic here.
+    return statement->DataAvailable() ? SQL_SUCCESS : SQL_NO_DATA;
+}
+
+SQLRETURN SQL_API SQLBindParameter(SQLHSTMT     stmt,
+                                   SQLUSMALLINT paramIdx,
+                                   SQLSMALLINT  ioType,
+                                   SQLSMALLINT  bufferType,
+                                   SQLSMALLINT  paramSqlType,
+                                   SQLULEN      columnSize,
+                                   SQLSMALLINT  decDigits,
+                                   SQLPOINTER   buffer,
+                                   SQLLEN       bufferLen,
+                                   SQLLEN*      resLen)
+{
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::Statement;
+    using ignite::odbc::app::ApplicationDataBuffer;
+    using ignite::odbc::app::Parameter;
+    using ignite::odbc::type_traits::IsSqlTypeSupported;
+
+    LOG_MSG("SQLBindParameter called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    if (ioType != SQL_PARAM_INPUT)
+        return SQL_ERROR;
+
+    if (*resLen == SQL_DATA_AT_EXEC || *resLen <= SQL_LEN_DATA_AT_EXEC_OFFSET)
+        return SQL_ERROR;
+
+    if (!IsSqlTypeSupported(paramSqlType))
+        return SQL_ERROR;
+
+    IgniteSqlType driverType = ToDriverType(bufferType);
+
+    if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED)
+        return SQL_ERROR;
+
+    if (buffer)
+    {
+        ApplicationDataBuffer dataBuffer(driverType, buffer, bufferLen, resLen);
+
+        Parameter param(dataBuffer, paramSqlType, columnSize, decDigits);
+
+        statement->BindParameter(paramIdx, param);
+    }
+    else
+        statement->UnbindParameter(paramIdx);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLNativeSql(SQLHDBC      conn,
+                               SQLCHAR*     inQuery,
+                               SQLINTEGER   inQueryLen,
+                               SQLCHAR*     outQueryBuffer,
+                               SQLINTEGER   outQueryBufferLen,
+                               SQLINTEGER*  outQueryLen)
+{
+    using namespace ignite::utility;
+
+    LOG_MSG("SQLNativeSql called\n");
+
+    std::string in = SqlStringToString(inQuery, inQueryLen);
+
+    CopyStringToBuffer(in, reinterpret_cast<char*>(outQueryBuffer),
+        static_cast<size_t>(outQueryBufferLen));
+
+    *outQueryLen = std::min(outQueryBufferLen, static_cast<SQLINTEGER>(in.size()));
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLColAttribute(SQLHSTMT        stmt,
+                                  SQLUSMALLINT    columnNum,
+                                  SQLUSMALLINT    fieldId,
+                                  SQLPOINTER      strAttr,
+                                  SQLSMALLINT     bufferLen,
+                                  SQLSMALLINT*    strAttrLen,
+                                  SQLLEN*         numericAttr)
+{
+    using ignite::odbc::Statement;
+    using ignite::odbc::meta::ColumnMetaVector;
+    using ignite::odbc::meta::ColumnMeta;
+
+    LOG_MSG("SQLColAttribute called: %d (%s)\n", fieldId, ColumnMeta::AttrIdToString(fieldId));
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    // This is a special case
+    if (fieldId == SQL_DESC_COUNT)
+    {
+        SQLSMALLINT val = 0;
+
+        SQLRETURN res = SQLNumResultCols(stmt, &val);
+
+        if (res == SQL_SUCCESS)
+            *numericAttr = val;
+
+        return res;
+    }
+
+    statement->GetColumnAttribute(columnNum, fieldId, reinterpret_cast<char*>(strAttr),
+        bufferLen, strAttrLen, numericAttr);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLDescribeCol(SQLHSTMT       stmt,
+                                 SQLUSMALLINT   columnNum, 
+                                 SQLCHAR*       columnNameBuf,
+                                 SQLSMALLINT    columnNameBufLen,
+                                 SQLSMALLINT*   columnNameLen,
+                                 SQLSMALLINT*   dataType, 
+                                 SQLULEN*       columnSize,
+                                 SQLSMALLINT*   decimalDigits, 
+                                 SQLSMALLINT*   nullable)
+{
+    using ignite::odbc::Statement;
+    using ignite::odbc::SqlLen;
+
+    LOG_MSG("SQLDescribeCol called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    statement->GetColumnAttribute(columnNum, SQL_DESC_NAME,
+        reinterpret_cast<char*>(columnNameBuf), columnNameBufLen, columnNameLen, 0);
+
+    SqlLen dataTypeRes;
+    SqlLen columnSizeRes;
+    SqlLen decimalDigitsRes;
+    SqlLen nullableRes;
+
+    statement->GetColumnAttribute(columnNum, SQL_DESC_TYPE, 0, 0, 0, &dataTypeRes);
+    statement->GetColumnAttribute(columnNum, SQL_DESC_PRECISION, 0, 0, 0, &columnSizeRes);
+    statement->GetColumnAttribute(columnNum, SQL_DESC_SCALE, 0, 0, 0, &decimalDigitsRes);
+    statement->GetColumnAttribute(columnNum, SQL_DESC_NULLABLE, 0, 0, 0, &nullableRes);
+
+    LOG_MSG("columnNum: %lld\n", columnNum);
+    LOG_MSG("dataTypeRes: %lld\n", dataTypeRes);
+    LOG_MSG("columnSizeRes: %lld\n", columnSizeRes);
+    LOG_MSG("decimalDigitsRes: %lld\n", decimalDigitsRes);
+    LOG_MSG("nullableRes: %lld\n", nullableRes);
+    LOG_MSG("columnNameBuf: %s\n", columnNameBuf);
+    LOG_MSG("columnNameLen: %d\n", *columnNameLen);
+
+    *dataType = static_cast<SQLSMALLINT>(dataTypeRes);
+    *columnSize = static_cast<SQLULEN>(columnSizeRes);
+    *decimalDigits = static_cast<SQLSMALLINT>(decimalDigitsRes);
+    *nullable = static_cast<SQLSMALLINT>(nullableRes);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+
+SQLRETURN SQL_API SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCnt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLRowCount called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    int64_t res = statement->AffectedRows();
+
+    *rowCnt = static_cast<SQLLEN>(res);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLForeignKeys(SQLHSTMT       stmt,
+                                 SQLCHAR*       primaryCatalogName,
+                                 SQLSMALLINT    primaryCatalogNameLen,
+                                 SQLCHAR*       primarySchemaName,
+                                 SQLSMALLINT    primarySchemaNameLen,
+                                 SQLCHAR*       primaryTableName,
+                                 SQLSMALLINT    primaryTableNameLen,
+                                 SQLCHAR*       foreignCatalogName,
+                                 SQLSMALLINT    foreignCatalogNameLen,
+                                 SQLCHAR*       foreignSchemaName,
+                                 SQLSMALLINT    foreignSchemaNameLen,
+                                 SQLCHAR*       foreignTableName,
+                                 SQLSMALLINT    foreignTableNameLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLForeignKeys called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string primaryCatalog = SqlStringToString(primaryCatalogName, primaryCatalogNameLen);
+    std::string primarySchema = SqlStringToString(primarySchemaName, primarySchemaNameLen);
+    std::string primaryTable = SqlStringToString(primaryTableName, primaryTableNameLen);
+    std::string foreignCatalog = SqlStringToString(foreignCatalogName, foreignCatalogNameLen);
+    std::string foreignSchema = SqlStringToString(foreignSchemaName, foreignSchemaNameLen);
+    std::string foreignTable = SqlStringToString(foreignTableName, foreignTableNameLen);
+
+    LOG_MSG("primaryCatalog: %s\n", primaryCatalog.c_str());
+    LOG_MSG("primarySchema: %s\n", primarySchema.c_str());
+    LOG_MSG("primaryTable: %s\n", primaryTable.c_str());
+    LOG_MSG("foreignCatalog: %s\n", foreignCatalog.c_str());
+    LOG_MSG("foreignSchema: %s\n", foreignSchema.c_str());
+    LOG_MSG("foreignTable: %s\n", foreignTable.c_str());
+
+    statement->ExecuteGetForeignKeysQuery(primaryCatalog, primarySchema,
+        primaryTable, foreignCatalog, foreignSchema, foreignTable);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLGetStmtAttr(SQLHSTMT       stmt,
+                                 SQLINTEGER     attr,
+                                 SQLPOINTER     valueBuf,
+                                 SQLINTEGER     valueBufLen,
+                                 SQLINTEGER*    valueResLen)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLGetStmtAttr called");
+
+#ifdef ODBC_DEBUG
+    using ignite::odbc::type_traits::StatementAttrIdToString;
+
+    LOG_MSG("Attr: %s (%d)\n", StatementAttrIdToString(attr), attr);
+#endif //ODBC_DEBUG
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    //TODO: move this logic into Statement.
+    switch (attr)
+    {
+        case SQL_ATTR_APP_ROW_DESC:
+        case SQL_ATTR_APP_PARAM_DESC:
+        case SQL_ATTR_IMP_ROW_DESC:
+        case SQL_ATTR_IMP_PARAM_DESC:
+        {
+            SQLPOINTER *val = reinterpret_cast<SQLPOINTER*>(valueBuf);
+
+            *val = static_cast<SQLPOINTER>(stmt);
+
+            break;
+        }
+
+        case SQL_ATTR_ROW_ARRAY_SIZE:
+        {
+            SQLINTEGER *val = reinterpret_cast<SQLINTEGER*>(valueBuf);
+
+            *val = static_cast<SQLINTEGER>(1);
+
+            break;
+        }
+
+        case SQL_ATTR_ROWS_FETCHED_PTR:
+        {
+            SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf);
+
+            *val = reinterpret_cast<SQLULEN*>(statement->GetRowsFetchedPtr());
+
+            break;
+        }
+
+        case SQL_ATTR_ROW_STATUS_PTR:
+        {
+            SQLUSMALLINT** val = reinterpret_cast<SQLUSMALLINT**>(valueBuf);
+
+            *val = reinterpret_cast<SQLUSMALLINT*>(statement->GetRowStatusesPtr());
+
+            break;
+        }
+
+        case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
+        {
+            SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf);
+
+            *val = reinterpret_cast<SQLULEN*>(statement->GetParamBindOffsetPtr());
+
+            break;
+        }
+
+        case SQL_ATTR_ROW_BIND_OFFSET_PTR:
+        {
+            SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf);
+
+            *val = reinterpret_cast<SQLULEN*>(statement->GetColumnBindOffsetPtr());
+
+            break;
+        }
+
+        default:
+            return SQL_ERROR;
+    }
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetStmtAttr(SQLHSTMT    stmt,
+                                 SQLINTEGER  attr,
+                                 SQLPOINTER  value,
+                                 SQLINTEGER  valueLen)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLSetStmtAttr called");
+
+#ifdef ODBC_DEBUG
+    using ignite::odbc::type_traits::StatementAttrIdToString;
+
+    LOG_MSG("Attr: %s (%d)\n", StatementAttrIdToString(attr), attr);
+#endif //ODBC_DEBUG
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    //TODO: move this logic into Statement.
+    switch (attr)
+    {
+        case SQL_ATTR_ROW_ARRAY_SIZE:
+        {
+            SQLULEN val = reinterpret_cast<SQLULEN>(value);
+
+            LOG_MSG("Value: %d\n", val);
+
+            if (val != 1)
+                return SQL_ERROR;
+
+            break;
+        }
+
+        case SQL_ATTR_ROWS_FETCHED_PTR:
+        {
+            statement->SetRowsFetchedPtr(reinterpret_cast<size_t*>(value));
+
+            break;
+        }
+
+        case SQL_ATTR_ROW_STATUS_PTR:
+        {
+            statement->SetRowStatusesPtr(reinterpret_cast<uint16_t*>(value));
+
+            break;
+        }
+
+        case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
+        {
+            statement->SetParamBindOffsetPtr(reinterpret_cast<size_t*>(value));
+
+            break;
+        }
+
+        case SQL_ATTR_ROW_BIND_OFFSET_PTR:
+        {
+            statement->SetColumnBindOffsetPtr(reinterpret_cast<size_t*>(value));
+
+            break;
+        }
+
+        default:
+            return SQL_ERROR;
+    }
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLPrimaryKeys(SQLHSTMT       stmt,
+                                 SQLCHAR*       catalogName,
+                                 SQLSMALLINT    catalogNameLen,
+                                 SQLCHAR*       schemaName,
+                                 SQLSMALLINT    schemaNameLen,
+                                 SQLCHAR*       tableName,
+                                 SQLSMALLINT    tableNameLen)
+{
+    using ignite::odbc::Statement;
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLPrimaryKeys called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string catalog = SqlStringToString(catalogName, catalogNameLen);
+    std::string schema = SqlStringToString(schemaName, schemaNameLen);
+    std::string table = SqlStringToString(tableName, tableNameLen);
+
+    LOG_MSG("catalog: %s\n", catalog.c_str());
+    LOG_MSG("schema: %s\n", schema.c_str());
+    LOG_MSG("table: %s\n", table.c_str());
+
+    statement->ExecuteGetPrimaryKeysQuery(catalog, schema, table);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLNumParams(SQLHSTMT stmt, SQLSMALLINT* paramCnt)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLNumParams called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    *paramCnt = static_cast<SQLSMALLINT>(statement->GetParametersNumber());
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT   handleType,
+                                  SQLHANDLE     handle,
+                                  SQLSMALLINT   recNum,
+                                  SQLSMALLINT   diagId,
+                                  SQLPOINTER    buffer,
+                                  SQLSMALLINT   bufferLen,
+                                  SQLSMALLINT*  resLen)
+{
+    using namespace ignite::odbc;
+    using namespace ignite::odbc::diagnostic;
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::app::ApplicationDataBuffer;
+
+    LOG_MSG("SQLGetDiagField called: %d\n", recNum);
+
+    SqlLen outResLen;
+    ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_DEFAULT, buffer, bufferLen, &outResLen);
+
+    SqlResult result;
+
+    DiagnosticField field = DiagnosticFieldToInternal(diagId);
+
+    switch (handleType)
+    {
+        case SQL_HANDLE_ENV:
+        case SQL_HANDLE_DBC:
+        case SQL_HANDLE_STMT:
+        {
+            Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle);
+
+            result = diag->GetDiagnosticRecords().GetField(recNum, field, outBuffer);
+
+            break;
+        }
+
+        default:
+        {
+            result = SQL_RESULT_NO_DATA;
+            break;
+        }
+    }
+
+    if (result == SQL_RESULT_SUCCESS)
+        *resLen = static_cast<SQLSMALLINT>(outResLen);
+
+    return SqlResultToReturnCode(result);
+}
+
+SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT     handleType,
+                                SQLHANDLE       handle,
+                                SQLSMALLINT     recNum,
+                                SQLCHAR*        sqlState,
+                                SQLINTEGER*     nativeError,
+                                SQLCHAR*        msgBuffer,
+                                SQLSMALLINT     msgBufferLen,
+                                SQLSMALLINT*    msgLen)
+{
+    using namespace ignite::utility;
+    using namespace ignite::odbc;
+    using namespace ignite::odbc::diagnostic;
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::app::ApplicationDataBuffer;
+
+    LOG_MSG("SQLGetDiagRec called\n");
+
+    const DiagnosticRecordStorage* records = 0;
+    
+    switch (handleType)
+    {
+        case SQL_HANDLE_ENV:
+        case SQL_HANDLE_DBC:
+        case SQL_HANDLE_STMT:
+        {
+            Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle);
+
+            records = &diag->GetDiagnosticRecords();
+
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    if (!records || recNum < 1 || recNum > records->GetStatusRecordsNumber())
+        return SQL_NO_DATA;
+
+    const DiagnosticRecord& record = records->GetStatusRecord(recNum);
+
+    if (sqlState)
+        CopyStringToBuffer(record.GetSqlState(), reinterpret_cast<char*>(sqlState), 6);
+
+    if (nativeError)
+        *nativeError = 0;
+
+    SqlLen outResLen;
+    ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_CHAR, msgBuffer, msgBufferLen, &outResLen);
+
+    outBuffer.PutString(record.GetMessage());
+
+    *msgLen = static_cast<SQLSMALLINT>(outResLen);
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetTypeInfo(SQLHSTMT       stmt,
+                                 SQLSMALLINT    type)
+{
+    using ignite::odbc::Statement;
+
+    LOG_MSG("SQLGetTypeInfo called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    statement->ExecuteGetTypeInfoQuery(static_cast<int16_t>(type));
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLEndTran(SQLSMALLINT    handleType,
+                             SQLHANDLE      handle,
+                             SQLSMALLINT    completionType)
+{
+    using namespace ignite::odbc;
+
+    LOG_MSG("SQLEndTran called\n");
+
+    SQLRETURN result;
+
+    switch (handleType)
+    {
+        case SQL_HANDLE_ENV:
+        {
+            Environment *env = reinterpret_cast<Environment*>(handle);
+
+            if (!env)
+                return SQL_INVALID_HANDLE;
+
+            if (completionType == SQL_COMMIT)
+                env->TransactionCommit();
+            else
+                env->TransactionRollback();
+
+            result = env->GetDiagnosticRecords().GetReturnCode();
+
+            break;
+        }
+
+        case SQL_HANDLE_DBC:
+        {
+            Connection *conn = reinterpret_cast<Connection*>(handle);
+
+            if (!conn)
+                return SQL_INVALID_HANDLE;
+
+            if (completionType == SQL_COMMIT)
+                conn->TransactionCommit();
+            else
+                conn->TransactionRollback();
+
+            result = conn->GetDiagnosticRecords().GetReturnCode();
+
+            break;
+        }
+
+        default:
+        {
+            result = SQL_INVALID_HANDLE;
+
+            break;
+        }
+    }
+
+    return result;
+}
+
+SQLRETURN SQL_API SQLGetData(SQLHSTMT       stmt,
+                             SQLUSMALLINT   colNum,
+                             SQLSMALLINT    targetType,
+                             SQLPOINTER     targetValue,
+                             SQLLEN         bufferLength,
+                             SQLLEN*        strLengthOrIndicator)
+{
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::Statement;
+    using ignite::odbc::app::ApplicationDataBuffer;
+
+    LOG_MSG("SQLGetData called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    IgniteSqlType driverType = ToDriverType(targetType);
+
+    ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator);
+
+    statement->GetColumnData(colNum, dataBuffer);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLSetEnvAttr(SQLHENV     env,
+                                SQLINTEGER  attr,
+                                SQLPOINTER  value,
+                                SQLINTEGER  valueLen)
+{
+    using ignite::odbc::Environment;
+
+    LOG_MSG("SQLSetEnvAttr called\n");
+
+    Environment *environment = reinterpret_cast<Environment*>(env);
+
+    if (!environment)
+        return SQL_INVALID_HANDLE;
+
+    environment->SetAttribute(attr, value, valueLen);
+
+    return environment->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV     env,
+                                SQLINTEGER  attr,
+                                SQLPOINTER  valueBuf,
+                                SQLINTEGER  valueBufLen,
+                                SQLINTEGER* valueResLen)
+{
+    using namespace ignite::odbc;
+    using namespace ignite::odbc::type_traits;
+
+    using ignite::odbc::app::ApplicationDataBuffer;
+
+    LOG_MSG("SQLGetEnvAttr called\n");
+
+    Environment *environment = reinterpret_cast<Environment*>(env);
+
+    if (!environment)
+        return SQL_INVALID_HANDLE;
+
+    SqlLen outResLen;
+    ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_DEFAULT, valueBuf,
+        static_cast<int32_t>(valueBufLen), &outResLen);
+
+    environment->GetAttribute(attr, outBuffer);
+
+    *valueResLen = static_cast<SQLSMALLINT>(outResLen);
+
+    return environment->GetDiagnosticRecords().GetReturnCode();
+}
+
+SQLRETURN SQL_API SQLSpecialColumns(SQLHSTMT    stmt,
+                                    SQLSMALLINT idType,
+                                    SQLCHAR*    catalogName,
+                                    SQLSMALLINT catalogNameLen,
+                                    SQLCHAR*    schemaName,
+                                    SQLSMALLINT schemaNameLen,
+                                    SQLCHAR*    tableName,
+                                    SQLSMALLINT tableNameLen,
+                                    SQLSMALLINT scope,
+                                    SQLSMALLINT nullable)
+{
+    using namespace ignite::odbc;
+
+    using ignite::utility::SqlStringToString;
+
+    LOG_MSG("SQLSpecialColumns called\n");
+
+    Statement *statement = reinterpret_cast<Statement*>(stmt);
+
+    if (!statement)
+        return SQL_INVALID_HANDLE;
+
+    std::string catalog = SqlStringToString(catalogName, catalogNameLen);
+    std::string schema = SqlStringToString(schemaName, schemaNameLen);
+    std::string table = SqlStringToString(tableName, tableNameLen);
+
+    LOG_MSG("catalog: %s\n", catalog.c_str());
+    LOG_MSG("schema: %s\n", schema.c_str());
+    LOG_MSG("table: %s\n", table.c_str());
+
+    statement->ExecuteSpecialColumnsQuery(idType, catalog, schema, table, scope, nullable);
+
+    return statement->GetDiagnosticRecords().GetReturnCode();
+}
+
+//
+// ==== Not implemented ====
+//
+
+SQLRETURN SQL_API SQLCancel(SQLHSTMT stmt)
+{
+    LOG_MSG("SQLCancel called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLColAttributes(SQLHSTMT     stmt,
+                                   SQLUSMALLINT colNum,
+                                   SQLUSMALLINT fieldId,
+                                   SQLPOINTER   strAttrBuf,
+                                   SQLSMALLINT  strAttrBufLen,
+                                   SQLSMALLINT* strAttrResLen,
+                                   SQLLEN*      numAttrBuf)
+{
+    LOG_MSG("SQLColAttributes called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLError(SQLHENV      env,
+                           SQLHDBC      conn,
+                           SQLHSTMT     stmt,
+                           SQLCHAR*     state,
+                           SQLINTEGER*  error,
+                           SQLCHAR*     msgBuf,
+                           SQLSMALLINT  msgBufLen,
+                           SQLSMALLINT* msgResLen)
+{
+    LOG_MSG("SQLError called\n");
+    return(SQL_NO_DATA_FOUND);
+}
+
+SQLRETURN SQL_API SQLGetCursorName(SQLHSTMT     stmt,
+                                   SQLCHAR*     nameBuf,
+                                   SQLSMALLINT  nameBufLen,
+                                   SQLSMALLINT* nameResLen)
+{
+    LOG_MSG("SQLGetCursorName called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetCursorName(SQLHSTMT     stmt,
+                                   SQLCHAR*     name,
+                                   SQLSMALLINT  nameLen)
+{
+    LOG_MSG("SQLSetCursorName called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetConnectOption(SQLHDBC       conn,
+                                      SQLUSMALLINT  option,
+                                      SQLPOINTER    value)
+{
+    LOG_MSG("SQLGetConnectOption called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetFunctions(SQLHDBC       conn,
+                                  SQLUSMALLINT  funcId,
+                                  SQLUSMALLINT* supported)
+{
+    LOG_MSG("SQLGetFunctions called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetStmtOption(SQLHSTMT     stmt,
+                                   SQLUSMALLINT option,
+                                   SQLPOINTER   value)
+{
+    LOG_MSG("SQLGetStmtOption called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLParamData(SQLHSTMT    stmt,
+                               SQLPOINTER* value)
+{
+    LOG_MSG("SQLParamData called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLPutData(SQLHSTMT     stmt,
+                             SQLPOINTER   data,
+                             SQLLEN       strLengthOrIndicator)
+{
+    LOG_MSG("SQLPutData called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetConnectOption(SQLHDBC       conn,
+                                      SQLUSMALLINT  option,
+                                      SQLULEN       value)
+{
+    LOG_MSG("SQLSetConnectOption called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetStmtOption(SQLHSTMT     stmt,
+                                   SQLUSMALLINT option,
+                                   SQLULEN      value)
+{
+    LOG_MSG("SQLSetStmtOption called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLStatistics(SQLHSTMT        stmt,
+                                SQLCHAR*        catalogName,
+                                SQLSMALLINT     catalogNameLen,
+                                SQLCHAR*        schemaName,
+                                SQLSMALLINT     schemaNameLen,
+                                SQLCHAR*        tableName,
+                                SQLSMALLINT     tableNameLen,
+                                SQLUSMALLINT    unique,
+                                SQLUSMALLINT    reserved)
+{
+    LOG_MSG("SQLStatistics called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLBrowseConnect(SQLHDBC      conn,
+                                   SQLCHAR*     inConnectionStr,
+                                   SQLSMALLINT  inConnectionStrLen,
+                                   SQLCHAR*     outConnectionStrBuf,
+                                   SQLSMALLINT  outConnectionStrBufLen,
+                                   SQLSMALLINT* outConnectionStrResLen)
+{
+    LOG_MSG("SQLBrowseConnect called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLProcedureColumns(SQLHSTMT      stmt,
+                                      SQLCHAR *     catalogName,
+                                      SQLSMALLINT   catalogNameLen,
+                                      SQLCHAR *     schemaName,
+                                      SQLSMALLINT   schemaNameLen,
+                                      SQLCHAR *     procName,
+                                      SQLSMALLINT   procNameLen,
+                                      SQLCHAR *     columnName,
+                                      SQLSMALLINT   columnNameLen)
+{
+    LOG_MSG("SQLProcedureColumns called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetPos(SQLHSTMT        stmt,
+                            SQLSETPOSIROW   rowNum,
+                            SQLUSMALLINT    operation,
+                            SQLUSMALLINT    lockType)
+{
+    LOG_MSG("SQLSetPos called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetScrollOptions(SQLHSTMT      stmt,
+                                      SQLUSMALLINT  concurrency,
+                                      SQLLEN        crowKeyset,
+                                      SQLUSMALLINT  crowRowset)
+{
+    LOG_MSG("SQLSetScrollOptions called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetConnectAttr(SQLHDBC     conn,
+                                    SQLINTEGER  attr,
+                                    SQLPOINTER  valueBuf,
+                                    SQLINTEGER  valueBufLen,
+                                    SQLINTEGER* valueResLen)
+{
+    LOG_MSG("SQLGetConnectAttr called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC     conn,
+                                    SQLINTEGER  attr,
+                                    SQLPOINTER  value,
+                                    SQLINTEGER  valueLen)
+{
+    using ignite::odbc::Connection;
+
+    LOG_MSG("SQLSetConnectAttr called\n");
+
+    Connection *connection = reinterpret_cast<Connection*>(conn);
+
+    if (!connection)
+        return SQL_INVALID_HANDLE;
+
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLBulkOperations(SQLHSTMT       stmt,
+                                    SQLUSMALLINT   operation)
+{
+    LOG_MSG("SQLBulkOperations called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLTablePrivileges(SQLHSTMT      stmt,
+                                     SQLCHAR*      catalogName,
+                                     SQLSMALLINT   catalogNameLen,
+                                     SQLCHAR*      schemaName,
+                                     SQLSMALLINT   schemaNameLen,
+                                     SQLCHAR*      tableName,
+                                     SQLSMALLINT   tableNameLen)
+{
+    LOG_MSG("SQLTablePrivileges called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLCopyDesc(SQLHDESC src, SQLHDESC dst)
+{
+    LOG_MSG("SQLCopyDesc called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetDescField(SQLHDESC      descr,
+                                  SQLSMALLINT   recNum,
+                                  SQLSMALLINT   fieldId,
+                                  SQLPOINTER    buffer,
+                                  SQLINTEGER    bufferLen,
+                                  SQLINTEGER*   resLen)
+{
+    LOG_MSG("SQLGetDescField called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLGetDescRec(SQLHDESC        DescriptorHandle,
+                                SQLSMALLINT     RecNumber,
+                                SQLCHAR*        nameBuffer,
+                                SQLSMALLINT     nameBufferLen,
+                                SQLSMALLINT*    strLen,
+                                SQLSMALLINT*    type,
+                                SQLSMALLINT*    subType,
+                                SQLLEN*         len,
+                                SQLSMALLINT*    precision,
+                                SQLSMALLINT*    scale,
+                                SQLSMALLINT*    nullable)
+{
+    LOG_MSG("SQLGetDescRec called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetDescField(SQLHDESC      descr,
+                                  SQLSMALLINT   recNum,
+                                  SQLSMALLINT   fieldId,
+                                  SQLPOINTER    buffer,
+                                  SQLINTEGER    bufferLen)
+{
+    LOG_MSG("SQLSetDescField called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLSetDescRec(SQLHDESC      descr,
+                                SQLSMALLINT   recNum,
+                                SQLSMALLINT   type,
+                                SQLSMALLINT   subType,
+                                SQLLEN        len,
+                                SQLSMALLINT   precision,
+                                SQLSMALLINT   scale,
+                                SQLPOINTER    buffer,
+                                SQLLEN*       resLen,
+                                SQLLEN*       id)
+{
+    LOG_MSG("SQLSetDescRec called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLColumnPrivileges(SQLHSTMT      stmt,
+                                      SQLCHAR*      catalogName,
+                                      SQLSMALLINT   catalogNameLen,
+                                      SQLCHAR*      schemaName,
+                                      SQLSMALLINT   schemaNameLen,
+                                      SQLCHAR*      tableName,
+                                      SQLSMALLINT   tableNameLen,
+                                      SQLCHAR*      columnName,
+                                      SQLSMALLINT   columnNameLen)
+{
+    LOG_MSG("SQLColumnPrivileges called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLDescribeParam(SQLHSTMT     stmt,
+                                   SQLUSMALLINT paramNum,
+                                   SQLSMALLINT* dataType,
+                                   SQLULEN*     paramSize,
+                                   SQLSMALLINT* decimalDigits,
+                                   SQLSMALLINT* nullable)
+{
+    LOG_MSG("SQLDescribeParam called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLParamOptions(SQLHSTMT  stmt,
+                                  SQLULEN   paramSetSize,
+                                  SQLULEN*  paramsProcessed)
+{
+    LOG_MSG("SQLParamOptions called\n");
+    return SQL_SUCCESS;
+}
+
+SQLRETURN SQL_API SQLProcedures(SQLHSTMT        stmt,
+                                SQLCHAR*        catalogName,
+                                SQLSMALLINT     catalogNameLen,
+                                SQLCHAR*        schemaName,
+                                SQLSMALLINT     schemaNameLen,
+                                SQLCHAR*        tableName,
+                                SQLSMALLINT     tableNameLen)
+{
+    LOG_MSG("SQLProcedures called\n");
+    return SQL_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
new file mode 100644
index 0000000..69a08b1
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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/impl/binary/binary_common.h>
+
+#include "ignite/odbc/type_traits.h"
+#include "ignite/odbc/connection.h"
+#include "ignite/odbc/message.h"
+#include "ignite/odbc/query/column_metadata_query.h"
+
+namespace
+{
+    enum ResultColumn
+    {
+        /** Catalog name. NULL if not applicable to the data source. */
+        TABLE_CAT = 1,
+
+        /** Schema name. NULL if not applicable to the data source. */
+        TABLE_SCHEM,
+
+        /** Table name. */
+        TABLE_NAME,
+
+        /** Column name. */
+        COLUMN_NAME,
+
+        /** SQL data type. */
+        DATA_TYPE,
+
+        /** Data source�dependent data type name. */
+        TYPE_NAME,
+
+        /** Column size. */
+        COLUMN_SIZE,
+
+        /** The length in bytes of data transferred on fetch. */
+        BUFFER_LENGTH,
+
+        /** The total number of significant digits to the right of the decimal point. */
+        DECIMAL_DIGITS,
+
+        /** Precision. */
+        NUM_PREC_RADIX,
+
+        /** Nullability of the data in column. */
+        NULLABLE,
+
+        /** A description of the column. */
+        REMARKS
+    };
+}
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace query
+        {
+            ColumnMetadataQuery::ColumnMetadataQuery(diagnostic::Diagnosable& diag, 
+                Connection& connection, const std::string& schema,
+                const std::string& table, const std::string& column) :
+                Query(diag),
+                connection(connection),
+                schema(schema),
+                table(table),
+                column(column),
+                executed(false),
+                meta(),
+                columnsMeta()
+            {
+                using namespace ignite::impl::binary;
+                using namespace ignite::odbc::type_traits;
+
+                using meta::ColumnMeta;
+
+                columnsMeta.reserve(12);
+
+                const std::string sch("");
+                const std::string tbl("");
+
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_CAT",      SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM",    SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME",     SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME",    SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "DATA_TYPE",      SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TYPE_NAME",      SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_SIZE",    SqlTypeName::INTEGER,  IGNITE_TYPE_INT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "BUFFER_LENGTH",  SqlTypeName::INTEGER,  IGNITE_TYPE_INT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "DECIMAL_DIGITS", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "NUM_PREC_RADIX", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "NULLABLE",       SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "REMARKS",        SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+            }
+
+            ColumnMetadataQuery::~ColumnMetadataQuery()
+            {
+                // No-op.
+            }
+
+            SqlResult ColumnMetadataQuery::Execute()
+            {
+                if (executed)
+                    Close();
+
+                SqlResult result = MakeRequestGetColumnsMeta();
+
+                if (result == SQL_RESULT_SUCCESS)
+                {
+                    executed = true;
+
+                    cursor = meta.begin();
+                }
+
+                return result;
+            }
+
+            const meta::ColumnMetaVector& ColumnMetadataQuery::GetMeta() const
+            {
+                return columnsMeta;
+            }
+
+            SqlResult ColumnMetadataQuery::FetchNextRow(app::ColumnBindingMap & columnBindings)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (cursor == meta.end())
+                    return SQL_RESULT_NO_DATA;
+
+                app::ColumnBindingMap::iterator it;
+
+                for (it = columnBindings.begin(); it != columnBindings.end(); ++it)
+                    GetColumn(it->first, it->second);
+
+                ++cursor;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult ColumnMetadataQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer & buffer)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (cursor == meta.end())
+                    return SQL_RESULT_NO_DATA;
+
+                const meta::ColumnMeta& currentColumn = *cursor;
+                uint8_t columnType = currentColumn.GetDataType();
+
+                switch (columnIdx)
+                {
+                    case TABLE_CAT:
+                    {
+                        buffer.PutNull();
+                        break;
+                    }
+
+                    case TABLE_SCHEM:
+                    {
+                        buffer.PutString(currentColumn.GetSchemaName());
+                        break;
+                    }
+
+                    case TABLE_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetTableName());
+                        break;
+                    }
+
+                    case COLUMN_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetColumnName());
+                        break;
+                    }
+
+                    case DATA_TYPE:
+                    {
+                        buffer.PutInt16(type_traits::BinaryToSqlType(columnType));
+                        break;
+                    }
+
+                    case TYPE_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetColumnTypeName());
+                        break;
+                    }
+
+                    case COLUMN_SIZE:
+                    {
+                        buffer.PutInt16(type_traits::BinaryTypeColumnSize(columnType));
+                        break;
+                    }
+
+                    case BUFFER_LENGTH:
+                    {
+                        buffer.PutInt16(type_traits::BinaryTypeTransferLength(columnType));
+                        break;
+                    }
+
+                    case DECIMAL_DIGITS:
+                    {
+                        int32_t decDigits = type_traits::BinaryTypeDecimalDigits(columnType);
+                        if (decDigits < 0)
+                            buffer.PutNull();
+                        else
+                            buffer.PutInt16(static_cast<int16_t>(decDigits));
+                        break;
+                    }
+
+                    case NUM_PREC_RADIX:
+                    {
+                        buffer.PutInt16(type_traits::BinaryTypeNumPrecRadix(columnType));
+                        break;
+                    }
+
+                    case NULLABLE:
+                    {
+                        buffer.PutInt16(type_traits::BinaryTypeNullability(columnType));
+                        break;
+                    }
+
+                    case REMARKS:
+                    {
+                        buffer.PutNull();
+                        break;
+                    }
+
+                    default:
+                        break;
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult ColumnMetadataQuery::Close()
+            {
+                meta.clear();
+
+                executed = false;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            bool ColumnMetadataQuery::DataAvailable() const
+            {
+                return cursor != meta.end();
+            }
+
+            int64_t ColumnMetadataQuery::AffectedRows() const
+            {
+                return 0;
+            }
+
+            SqlResult ColumnMetadataQuery::MakeRequestGetColumnsMeta()
+            {
+                QueryGetColumnsMetaRequest req(schema, table, column);
+                QueryGetColumnsMetaResponse rsp;
+
+                bool success = connection.SyncMessage(req, rsp);
+
+                if (!success)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS)
+                {
+                    LOG_MSG("Error: %s\n", rsp.GetError().c_str());
+
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError());
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                meta = rsp.GetMeta();
+
+                for (size_t i = 0; i < meta.size(); ++i)
+                {
+                    LOG_MSG("[%d] SchemaName:     %s\n", i, meta[i].GetSchemaName().c_str());
+                    LOG_MSG("[%d] TableName:      %s\n", i, meta[i].GetTableName().c_str());
+                    LOG_MSG("[%d] ColumnName:     %s\n", i, meta[i].GetColumnName().c_str());
+                    LOG_MSG("[%d] ColumnTypeName: %s\n", i, meta[i].GetColumnTypeName().c_str());
+                    LOG_MSG("[%d] ColumnType:     %d\n", i, meta[i].GetDataType());
+                    LOG_MSG("\n");
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/data_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/data_query.cpp b/modules/platforms/cpp/odbc/src/query/data_query.cpp
new file mode 100644
index 0000000..4e9239b
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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/connection.h"
+#include "ignite/odbc/message.h"
+#include "ignite/odbc/query/data_query.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace query
+        {
+            DataQuery::DataQuery(diagnostic::Diagnosable& diag,
+                Connection& connection, const std::string& sql,
+                const app::ParameterBindingMap& params) :
+                Query(diag),
+                connection(connection),
+                sql(sql),
+                params(params)
+            {
+                // No-op.
+            }
+
+            DataQuery::~DataQuery()
+            {
+                Close();
+            }
+            
+            SqlResult DataQuery::Execute()
+            {
+                if (cursor.get())
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query cursor is in open state already.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                return MakeRequestExecute();
+            }
+
+            const meta::ColumnMetaVector & DataQuery::GetMeta() const
+            {
+                return resultMeta;
+            }
+
+            SqlResult DataQuery::FetchNextRow(app::ColumnBindingMap& columnBindings)
+            {
+                if (!cursor.get())
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (!cursor->HasNext())
+                    return SQL_RESULT_NO_DATA;
+
+                if (cursor->NeedDataUpdate())
+                {
+                    SqlResult result = MakeRequestFetch();
+
+                    if (result != SQL_RESULT_SUCCESS)
+                        return result;
+
+                    if (!cursor->HasNext())
+                        return SQL_RESULT_NO_DATA;
+                }
+                else
+                    cursor->Increment();
+
+                Row* row = cursor->GetRow();
+
+                if (!row)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Unknown error.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                for (int32_t i = 1; i < row->GetSize() + 1; ++i)
+                {
+                    app::ColumnBindingMap::iterator it = columnBindings.find(i);
+
+                    SqlResult result;
+
+                    if (it != columnBindings.end())
+                        result = row->ReadColumnToBuffer(i, it->second);
+
+                    if (result == SQL_RESULT_ERROR)
+                    {
+                        diag.AddStatusRecord(SQL_STATE_01S01_ERROR_IN_ROW, "Can not retrieve row column.", 0, i);
+
+                        return SQL_RESULT_ERROR;
+                    }
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult DataQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer)
+            {
+                if (!cursor.get())
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                Row* row = cursor->GetRow();
+
+                if (!row)
+                    return SQL_RESULT_NO_DATA;
+
+                SqlResult result = row->ReadColumnToBuffer(columnIdx, buffer);
+
+                if (result == SQL_RESULT_ERROR)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Unknown column type.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                return result;
+            }
+
+            SqlResult DataQuery::Close()
+            {
+                if (!cursor.get())
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query cursor is not in open state.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                SqlResult result = MakeRequestClose();
+
+                if (result == SQL_RESULT_SUCCESS)
+                    cursor.reset();
+
+                return result;
+            }
+
+            bool DataQuery::DataAvailable() const
+            {
+                return cursor.get() && cursor->HasNext();
+            }
+
+            int64_t DataQuery::AffectedRows() const
+            {
+                // We are only support SELECT statements so we should not
+                // return anything particullar.
+                return 0;
+            }
+
+            SqlResult DataQuery::MakeRequestExecute()
+            {
+                const std::string& cacheName = connection.GetCache();
+
+                QueryExecuteRequest req(cacheName, sql, params);
+                QueryExecuteResponse rsp;
+
+                bool success = connection.SyncMessage(req, rsp);
+
+                if (!success)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS)
+                {
+                    LOG_MSG("Error: %s\n", rsp.GetError().c_str());
+
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError());
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                cursor.reset(new Cursor(rsp.GetQueryId()));
+
+                resultMeta.assign(rsp.GetMeta().begin(), rsp.GetMeta().end());
+
+                LOG_MSG("Query id: %lld\n", cursor->GetQueryId());
+
+                for (size_t i = 0; i < rsp.GetMeta().size(); ++i)
+                {
+                    LOG_MSG("[%d] SchemaName:     %s\n", i, rsp.GetMeta()[i].GetSchemaName().c_str());
+                    LOG_MSG("[%d] TypeName:       %s\n", i, rsp.GetMeta()[i].GetTableName().c_str());
+                    LOG_MSG("[%d] ColumnName:     %s\n", i, rsp.GetMeta()[i].GetColumnName().c_str());
+                    LOG_MSG("[%d] ColumnTypeName: %s\n", i, rsp.GetMeta()[i].GetColumnTypeName().c_str());
+                    LOG_MSG("[%d] ColumnType:     %d\n", i, rsp.GetMeta()[i].GetDataType());
+                    LOG_MSG("\n");
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult DataQuery::MakeRequestClose()
+            {
+                QueryCloseRequest req(cursor->GetQueryId());
+                QueryCloseResponse rsp;
+
+                bool success = connection.SyncMessage(req, rsp);
+
+                if (!success)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                LOG_MSG("Query id: %lld\n", rsp.GetQueryId());
+
+                if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS)
+                {
+                    LOG_MSG("Error: %s\n", rsp.GetError().c_str());
+
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError());
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult DataQuery::MakeRequestFetch()
+            {
+                std::auto_ptr<ResultPage> resultPage(new ResultPage());
+
+                QueryFetchRequest req(cursor->GetQueryId(), ResultPage::DEFAULT_SIZE);
+                QueryFetchResponse rsp(*resultPage);
+
+                bool success = connection.SyncMessage(req, rsp);
+
+                LOG_MSG("Query id: %lld\n", rsp.GetQueryId());
+                LOG_MSG("Request status: %s\n", success ? "Success" : "Failure");
+
+                if (!success)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS)
+                {
+                    LOG_MSG("Error: %s\n", rsp.GetError().c_str());
+
+                    diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError());
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                cursor->UpdateData(resultPage);
+
+                return SQL_RESULT_SUCCESS;
+            }
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp b/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp
new file mode 100644
index 0000000..78e1464
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ignite/impl/binary/binary_common.h>
+
+#include "ignite/odbc/type_traits.h"
+#include "ignite/odbc/connection.h"
+#include "ignite/odbc/message.h"
+#include "ignite/odbc/query/foreign_keys_query.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace query
+        {
+            ForeignKeysQuery::ForeignKeysQuery(diagnostic::Diagnosable& diag, Connection& connection,
+                const std::string& primaryCatalog, const std::string& primarySchema,
+                const std::string& primaryTable, const std::string& foreignCatalog,
+                const std::string& foreignSchema, const std::string& foreignTable) :
+                Query(diag),
+                connection(connection),
+                primaryCatalog(primaryCatalog),
+                primarySchema(primarySchema),
+                primaryTable(primaryTable),
+                foreignCatalog(foreignCatalog),
+                foreignSchema(foreignSchema),
+                foreignTable(foreignTable),
+                executed(false),
+                columnsMeta()
+            {
+                using namespace ignite::impl::binary;
+                using namespace ignite::odbc::type_traits;
+
+                using meta::ColumnMeta;
+
+                columnsMeta.reserve(14);
+
+                const std::string sch("");
+                const std::string tbl("");
+
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_CAT",   SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_SCHEM", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_NAME",  SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PKCOLUMN_NAME", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_CAT",   SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_SCHEM", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_NAME",  SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "FKCOLUMN_NAME", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ",       SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "UPDATE_RULE",   SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "DELETE_RULE",   SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "FK_NAME",       SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME",       SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "DEFERRABILITY", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+            }
+
+            ForeignKeysQuery::~ForeignKeysQuery()
+            {
+                // No-op.
+            }
+
+            SqlResult ForeignKeysQuery::Execute()
+            {
+                executed = true;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            const meta::ColumnMetaVector & ForeignKeysQuery::GetMeta() const
+            {
+                return columnsMeta;
+            }
+
+            SqlResult ForeignKeysQuery::FetchNextRow(app::ColumnBindingMap & columnBindings)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                return SQL_RESULT_NO_DATA;
+            }
+
+            SqlResult ForeignKeysQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                return SQL_RESULT_NO_DATA;
+            }
+
+            SqlResult ForeignKeysQuery::Close()
+            {
+                executed = false;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            bool ForeignKeysQuery::DataAvailable() const
+            {
+                return false;
+            }
+            int64_t ForeignKeysQuery::AffectedRows() const
+            {
+                return 0;
+            }
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp b/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp
new file mode 100644
index 0000000..b616db3
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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/impl/binary/binary_common.h>
+
+#include "ignite/odbc/type_traits.h"
+#include "ignite/odbc/connection.h"
+#include "ignite/odbc/message.h"
+#include "ignite/odbc/query/primary_keys_query.h"
+
+namespace
+{
+    enum ResultColumn
+    {
+        /** Catalog name. NULL if not applicable to the data source. */
+        TABLE_CAT = 1,
+
+        /** Schema name. NULL if not applicable to the data source. */
+        TABLE_SCHEM,
+
+        /** Table name. */
+        TABLE_NAME,
+
+        /** Column name. */
+        COLUMN_NAME,
+
+        /** Column sequence number in key. */
+        KEY_SEQ,
+
+        /** Primary key name. */
+        PK_NAME
+    };
+}
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace query
+        {
+            PrimaryKeysQuery::PrimaryKeysQuery(diagnostic::Diagnosable& diag,
+                Connection& connection, const std::string& catalog,
+                const std::string& schema, const std::string& table) :
+                Query(diag),
+                connection(connection),
+                catalog(catalog),
+                schema(schema),
+                table(table),
+                executed(false),
+                columnsMeta()
+            {
+                using namespace ignite::impl::binary;
+                using namespace ignite::odbc::type_traits;
+
+                using meta::ColumnMeta;
+
+                columnsMeta.reserve(6);
+
+                const std::string sch("");
+                const std::string tbl("");
+
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_CAT",   SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME",  SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME", SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ",     SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT));
+                columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME",     SqlTypeName::VARCHAR,  IGNITE_TYPE_STRING));
+            }
+
+            PrimaryKeysQuery::~PrimaryKeysQuery()
+            {
+                // No-op.
+            }
+
+            SqlResult PrimaryKeysQuery::Execute()
+            {
+                if (executed)
+                    Close();
+
+                meta.push_back(meta::PrimaryKeyMeta(catalog, schema, table, "_KEY", 1, "_KEY"));
+
+                executed = true;
+
+                cursor = meta.begin();
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            const meta::ColumnMetaVector & PrimaryKeysQuery::GetMeta() const
+            {
+                return columnsMeta;
+            }
+
+            SqlResult PrimaryKeysQuery::FetchNextRow(app::ColumnBindingMap & columnBindings)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (cursor == meta.end())
+                    return SQL_RESULT_NO_DATA;
+
+                app::ColumnBindingMap::iterator it;
+
+                for (it = columnBindings.begin(); it != columnBindings.end(); ++it)
+                    GetColumn(it->first, it->second);
+
+                ++cursor;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult PrimaryKeysQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer)
+            {
+                if (!executed)
+                {
+                    diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed.");
+
+                    return SQL_RESULT_ERROR;
+                }
+
+                if (cursor == meta.end())
+                    return SQL_RESULT_NO_DATA;
+
+                const meta::PrimaryKeyMeta& currentColumn = *cursor;
+
+                switch (columnIdx)
+                {
+                    case TABLE_CAT:
+                    {
+                        buffer.PutString(currentColumn.GetCatalogName());
+                        break;
+                    }
+
+                    case TABLE_SCHEM:
+                    {
+                        buffer.PutString(currentColumn.GetSchemaName());
+                        break;
+                    }
+
+                    case TABLE_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetTableName());
+                        break;
+                    }
+
+                    case COLUMN_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetColumnName());
+                        break;
+                    }
+
+                    case KEY_SEQ:
+                    {
+                        buffer.PutInt16(currentColumn.GetKeySeq());
+                        break;
+                    }
+
+                    case PK_NAME:
+                    {
+                        buffer.PutString(currentColumn.GetKeyName());
+                        break;
+                    }
+
+                    default:
+                        break;
+                }
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            SqlResult PrimaryKeysQuery::Close()
+            {
+                meta.clear();
+
+                executed = false;
+
+                return SQL_RESULT_SUCCESS;
+            }
+
+            bool PrimaryKeysQuery::DataAvailable() const
+            {
+                return cursor != meta.end();
+            }
+
+            int64_t PrimaryKeysQuery::AffectedRows() const
+            {
+                return 0;
+            }
+        }
+    }
+}
+