You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dm...@apache.org on 2016/05/05 19:37:40 UTC
[06/40] ignite git commit: IGNITE-1786: Implemented ODBC driver.
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
new file mode 100644
index 0000000..d397618
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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/system/odbc_constants.h"
+#include "ignite/odbc/meta/column_meta.h"
+#include "ignite/odbc/type_traits.h"
+#include "ignite/odbc/common_types.h"
+
+namespace ignite
+{
+ namespace odbc
+ {
+ namespace meta
+ {
+
+#ifdef ODBC_DEBUG
+
+#define DBG_STR_CASE(x) case x: return #x
+
+ const char* ColumnMeta::AttrIdToString(uint16_t id)
+ {
+ switch (id)
+ {
+ DBG_STR_CASE(SQL_DESC_LABEL);
+ DBG_STR_CASE(SQL_DESC_BASE_COLUMN_NAME);
+ DBG_STR_CASE(SQL_DESC_NAME);
+ DBG_STR_CASE(SQL_DESC_TABLE_NAME);
+ DBG_STR_CASE(SQL_DESC_BASE_TABLE_NAME);
+ DBG_STR_CASE(SQL_DESC_SCHEMA_NAME);
+ DBG_STR_CASE(SQL_DESC_CATALOG_NAME);
+ DBG_STR_CASE(SQL_DESC_LITERAL_PREFIX);
+ DBG_STR_CASE(SQL_DESC_LITERAL_SUFFIX);
+ DBG_STR_CASE(SQL_DESC_TYPE_NAME);
+ DBG_STR_CASE(SQL_DESC_LOCAL_TYPE_NAME);
+ DBG_STR_CASE(SQL_DESC_FIXED_PREC_SCALE);
+ DBG_STR_CASE(SQL_DESC_AUTO_UNIQUE_VALUE);
+ DBG_STR_CASE(SQL_DESC_CASE_SENSITIVE);
+ DBG_STR_CASE(SQL_DESC_CONCISE_TYPE);
+ DBG_STR_CASE(SQL_DESC_TYPE);
+ DBG_STR_CASE(SQL_DESC_DISPLAY_SIZE);
+ DBG_STR_CASE(SQL_DESC_LENGTH);
+ DBG_STR_CASE(SQL_DESC_OCTET_LENGTH);
+ DBG_STR_CASE(SQL_DESC_NULLABLE);
+ DBG_STR_CASE(SQL_DESC_NUM_PREC_RADIX);
+ DBG_STR_CASE(SQL_DESC_PRECISION);
+ DBG_STR_CASE(SQL_DESC_SCALE);
+ DBG_STR_CASE(SQL_DESC_SEARCHABLE);
+ DBG_STR_CASE(SQL_DESC_UNNAMED);
+ DBG_STR_CASE(SQL_DESC_UNSIGNED);
+ DBG_STR_CASE(SQL_DESC_UPDATABLE);
+ default:
+ break;
+ }
+ return "<< UNKNOWN ID >>";
+ }
+
+#undef DBG_STR_CASE
+
+#endif
+
+ void ColumnMeta::Read(ignite::impl::binary::BinaryReaderImpl& reader)
+ {
+ utility::ReadString(reader, schemaName);
+ utility::ReadString(reader, tableName);
+ utility::ReadString(reader, columnName);
+
+ dataType = reader.ReadInt8();
+ }
+
+ bool ColumnMeta::GetAttribute(uint16_t fieldId, std::string& value) const
+ {
+ using namespace ignite::impl::binary;
+
+ switch (fieldId)
+ {
+ case SQL_DESC_LABEL:
+ case SQL_DESC_BASE_COLUMN_NAME:
+ case SQL_DESC_NAME:
+ {
+ value = columnName;
+
+ return true;
+ }
+
+ case SQL_DESC_TABLE_NAME:
+ case SQL_DESC_BASE_TABLE_NAME:
+ {
+ value = tableName;
+
+ return true;
+ }
+
+ case SQL_DESC_SCHEMA_NAME:
+ {
+ value = schemaName;
+
+ return true;
+ }
+
+ case SQL_DESC_CATALOG_NAME:
+ {
+ value.clear();
+
+ return true;
+ }
+
+ case SQL_DESC_LITERAL_PREFIX:
+ case SQL_DESC_LITERAL_SUFFIX:
+ {
+ if (dataType == IGNITE_TYPE_STRING)
+ value = "'";
+ else
+ value.clear();
+
+ return true;
+ }
+
+ case SQL_DESC_TYPE_NAME:
+ case SQL_DESC_LOCAL_TYPE_NAME:
+ {
+ value = type_traits::BinaryTypeToSqlTypeName(dataType);
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ bool ColumnMeta::GetAttribute(uint16_t fieldId, SqlLen& value) const
+ {
+ using namespace ignite::impl::binary;
+
+ switch (fieldId)
+ {
+ case SQL_DESC_FIXED_PREC_SCALE:
+ case SQL_DESC_AUTO_UNIQUE_VALUE:
+ {
+ value = SQL_FALSE;
+
+ return true;
+ }
+
+ case SQL_DESC_CASE_SENSITIVE:
+ {
+ if (dataType == IGNITE_TYPE_STRING)
+ value = SQL_TRUE;
+ else
+ value = SQL_FALSE;
+
+ return true;
+ }
+
+ case SQL_DESC_CONCISE_TYPE:
+ case SQL_DESC_TYPE:
+ {
+ value = type_traits::BinaryToSqlType(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_DISPLAY_SIZE:
+ {
+ value = type_traits::BinaryTypeDisplaySize(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_LENGTH:
+ case SQL_DESC_OCTET_LENGTH:
+ {
+ value = type_traits::BinaryTypeTransferLength(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_NULLABLE:
+ {
+ value = type_traits::BinaryTypeNullability(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_NUM_PREC_RADIX:
+ {
+ value = type_traits::BinaryTypeNumPrecRadix(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_PRECISION:
+ {
+ value = type_traits::BinaryTypeColumnSize(dataType);
+
+ return true;
+ }
+
+ case SQL_DESC_SCALE:
+ {
+ value = type_traits::BinaryTypeDecimalDigits(dataType);
+
+ if (value < 0)
+ value = 0;
+
+ return true;
+ }
+
+ case SQL_DESC_SEARCHABLE:
+ {
+ value = SQL_PRED_BASIC;
+
+ return true;
+ }
+
+ case SQL_DESC_UNNAMED:
+ {
+ value = columnName.empty() ? SQL_UNNAMED : SQL_NAMED;
+
+ return true;
+ }
+
+ case SQL_DESC_UNSIGNED:
+ {
+ value = type_traits::BinaryTypeUnsigned(dataType) ? SQL_TRUE : SQL_FALSE;
+
+ return true;
+ }
+
+ case SQL_DESC_UPDATABLE:
+ {
+ // We do not support update for now so just set all
+ // columns to readonly.
+ value = SQL_ATTR_READONLY;
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ void ReadColumnMetaVector(ignite::impl::binary::BinaryReaderImpl& reader, ColumnMetaVector& meta)
+ {
+ int32_t metaNum = reader.ReadInt32();
+
+ meta.clear();
+ meta.reserve(static_cast<size_t>(metaNum));
+
+ for (int32_t i = 0; i < metaNum; ++i)
+ {
+ meta.push_back(ColumnMeta());
+
+ meta.back().Read(reader);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/meta/table_meta.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/meta/table_meta.cpp b/modules/platforms/cpp/odbc/src/meta/table_meta.cpp
new file mode 100644
index 0000000..71ced8f
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/meta/table_meta.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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/meta/table_meta.h"
+
+namespace ignite
+{
+ namespace odbc
+ {
+ namespace meta
+ {
+ void TableMeta::Read(ignite::impl::binary::BinaryReaderImpl & reader)
+ {
+ utility::ReadString(reader, catalogName);
+ utility::ReadString(reader, schemaName);
+ utility::ReadString(reader, tableName);
+ utility::ReadString(reader, tableType);
+ }
+
+ void ReadTableMetaVector(ignite::impl::binary::BinaryReaderImpl& reader, TableMetaVector& meta)
+ {
+ int32_t metaNum = reader.ReadInt32();
+
+ meta.clear();
+ meta.reserve(static_cast<size_t>(metaNum));
+
+ for (int32_t i = 0; i < metaNum; ++i)
+ {
+ meta.push_back(TableMeta());
+
+ meta.back().Read(reader);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/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..53717c7
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -0,0 +1,1364 @@
+/*
+ * 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"
+#include "ignite/odbc.h"
+
+namespace ignite
+{
+
+ BOOL 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 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), %p, %d, %p\n",
+ infoType, ConnectionInfo::InfoTypeToString(infoType),
+ infoValue, infoValueMax, length);
+
+ Connection *connection = reinterpret_cast<Connection*>(conn);
+
+ if (!connection)
+ return SQL_INVALID_HANDLE;
+
+ connection->GetInfo(infoType, infoValue, infoValueMax, length);
+
+ return connection->GetDiagnosticRecords().GetReturnCode();
+ }
+
+ SQLRETURN 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 SQLAllocEnv(SQLHENV* env)
+ {
+ using ignite::odbc::Environment;
+
+ LOG_MSG("SQLAllocEnv called\n");
+
+ *env = reinterpret_cast<SQLHENV>(new Environment());
+
+ return SQL_SUCCESS;
+ }
+
+ SQLRETURN 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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);
+
+ if (valueResLen)
+ *valueResLen = static_cast<SQLSMALLINT>(outResLen);
+
+ return environment->GetDiagnosticRecords().GetReturnCode();
+ }
+
+ SQLRETURN 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();
+ }
+
+} // namespace ignite;
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/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..5e764a2
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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\ufffddependent 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", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "DATA_TYPE", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "TYPE_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_SIZE", IGNITE_TYPE_INT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "BUFFER_LENGTH", IGNITE_TYPE_INT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "DECIMAL_DIGITS", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "NUM_PREC_RADIX", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "NULLABLE", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "REMARKS", 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(type_traits::BinaryTypeToSqlTypeName(currentColumn.GetDataType()));
+ 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;
+
+ try
+ {
+ connection.SyncMessage(req, rsp);
+ }
+ catch (const IgniteError& err)
+ {
+ diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, err.GetText());
+
+ 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] ColumnType: %d\n", i, meta[i].GetDataType());
+ LOG_MSG("\n");
+ }
+
+ return SQL_RESULT_SUCCESS;
+ }
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/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..e96f1da
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp
@@ -0,0 +1,278 @@
+/*
+ * 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->HasData())
+ return SQL_RESULT_NO_DATA;
+
+ cursor->Increment();
+
+ if (cursor->NeedDataUpdate())
+ {
+ SqlResult result = MakeRequestFetch();
+
+ if (result != SQL_RESULT_SUCCESS)
+ return result;
+ }
+
+ if (!cursor->HasData())
+ return SQL_RESULT_NO_DATA;
+
+ 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);
+
+ if (it == columnBindings.end())
+ continue;
+
+ SqlResult 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->HasData();
+ }
+
+ int64_t DataQuery::AffectedRows() const
+ {
+ // We are only support SELECT statements so we can not affect any row.
+ return 0;
+ }
+
+ SqlResult DataQuery::MakeRequestExecute()
+ {
+ const std::string& cacheName = connection.GetCache();
+
+ QueryExecuteRequest req(cacheName, sql, params);
+ QueryExecuteResponse rsp;
+
+ try
+ {
+ connection.SyncMessage(req, rsp);
+ }
+ catch (const IgniteError& err)
+ {
+ diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, err.GetText());
+
+ 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] ColumnType: %d\n", i, rsp.GetMeta()[i].GetDataType());
+ LOG_MSG("\n");
+ }
+
+ return SQL_RESULT_SUCCESS;
+ }
+
+ SqlResult DataQuery::MakeRequestClose()
+ {
+ QueryCloseRequest req(cursor->GetQueryId());
+ QueryCloseResponse rsp;
+
+ try
+ {
+ connection.SyncMessage(req, rsp);
+ }
+ catch (const IgniteError& err)
+ {
+ diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, err.GetText());
+
+ 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);
+
+ try
+ {
+ connection.SyncMessage(req, rsp);
+ }
+ catch (const IgniteError& err)
+ {
+ diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, err.GetText());
+
+ 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/764c97b9/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..4fefa22
--- /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", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_SCHEM", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "PKCOLUMN_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_CAT", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_SCHEM", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "FKCOLUMN_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "UPDATE_RULE", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "DELETE_RULE", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "FK_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "DEFERRABILITY", 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/764c97b9/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..11ff4fa
--- /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", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME", IGNITE_TYPE_STRING));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ", IGNITE_TYPE_SHORT));
+ columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME", 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;
+ }
+ }
+ }
+}
+