Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id F0BB42009F3 for ; Thu, 5 May 2016 21:37:40 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id EF3221609F9; Thu, 5 May 2016 19:37:40 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 04904160A06 for ; Thu, 5 May 2016 21:37:37 +0200 (CEST) Received: (qmail 51800 invoked by uid 500); 5 May 2016 19:37:36 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 51661 invoked by uid 99); 5 May 2016 19:37:36 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 May 2016 19:37:36 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 157BBE0252; Thu, 5 May 2016 19:37:36 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: dmagda@apache.org To: commits@ignite.apache.org Date: Thu, 05 May 2016 19:37:40 -0000 Message-Id: <16e1c322da3a45c69b3101afb5f91817@git.apache.org> In-Reply-To: <157de727a73f4c6fae12667d5751dc81@git.apache.org> References: <157de727a73f4c6fae12667d5751dc81@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [06/40] ignite git commit: IGNITE-1786: Implemented ODBC driver. archived-at: Thu, 05 May 2016 19:37:41 -0000 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(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(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 +#include +#include +#include + +#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(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(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(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + Connection *connection = environment->CreateConnection(); + + if (!connection) + return environment->GetDiagnosticRecords().GetReturnCode(); + + *conn = reinterpret_cast(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(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + Statement *statement = connection->CreateStatement(); + + *stmt = reinterpret_cast(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(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(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(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(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(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(outConnectionString), + static_cast(outConnectionStringBufferLen)); + + if (outConnectionStringLen) + *outConnectionStringLen = static_cast(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(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(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(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(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(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(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(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(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + int32_t res = statement->GetColumnNumber(); + + *columnNum = static_cast(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(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(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(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(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(outQueryBuffer), + static_cast(outQueryBufferLen)); + + *outQueryLen = std::min(outQueryBufferLen, static_cast(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(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(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(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->GetColumnAttribute(columnNum, SQL_DESC_NAME, + reinterpret_cast(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(dataTypeRes); + *columnSize = static_cast(columnSizeRes); + *decimalDigits = static_cast(decimalDigitsRes); + *nullable = static_cast(nullableRes); + + return statement->GetDiagnosticRecords().GetReturnCode(); + } + + + SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCnt) + { + using ignite::odbc::Statement; + + LOG_MSG("SQLRowCount called\n"); + + Statement *statement = reinterpret_cast(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + int64_t res = statement->AffectedRows(); + + *rowCnt = static_cast(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(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(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(valueBuf); + + *val = static_cast(stmt); + + break; + } + + case SQL_ATTR_ROW_ARRAY_SIZE: + { + SQLINTEGER *val = reinterpret_cast(valueBuf); + + *val = static_cast(1); + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + SQLULEN** val = reinterpret_cast(valueBuf); + + *val = reinterpret_cast(statement->GetRowsFetchedPtr()); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + SQLUSMALLINT** val = reinterpret_cast(valueBuf); + + *val = reinterpret_cast(statement->GetRowStatusesPtr()); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast(valueBuf); + + *val = reinterpret_cast(statement->GetParamBindOffsetPtr()); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast(valueBuf); + + *val = reinterpret_cast(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(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(value); + + LOG_MSG("Value: %d\n", val); + + if (val != 1) + return SQL_ERROR; + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + statement->SetRowsFetchedPtr(reinterpret_cast(value)); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + statement->SetRowStatusesPtr(reinterpret_cast(value)); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + statement->SetParamBindOffsetPtr(reinterpret_cast(value)); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + statement->SetColumnBindOffsetPtr(reinterpret_cast(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(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(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + *paramCnt = static_cast(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(handle); + + result = diag->GetDiagnosticRecords().GetField(recNum, field, outBuffer); + + break; + } + + default: + { + result = SQL_RESULT_NO_DATA; + break; + } + } + + if (result == SQL_RESULT_SUCCESS) + *resLen = static_cast(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(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(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(outResLen); + + return SQL_SUCCESS; + } + + SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT type) + { + using ignite::odbc::Statement; + + LOG_MSG("SQLGetTypeInfo called\n"); + + Statement *statement = reinterpret_cast(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->ExecuteGetTypeInfoQuery(static_cast(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(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(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(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(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(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + SqlLen outResLen; + ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_DEFAULT, valueBuf, + static_cast(valueBufLen), &outResLen); + + environment->GetAttribute(attr, outBuffer); + + if (valueResLen) + *valueResLen = static_cast(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(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 + +#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", 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(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(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 + +#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 + +#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; + } + } + } +} +