http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp new file mode 100644 index 0000000..84e312a --- /dev/null +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -0,0 +1,1687 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <algorithm> + +#include "ignite/odbc/utility.h" +#include "ignite/odbc/system/odbc_constants.h" + +#include "ignite/odbc/config/configuration.h" +#include "ignite/odbc/type_traits.h" +#include "ignite/odbc/environment.h" +#include "ignite/odbc/connection.h" +#include "ignite/odbc/statement.h" + +#ifdef ODBC_DEBUG + +FILE* log_file = NULL; + +void logInit(const char* path) +{ + if (!log_file) + { + log_file = fopen(path, "w"); + } +} + +#endif //ODBC_DEBUG + +BOOL INSTAPI ConfigDSN(HWND hwndParent, + WORD req, + LPCSTR driver, + LPCSTR attributes) +{ + LOG_MSG("ConfigDSN called\n"); + + ignite::odbc::config::Configuration config; + + config.FillFromConfigAttributes(attributes); + + if (!SQLValidDSN(config.GetDsn().c_str())) + return SQL_FALSE; + + LOG_MSG("Driver: %s\n", driver); + LOG_MSG("Attributes: %s\n", attributes); + + LOG_MSG("DSN: %s\n", config.GetDsn().c_str()); + + switch (req) + { + case ODBC_ADD_DSN: + { + LOG_MSG("ODBC_ADD_DSN\n"); + + return SQLWriteDSNToIni(config.GetDsn().c_str(), driver); + } + + case ODBC_CONFIG_DSN: + { + LOG_MSG("ODBC_CONFIG_DSN\n"); + break; + } + + case ODBC_REMOVE_DSN: + { + LOG_MSG("ODBC_REMOVE_DSN\n"); + + return SQLRemoveDSNFromIni(config.GetDsn().c_str()); + } + + default: + { + return SQL_FALSE; + } + } + + return SQL_TRUE; +} + +SQLRETURN SQL_API SQLGetInfo(SQLHDBC conn, + SQLUSMALLINT infoType, + SQLPOINTER infoValue, + SQLSMALLINT infoValueMax, + SQLSMALLINT* length) +{ + using ignite::odbc::Connection; + using ignite::odbc::config::ConnectionInfo; + + LOG_MSG("SQLGetInfo called: %d (%s)\n", infoType, ConnectionInfo::InfoTypeToString(infoType)); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + connection->GetInfo(infoType, infoValue, infoValueMax, length); + + return connection->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) +{ + //LOG_MSG("SQLAllocHandle called\n"); + switch (type) + { + case SQL_HANDLE_ENV: + return SQLAllocEnv(result); + + case SQL_HANDLE_DBC: + return SQLAllocConnect(parent, result); + + case SQL_HANDLE_STMT: + return SQLAllocStmt(parent, result); + + case SQL_HANDLE_DESC: + default: + break; + } + + *result = 0; + return SQL_ERROR; +} + +SQLRETURN SQL_API SQLAllocEnv(SQLHENV* env) +{ + using ignite::odbc::Environment; + + LOG_MSG("SQLAllocEnv called\n"); + + *env = reinterpret_cast<SQLHENV>(new Environment()); + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLAllocConnect(SQLHENV env, SQLHDBC* conn) +{ + using ignite::odbc::Environment; + using ignite::odbc::Connection; + + LOG_MSG("SQLAllocConnect called\n"); + + *conn = SQL_NULL_HDBC; + + Environment *environment = reinterpret_cast<Environment*>(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + Connection *connection = environment->CreateConnection(); + + if (!connection) + return environment->GetDiagnosticRecords().GetReturnCode(); + + *conn = reinterpret_cast<SQLHDBC>(connection); + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLAllocStmt(SQLHDBC conn, SQLHSTMT* stmt) +{ + using ignite::odbc::Connection; + using ignite::odbc::Statement; + + LOG_MSG("SQLAllocStmt called\n"); + + *stmt = SQL_NULL_HDBC; + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + Statement *statement = connection->CreateStatement(); + + *stmt = reinterpret_cast<SQLHSTMT>(statement); + + return connection->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) +{ + switch (type) + { + case SQL_HANDLE_ENV: + return SQLFreeEnv(handle); + + case SQL_HANDLE_DBC: + return SQLFreeConnect(handle); + + case SQL_HANDLE_STMT: + return SQLFreeStmt(handle, SQL_DROP); + + case SQL_HANDLE_DESC: + default: + break; + } + + return SQL_ERROR; +} + +SQLRETURN SQL_API SQLFreeEnv(SQLHENV env) +{ + using ignite::odbc::Environment; + + LOG_MSG("SQLFreeEnv called\n"); + + Environment *environment = reinterpret_cast<Environment*>(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + delete environment; + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLFreeConnect(SQLHDBC conn) +{ + using ignite::odbc::Connection; + + LOG_MSG("SQLFreeConnect called\n"); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + delete connection; + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLFreeStmt called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + switch (option) + { + case SQL_DROP: + { + delete statement; + + break; + } + + case SQL_CLOSE: + { + return SQLCloseCursor(stmt); + } + + case SQL_UNBIND: + { + statement->UnbindAllColumns(); + + break; + } + + case SQL_RESET_PARAMS: + { + statement->UnbindAllParameters(); + + break; + } + + default: + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT stmt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLCloseCursor called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + statement->Close(); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLDriverConnect(SQLHDBC conn, + SQLHWND windowHandle, + SQLCHAR* inConnectionString, + SQLSMALLINT inConnectionStringLen, + SQLCHAR* outConnectionString, + SQLSMALLINT outConnectionStringBufferLen, + SQLSMALLINT* outConnectionStringLen, + SQLUSMALLINT driverCompletion) +{ + using ignite::odbc::Connection; + using ignite::odbc::diagnostic::DiagnosticRecordStorage; + using ignite::utility::SqlStringToString; + using ignite::utility::CopyStringToBuffer; + + UNREFERENCED_PARAMETER(windowHandle); + + LOG_MSG("SQLDriverConnect called\n"); + LOG_MSG("Connection String: [%s]\n", inConnectionString); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + std::string connectStr = SqlStringToString(inConnectionString, inConnectionStringLen); + + ignite::odbc::config::Configuration config; + + config.FillFromConnectString(connectStr); + + connection->Establish(config.GetHost(), config.GetPort(), config.GetCache()); + + const DiagnosticRecordStorage& diag = connection->GetDiagnosticRecords(); + + if (!diag.IsSuccessful()) + return diag.GetReturnCode(); + + std::string outConnectStr = config.ToConnectString(); + + size_t reslen = CopyStringToBuffer(outConnectStr, + reinterpret_cast<char*>(outConnectionString), + static_cast<size_t>(outConnectionStringBufferLen)); + + if (outConnectionStringLen) + *outConnectionStringLen = static_cast<SQLSMALLINT>(reslen); + + LOG_MSG("%s\n", outConnectionString); + + return diag.GetReturnCode(); +} + +SQLRETURN SQL_API SQLConnect(SQLHDBC conn, + SQLCHAR* serverName, + SQLSMALLINT serverNameLen, + SQLCHAR* userName, + SQLSMALLINT userNameLen, + SQLCHAR* auth, + SQLSMALLINT authLen) +{ + using ignite::odbc::Connection; + using ignite::odbc::diagnostic::DiagnosticRecordStorage; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLConnect called\n"); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + std::string server = SqlStringToString(serverName, serverNameLen); + + connection->Establish(server); + + return connection->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLDisconnect(SQLHDBC conn) +{ + using ignite::odbc::Connection; + + LOG_MSG("SQLDisconnect called\n"); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + connection->Release(); + + return connection->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLPrepare(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLPrepare called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string sql = SqlStringToString(query, queryLen); + + LOG_MSG("SQL: %s\n", sql.c_str()); + + statement->PrepareSqlQuery(sql); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLExecute(SQLHSTMT stmt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLExecute called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->ExecuteSqlQuery(); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLExecDirect(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLExecDirect called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string sql = SqlStringToString(query, queryLen); + + LOG_MSG("SQL: %s\n", sql.c_str()); + + statement->ExecuteSqlQuery(sql); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLBindCol(SQLHSTMT stmt, + SQLUSMALLINT colNum, + SQLSMALLINT targetType, + SQLPOINTER targetValue, + SQLLEN bufferLength, + SQLLEN* strLengthOrIndicator) +{ + using namespace ignite::odbc::type_traits; + + using ignite::odbc::Statement; + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLBindCol called: index=%d, type=%d\n", colNum, targetType); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + IgniteSqlType driverType = ToDriverType(targetType); + + if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) + return SQL_ERROR; + + if (bufferLength < 0) + return SQL_ERROR; + + if (targetValue || strLengthOrIndicator) + { + ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator); + + statement->BindColumn(colNum, dataBuffer); + } + else + statement->UnbindColumn(colNum); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLFetch(SQLHSTMT stmt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLFetch called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->FetchRow(); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLFetchScroll(SQLHSTMT stmt, + SQLSMALLINT orientation, + SQLLEN offset) +{ + LOG_MSG("SQLFetchScroll called\n"); + LOG_MSG("Orientation: %d, Offset: %d\n", orientation, offset); + + if (orientation != SQL_FETCH_NEXT) + return SQL_ERROR; + + return SQLFetch(stmt); +} + +SQLRETURN SQL_API SQLExtendedFetch(SQLHSTMT stmt, + SQLUSMALLINT orientation, + SQLLEN offset, + SQLULEN* rowCount, + SQLUSMALLINT* rowStatusArray) +{ + LOG_MSG("SQLExtendedFetch called\n"); + + SQLRETURN res = SQLFetchScroll(stmt, orientation, offset); + + if (res == SQL_SUCCESS || res == SQL_NO_DATA) + { + if (rowCount) + *rowCount = 1; + + if (rowStatusArray) + rowStatusArray[0] = SQL_ROW_SUCCESS; + } + + return res; +} + +SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *columnNum) +{ + using ignite::odbc::Statement; + using ignite::odbc::meta::ColumnMetaVector; + + LOG_MSG("SQLNumResultCols called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + int32_t res = statement->GetColumnNumber(); + + *columnNum = static_cast<SQLSMALLINT>(res); + + LOG_MSG("columnNum: %d\n", *columnNum); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLTables(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLCHAR* tableType, + SQLSMALLINT tableTypeLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLTables called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string catalog = SqlStringToString(catalogName, catalogNameLen); + std::string schema = SqlStringToString(schemaName, schemaNameLen); + std::string table = SqlStringToString(tableName, tableNameLen); + std::string tableTypeStr = SqlStringToString(tableType, tableTypeLen); + + LOG_MSG("catalog: %s\n", catalog.c_str()); + LOG_MSG("schema: %s\n", schema.c_str()); + LOG_MSG("table: %s\n", table.c_str()); + LOG_MSG("tableType: %s\n", tableTypeStr.c_str()); + + statement->ExecuteGetTablesMetaQuery(catalog, schema, table, tableTypeStr); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLColumns(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLCHAR* columnName, + SQLSMALLINT columnNameLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLColumns called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string catalog = SqlStringToString(catalogName, catalogNameLen); + std::string schema = SqlStringToString(schemaName, schemaNameLen); + std::string table = SqlStringToString(tableName, tableNameLen); + std::string column = SqlStringToString(columnName, columnNameLen); + + LOG_MSG("catalog: %s\n", catalog.c_str()); + LOG_MSG("schema: %s\n", schema.c_str()); + LOG_MSG("table: %s\n", table.c_str()); + LOG_MSG("column: %s\n", column.c_str()); + + statement->ExecuteGetColumnsMetaQuery(schema, table, column); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLMoreResults(SQLHSTMT stmt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLMoreResults called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + //TODO: reset diagnostic here. + return statement->DataAvailable() ? SQL_SUCCESS : SQL_NO_DATA; +} + +SQLRETURN SQL_API SQLBindParameter(SQLHSTMT stmt, + SQLUSMALLINT paramIdx, + SQLSMALLINT ioType, + SQLSMALLINT bufferType, + SQLSMALLINT paramSqlType, + SQLULEN columnSize, + SQLSMALLINT decDigits, + SQLPOINTER buffer, + SQLLEN bufferLen, + SQLLEN* resLen) +{ + using namespace ignite::odbc::type_traits; + + using ignite::odbc::Statement; + using ignite::odbc::app::ApplicationDataBuffer; + using ignite::odbc::app::Parameter; + using ignite::odbc::type_traits::IsSqlTypeSupported; + + LOG_MSG("SQLBindParameter called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + if (ioType != SQL_PARAM_INPUT) + return SQL_ERROR; + + if (*resLen == SQL_DATA_AT_EXEC || *resLen <= SQL_LEN_DATA_AT_EXEC_OFFSET) + return SQL_ERROR; + + if (!IsSqlTypeSupported(paramSqlType)) + return SQL_ERROR; + + IgniteSqlType driverType = ToDriverType(bufferType); + + if (driverType == IGNITE_ODBC_C_TYPE_UNSUPPORTED) + return SQL_ERROR; + + if (buffer) + { + ApplicationDataBuffer dataBuffer(driverType, buffer, bufferLen, resLen); + + Parameter param(dataBuffer, paramSqlType, columnSize, decDigits); + + statement->BindParameter(paramIdx, param); + } + else + statement->UnbindParameter(paramIdx); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLNativeSql(SQLHDBC conn, + SQLCHAR* inQuery, + SQLINTEGER inQueryLen, + SQLCHAR* outQueryBuffer, + SQLINTEGER outQueryBufferLen, + SQLINTEGER* outQueryLen) +{ + using namespace ignite::utility; + + LOG_MSG("SQLNativeSql called\n"); + + std::string in = SqlStringToString(inQuery, inQueryLen); + + CopyStringToBuffer(in, reinterpret_cast<char*>(outQueryBuffer), + static_cast<size_t>(outQueryBufferLen)); + + *outQueryLen = std::min(outQueryBufferLen, static_cast<SQLINTEGER>(in.size())); + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLColAttribute(SQLHSTMT stmt, + SQLUSMALLINT columnNum, + SQLUSMALLINT fieldId, + SQLPOINTER strAttr, + SQLSMALLINT bufferLen, + SQLSMALLINT* strAttrLen, + SQLLEN* numericAttr) +{ + using ignite::odbc::Statement; + using ignite::odbc::meta::ColumnMetaVector; + using ignite::odbc::meta::ColumnMeta; + + LOG_MSG("SQLColAttribute called: %d (%s)\n", fieldId, ColumnMeta::AttrIdToString(fieldId)); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + // This is a special case + if (fieldId == SQL_DESC_COUNT) + { + SQLSMALLINT val = 0; + + SQLRETURN res = SQLNumResultCols(stmt, &val); + + if (res == SQL_SUCCESS) + *numericAttr = val; + + return res; + } + + statement->GetColumnAttribute(columnNum, fieldId, reinterpret_cast<char*>(strAttr), + bufferLen, strAttrLen, numericAttr); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLDescribeCol(SQLHSTMT stmt, + SQLUSMALLINT columnNum, + SQLCHAR* columnNameBuf, + SQLSMALLINT columnNameBufLen, + SQLSMALLINT* columnNameLen, + SQLSMALLINT* dataType, + SQLULEN* columnSize, + SQLSMALLINT* decimalDigits, + SQLSMALLINT* nullable) +{ + using ignite::odbc::Statement; + using ignite::odbc::SqlLen; + + LOG_MSG("SQLDescribeCol called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->GetColumnAttribute(columnNum, SQL_DESC_NAME, + reinterpret_cast<char*>(columnNameBuf), columnNameBufLen, columnNameLen, 0); + + SqlLen dataTypeRes; + SqlLen columnSizeRes; + SqlLen decimalDigitsRes; + SqlLen nullableRes; + + statement->GetColumnAttribute(columnNum, SQL_DESC_TYPE, 0, 0, 0, &dataTypeRes); + statement->GetColumnAttribute(columnNum, SQL_DESC_PRECISION, 0, 0, 0, &columnSizeRes); + statement->GetColumnAttribute(columnNum, SQL_DESC_SCALE, 0, 0, 0, &decimalDigitsRes); + statement->GetColumnAttribute(columnNum, SQL_DESC_NULLABLE, 0, 0, 0, &nullableRes); + + LOG_MSG("columnNum: %lld\n", columnNum); + LOG_MSG("dataTypeRes: %lld\n", dataTypeRes); + LOG_MSG("columnSizeRes: %lld\n", columnSizeRes); + LOG_MSG("decimalDigitsRes: %lld\n", decimalDigitsRes); + LOG_MSG("nullableRes: %lld\n", nullableRes); + LOG_MSG("columnNameBuf: %s\n", columnNameBuf); + LOG_MSG("columnNameLen: %d\n", *columnNameLen); + + *dataType = static_cast<SQLSMALLINT>(dataTypeRes); + *columnSize = static_cast<SQLULEN>(columnSizeRes); + *decimalDigits = static_cast<SQLSMALLINT>(decimalDigitsRes); + *nullable = static_cast<SQLSMALLINT>(nullableRes); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + + +SQLRETURN SQL_API SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCnt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLRowCount called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + int64_t res = statement->AffectedRows(); + + *rowCnt = static_cast<SQLLEN>(res); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLForeignKeys(SQLHSTMT stmt, + SQLCHAR* primaryCatalogName, + SQLSMALLINT primaryCatalogNameLen, + SQLCHAR* primarySchemaName, + SQLSMALLINT primarySchemaNameLen, + SQLCHAR* primaryTableName, + SQLSMALLINT primaryTableNameLen, + SQLCHAR* foreignCatalogName, + SQLSMALLINT foreignCatalogNameLen, + SQLCHAR* foreignSchemaName, + SQLSMALLINT foreignSchemaNameLen, + SQLCHAR* foreignTableName, + SQLSMALLINT foreignTableNameLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLForeignKeys called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string primaryCatalog = SqlStringToString(primaryCatalogName, primaryCatalogNameLen); + std::string primarySchema = SqlStringToString(primarySchemaName, primarySchemaNameLen); + std::string primaryTable = SqlStringToString(primaryTableName, primaryTableNameLen); + std::string foreignCatalog = SqlStringToString(foreignCatalogName, foreignCatalogNameLen); + std::string foreignSchema = SqlStringToString(foreignSchemaName, foreignSchemaNameLen); + std::string foreignTable = SqlStringToString(foreignTableName, foreignTableNameLen); + + LOG_MSG("primaryCatalog: %s\n", primaryCatalog.c_str()); + LOG_MSG("primarySchema: %s\n", primarySchema.c_str()); + LOG_MSG("primaryTable: %s\n", primaryTable.c_str()); + LOG_MSG("foreignCatalog: %s\n", foreignCatalog.c_str()); + LOG_MSG("foreignSchema: %s\n", foreignSchema.c_str()); + LOG_MSG("foreignTable: %s\n", foreignTable.c_str()); + + statement->ExecuteGetForeignKeysQuery(primaryCatalog, primarySchema, + primaryTable, foreignCatalog, foreignSchema, foreignTable); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLGetStmtAttr(SQLHSTMT stmt, + SQLINTEGER attr, + SQLPOINTER valueBuf, + SQLINTEGER valueBufLen, + SQLINTEGER* valueResLen) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLGetStmtAttr called"); + +#ifdef ODBC_DEBUG + using ignite::odbc::type_traits::StatementAttrIdToString; + + LOG_MSG("Attr: %s (%d)\n", StatementAttrIdToString(attr), attr); +#endif //ODBC_DEBUG + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + //TODO: move this logic into Statement. + switch (attr) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + case SQL_ATTR_IMP_ROW_DESC: + case SQL_ATTR_IMP_PARAM_DESC: + { + SQLPOINTER *val = reinterpret_cast<SQLPOINTER*>(valueBuf); + + *val = static_cast<SQLPOINTER>(stmt); + + break; + } + + case SQL_ATTR_ROW_ARRAY_SIZE: + { + SQLINTEGER *val = reinterpret_cast<SQLINTEGER*>(valueBuf); + + *val = static_cast<SQLINTEGER>(1); + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); + + *val = reinterpret_cast<SQLULEN*>(statement->GetRowsFetchedPtr()); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + SQLUSMALLINT** val = reinterpret_cast<SQLUSMALLINT**>(valueBuf); + + *val = reinterpret_cast<SQLUSMALLINT*>(statement->GetRowStatusesPtr()); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); + + *val = reinterpret_cast<SQLULEN*>(statement->GetParamBindOffsetPtr()); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); + + *val = reinterpret_cast<SQLULEN*>(statement->GetColumnBindOffsetPtr()); + + break; + } + + default: + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetStmtAttr(SQLHSTMT stmt, + SQLINTEGER attr, + SQLPOINTER value, + SQLINTEGER valueLen) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLSetStmtAttr called"); + +#ifdef ODBC_DEBUG + using ignite::odbc::type_traits::StatementAttrIdToString; + + LOG_MSG("Attr: %s (%d)\n", StatementAttrIdToString(attr), attr); +#endif //ODBC_DEBUG + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + //TODO: move this logic into Statement. + switch (attr) + { + case SQL_ATTR_ROW_ARRAY_SIZE: + { + SQLULEN val = reinterpret_cast<SQLULEN>(value); + + LOG_MSG("Value: %d\n", val); + + if (val != 1) + return SQL_ERROR; + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + statement->SetRowsFetchedPtr(reinterpret_cast<size_t*>(value)); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + statement->SetRowStatusesPtr(reinterpret_cast<uint16_t*>(value)); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + statement->SetParamBindOffsetPtr(reinterpret_cast<size_t*>(value)); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + statement->SetColumnBindOffsetPtr(reinterpret_cast<size_t*>(value)); + + break; + } + + default: + return SQL_ERROR; + } + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLPrimaryKeys(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen) +{ + using ignite::odbc::Statement; + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLPrimaryKeys called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string catalog = SqlStringToString(catalogName, catalogNameLen); + std::string schema = SqlStringToString(schemaName, schemaNameLen); + std::string table = SqlStringToString(tableName, tableNameLen); + + LOG_MSG("catalog: %s\n", catalog.c_str()); + LOG_MSG("schema: %s\n", schema.c_str()); + LOG_MSG("table: %s\n", table.c_str()); + + statement->ExecuteGetPrimaryKeysQuery(catalog, schema, table); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLNumParams(SQLHSTMT stmt, SQLSMALLINT* paramCnt) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLNumParams called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + *paramCnt = static_cast<SQLSMALLINT>(statement->GetParametersNumber()); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT handleType, + SQLHANDLE handle, + SQLSMALLINT recNum, + SQLSMALLINT diagId, + SQLPOINTER buffer, + SQLSMALLINT bufferLen, + SQLSMALLINT* resLen) +{ + using namespace ignite::odbc; + using namespace ignite::odbc::diagnostic; + using namespace ignite::odbc::type_traits; + + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLGetDiagField called: %d\n", recNum); + + SqlLen outResLen; + ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_DEFAULT, buffer, bufferLen, &outResLen); + + SqlResult result; + + DiagnosticField field = DiagnosticFieldToInternal(diagId); + + switch (handleType) + { + case SQL_HANDLE_ENV: + case SQL_HANDLE_DBC: + case SQL_HANDLE_STMT: + { + Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle); + + result = diag->GetDiagnosticRecords().GetField(recNum, field, outBuffer); + + break; + } + + default: + { + result = SQL_RESULT_NO_DATA; + break; + } + } + + if (result == SQL_RESULT_SUCCESS) + *resLen = static_cast<SQLSMALLINT>(outResLen); + + return SqlResultToReturnCode(result); +} + +SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT handleType, + SQLHANDLE handle, + SQLSMALLINT recNum, + SQLCHAR* sqlState, + SQLINTEGER* nativeError, + SQLCHAR* msgBuffer, + SQLSMALLINT msgBufferLen, + SQLSMALLINT* msgLen) +{ + using namespace ignite::utility; + using namespace ignite::odbc; + using namespace ignite::odbc::diagnostic; + using namespace ignite::odbc::type_traits; + + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLGetDiagRec called\n"); + + const DiagnosticRecordStorage* records = 0; + + switch (handleType) + { + case SQL_HANDLE_ENV: + case SQL_HANDLE_DBC: + case SQL_HANDLE_STMT: + { + Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle); + + records = &diag->GetDiagnosticRecords(); + + break; + } + + default: + break; + } + + if (!records || recNum < 1 || recNum > records->GetStatusRecordsNumber()) + return SQL_NO_DATA; + + const DiagnosticRecord& record = records->GetStatusRecord(recNum); + + if (sqlState) + CopyStringToBuffer(record.GetSqlState(), reinterpret_cast<char*>(sqlState), 6); + + if (nativeError) + *nativeError = 0; + + SqlLen outResLen; + ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_CHAR, msgBuffer, msgBufferLen, &outResLen); + + outBuffer.PutString(record.GetMessage()); + + *msgLen = static_cast<SQLSMALLINT>(outResLen); + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetTypeInfo(SQLHSTMT stmt, + SQLSMALLINT type) +{ + using ignite::odbc::Statement; + + LOG_MSG("SQLGetTypeInfo called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + statement->ExecuteGetTypeInfoQuery(static_cast<int16_t>(type)); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLEndTran(SQLSMALLINT handleType, + SQLHANDLE handle, + SQLSMALLINT completionType) +{ + using namespace ignite::odbc; + + LOG_MSG("SQLEndTran called\n"); + + SQLRETURN result; + + switch (handleType) + { + case SQL_HANDLE_ENV: + { + Environment *env = reinterpret_cast<Environment*>(handle); + + if (!env) + return SQL_INVALID_HANDLE; + + if (completionType == SQL_COMMIT) + env->TransactionCommit(); + else + env->TransactionRollback(); + + result = env->GetDiagnosticRecords().GetReturnCode(); + + break; + } + + case SQL_HANDLE_DBC: + { + Connection *conn = reinterpret_cast<Connection*>(handle); + + if (!conn) + return SQL_INVALID_HANDLE; + + if (completionType == SQL_COMMIT) + conn->TransactionCommit(); + else + conn->TransactionRollback(); + + result = conn->GetDiagnosticRecords().GetReturnCode(); + + break; + } + + default: + { + result = SQL_INVALID_HANDLE; + + break; + } + } + + return result; +} + +SQLRETURN SQL_API SQLGetData(SQLHSTMT stmt, + SQLUSMALLINT colNum, + SQLSMALLINT targetType, + SQLPOINTER targetValue, + SQLLEN bufferLength, + SQLLEN* strLengthOrIndicator) +{ + using namespace ignite::odbc::type_traits; + + using ignite::odbc::Statement; + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLGetData called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + IgniteSqlType driverType = ToDriverType(targetType); + + ApplicationDataBuffer dataBuffer(driverType, targetValue, bufferLength, strLengthOrIndicator); + + statement->GetColumnData(colNum, dataBuffer); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLSetEnvAttr(SQLHENV env, + SQLINTEGER attr, + SQLPOINTER value, + SQLINTEGER valueLen) +{ + using ignite::odbc::Environment; + + LOG_MSG("SQLSetEnvAttr called\n"); + + Environment *environment = reinterpret_cast<Environment*>(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + environment->SetAttribute(attr, value, valueLen); + + return environment->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV env, + SQLINTEGER attr, + SQLPOINTER valueBuf, + SQLINTEGER valueBufLen, + SQLINTEGER* valueResLen) +{ + using namespace ignite::odbc; + using namespace ignite::odbc::type_traits; + + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLGetEnvAttr called\n"); + + Environment *environment = reinterpret_cast<Environment*>(env); + + if (!environment) + return SQL_INVALID_HANDLE; + + SqlLen outResLen; + ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_DEFAULT, valueBuf, + static_cast<int32_t>(valueBufLen), &outResLen); + + environment->GetAttribute(attr, outBuffer); + + *valueResLen = static_cast<SQLSMALLINT>(outResLen); + + return environment->GetDiagnosticRecords().GetReturnCode(); +} + +SQLRETURN SQL_API SQLSpecialColumns(SQLHSTMT stmt, + SQLSMALLINT idType, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLSMALLINT scope, + SQLSMALLINT nullable) +{ + using namespace ignite::odbc; + + using ignite::utility::SqlStringToString; + + LOG_MSG("SQLSpecialColumns called\n"); + + Statement *statement = reinterpret_cast<Statement*>(stmt); + + if (!statement) + return SQL_INVALID_HANDLE; + + std::string catalog = SqlStringToString(catalogName, catalogNameLen); + std::string schema = SqlStringToString(schemaName, schemaNameLen); + std::string table = SqlStringToString(tableName, tableNameLen); + + LOG_MSG("catalog: %s\n", catalog.c_str()); + LOG_MSG("schema: %s\n", schema.c_str()); + LOG_MSG("table: %s\n", table.c_str()); + + statement->ExecuteSpecialColumnsQuery(idType, catalog, schema, table, scope, nullable); + + return statement->GetDiagnosticRecords().GetReturnCode(); +} + +// +// ==== Not implemented ==== +// + +SQLRETURN SQL_API SQLCancel(SQLHSTMT stmt) +{ + LOG_MSG("SQLCancel called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLColAttributes(SQLHSTMT stmt, + SQLUSMALLINT colNum, + SQLUSMALLINT fieldId, + SQLPOINTER strAttrBuf, + SQLSMALLINT strAttrBufLen, + SQLSMALLINT* strAttrResLen, + SQLLEN* numAttrBuf) +{ + LOG_MSG("SQLColAttributes called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLError(SQLHENV env, + SQLHDBC conn, + SQLHSTMT stmt, + SQLCHAR* state, + SQLINTEGER* error, + SQLCHAR* msgBuf, + SQLSMALLINT msgBufLen, + SQLSMALLINT* msgResLen) +{ + LOG_MSG("SQLError called\n"); + return(SQL_NO_DATA_FOUND); +} + +SQLRETURN SQL_API SQLGetCursorName(SQLHSTMT stmt, + SQLCHAR* nameBuf, + SQLSMALLINT nameBufLen, + SQLSMALLINT* nameResLen) +{ + LOG_MSG("SQLGetCursorName called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetCursorName(SQLHSTMT stmt, + SQLCHAR* name, + SQLSMALLINT nameLen) +{ + LOG_MSG("SQLSetCursorName called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetConnectOption(SQLHDBC conn, + SQLUSMALLINT option, + SQLPOINTER value) +{ + LOG_MSG("SQLGetConnectOption called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetFunctions(SQLHDBC conn, + SQLUSMALLINT funcId, + SQLUSMALLINT* supported) +{ + LOG_MSG("SQLGetFunctions called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetStmtOption(SQLHSTMT stmt, + SQLUSMALLINT option, + SQLPOINTER value) +{ + LOG_MSG("SQLGetStmtOption called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLParamData(SQLHSTMT stmt, + SQLPOINTER* value) +{ + LOG_MSG("SQLParamData called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLPutData(SQLHSTMT stmt, + SQLPOINTER data, + SQLLEN strLengthOrIndicator) +{ + LOG_MSG("SQLPutData called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetConnectOption(SQLHDBC conn, + SQLUSMALLINT option, + SQLULEN value) +{ + LOG_MSG("SQLSetConnectOption called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetStmtOption(SQLHSTMT stmt, + SQLUSMALLINT option, + SQLULEN value) +{ + LOG_MSG("SQLSetStmtOption called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLStatistics(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLUSMALLINT unique, + SQLUSMALLINT reserved) +{ + LOG_MSG("SQLStatistics called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLBrowseConnect(SQLHDBC conn, + SQLCHAR* inConnectionStr, + SQLSMALLINT inConnectionStrLen, + SQLCHAR* outConnectionStrBuf, + SQLSMALLINT outConnectionStrBufLen, + SQLSMALLINT* outConnectionStrResLen) +{ + LOG_MSG("SQLBrowseConnect called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLProcedureColumns(SQLHSTMT stmt, + SQLCHAR * catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR * schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR * procName, + SQLSMALLINT procNameLen, + SQLCHAR * columnName, + SQLSMALLINT columnNameLen) +{ + LOG_MSG("SQLProcedureColumns called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetPos(SQLHSTMT stmt, + SQLSETPOSIROW rowNum, + SQLUSMALLINT operation, + SQLUSMALLINT lockType) +{ + LOG_MSG("SQLSetPos called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetScrollOptions(SQLHSTMT stmt, + SQLUSMALLINT concurrency, + SQLLEN crowKeyset, + SQLUSMALLINT crowRowset) +{ + LOG_MSG("SQLSetScrollOptions called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetConnectAttr(SQLHDBC conn, + SQLINTEGER attr, + SQLPOINTER valueBuf, + SQLINTEGER valueBufLen, + SQLINTEGER* valueResLen) +{ + LOG_MSG("SQLGetConnectAttr called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC conn, + SQLINTEGER attr, + SQLPOINTER value, + SQLINTEGER valueLen) +{ + using ignite::odbc::Connection; + + LOG_MSG("SQLSetConnectAttr called\n"); + + Connection *connection = reinterpret_cast<Connection*>(conn); + + if (!connection) + return SQL_INVALID_HANDLE; + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLBulkOperations(SQLHSTMT stmt, + SQLUSMALLINT operation) +{ + LOG_MSG("SQLBulkOperations called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLTablePrivileges(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen) +{ + LOG_MSG("SQLTablePrivileges called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLCopyDesc(SQLHDESC src, SQLHDESC dst) +{ + LOG_MSG("SQLCopyDesc called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetDescField(SQLHDESC descr, + SQLSMALLINT recNum, + SQLSMALLINT fieldId, + SQLPOINTER buffer, + SQLINTEGER bufferLen, + SQLINTEGER* resLen) +{ + LOG_MSG("SQLGetDescField called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLGetDescRec(SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLCHAR* nameBuffer, + SQLSMALLINT nameBufferLen, + SQLSMALLINT* strLen, + SQLSMALLINT* type, + SQLSMALLINT* subType, + SQLLEN* len, + SQLSMALLINT* precision, + SQLSMALLINT* scale, + SQLSMALLINT* nullable) +{ + LOG_MSG("SQLGetDescRec called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetDescField(SQLHDESC descr, + SQLSMALLINT recNum, + SQLSMALLINT fieldId, + SQLPOINTER buffer, + SQLINTEGER bufferLen) +{ + LOG_MSG("SQLSetDescField called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLSetDescRec(SQLHDESC descr, + SQLSMALLINT recNum, + SQLSMALLINT type, + SQLSMALLINT subType, + SQLLEN len, + SQLSMALLINT precision, + SQLSMALLINT scale, + SQLPOINTER buffer, + SQLLEN* resLen, + SQLLEN* id) +{ + LOG_MSG("SQLSetDescRec called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLColumnPrivileges(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLCHAR* columnName, + SQLSMALLINT columnNameLen) +{ + LOG_MSG("SQLColumnPrivileges called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLDescribeParam(SQLHSTMT stmt, + SQLUSMALLINT paramNum, + SQLSMALLINT* dataType, + SQLULEN* paramSize, + SQLSMALLINT* decimalDigits, + SQLSMALLINT* nullable) +{ + LOG_MSG("SQLDescribeParam called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLParamOptions(SQLHSTMT stmt, + SQLULEN paramSetSize, + SQLULEN* paramsProcessed) +{ + LOG_MSG("SQLParamOptions called\n"); + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLProcedures(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen) +{ + LOG_MSG("SQLProcedures called\n"); + return SQL_SUCCESS; +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp new file mode 100644 index 0000000..69a08b1 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp @@ -0,0 +1,317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ignite/impl/binary/binary_common.h> + +#include "ignite/odbc/type_traits.h" +#include "ignite/odbc/connection.h" +#include "ignite/odbc/message.h" +#include "ignite/odbc/query/column_metadata_query.h" + +namespace +{ + enum ResultColumn + { + /** Catalog name. NULL if not applicable to the data source. */ + TABLE_CAT = 1, + + /** Schema name. NULL if not applicable to the data source. */ + TABLE_SCHEM, + + /** Table name. */ + TABLE_NAME, + + /** Column name. */ + COLUMN_NAME, + + /** SQL data type. */ + DATA_TYPE, + + /** Data source�dependent data type name. */ + TYPE_NAME, + + /** Column size. */ + COLUMN_SIZE, + + /** The length in bytes of data transferred on fetch. */ + BUFFER_LENGTH, + + /** The total number of significant digits to the right of the decimal point. */ + DECIMAL_DIGITS, + + /** Precision. */ + NUM_PREC_RADIX, + + /** Nullability of the data in column. */ + NULLABLE, + + /** A description of the column. */ + REMARKS + }; +} + +namespace ignite +{ + namespace odbc + { + namespace query + { + ColumnMetadataQuery::ColumnMetadataQuery(diagnostic::Diagnosable& diag, + Connection& connection, const std::string& schema, + const std::string& table, const std::string& column) : + Query(diag), + connection(connection), + schema(schema), + table(table), + column(column), + executed(false), + meta(), + columnsMeta() + { + using namespace ignite::impl::binary; + using namespace ignite::odbc::type_traits; + + using meta::ColumnMeta; + + columnsMeta.reserve(12); + + const std::string sch(""); + const std::string tbl(""); + + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_CAT", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "DATA_TYPE", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "TYPE_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_SIZE", SqlTypeName::INTEGER, IGNITE_TYPE_INT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "BUFFER_LENGTH", SqlTypeName::INTEGER, IGNITE_TYPE_INT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "DECIMAL_DIGITS", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "NUM_PREC_RADIX", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "NULLABLE", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "REMARKS", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + } + + ColumnMetadataQuery::~ColumnMetadataQuery() + { + // No-op. + } + + SqlResult ColumnMetadataQuery::Execute() + { + if (executed) + Close(); + + SqlResult result = MakeRequestGetColumnsMeta(); + + if (result == SQL_RESULT_SUCCESS) + { + executed = true; + + cursor = meta.begin(); + } + + return result; + } + + const meta::ColumnMetaVector& ColumnMetadataQuery::GetMeta() const + { + return columnsMeta; + } + + SqlResult ColumnMetadataQuery::FetchNextRow(app::ColumnBindingMap & columnBindings) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + if (cursor == meta.end()) + return SQL_RESULT_NO_DATA; + + app::ColumnBindingMap::iterator it; + + for (it = columnBindings.begin(); it != columnBindings.end(); ++it) + GetColumn(it->first, it->second); + + ++cursor; + + return SQL_RESULT_SUCCESS; + } + + SqlResult ColumnMetadataQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer & buffer) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + if (cursor == meta.end()) + return SQL_RESULT_NO_DATA; + + const meta::ColumnMeta& currentColumn = *cursor; + uint8_t columnType = currentColumn.GetDataType(); + + switch (columnIdx) + { + case TABLE_CAT: + { + buffer.PutNull(); + break; + } + + case TABLE_SCHEM: + { + buffer.PutString(currentColumn.GetSchemaName()); + break; + } + + case TABLE_NAME: + { + buffer.PutString(currentColumn.GetTableName()); + break; + } + + case COLUMN_NAME: + { + buffer.PutString(currentColumn.GetColumnName()); + break; + } + + case DATA_TYPE: + { + buffer.PutInt16(type_traits::BinaryToSqlType(columnType)); + break; + } + + case TYPE_NAME: + { + buffer.PutString(currentColumn.GetColumnTypeName()); + break; + } + + case COLUMN_SIZE: + { + buffer.PutInt16(type_traits::BinaryTypeColumnSize(columnType)); + break; + } + + case BUFFER_LENGTH: + { + buffer.PutInt16(type_traits::BinaryTypeTransferLength(columnType)); + break; + } + + case DECIMAL_DIGITS: + { + int32_t decDigits = type_traits::BinaryTypeDecimalDigits(columnType); + if (decDigits < 0) + buffer.PutNull(); + else + buffer.PutInt16(static_cast<int16_t>(decDigits)); + break; + } + + case NUM_PREC_RADIX: + { + buffer.PutInt16(type_traits::BinaryTypeNumPrecRadix(columnType)); + break; + } + + case NULLABLE: + { + buffer.PutInt16(type_traits::BinaryTypeNullability(columnType)); + break; + } + + case REMARKS: + { + buffer.PutNull(); + break; + } + + default: + break; + } + + return SQL_RESULT_SUCCESS; + } + + SqlResult ColumnMetadataQuery::Close() + { + meta.clear(); + + executed = false; + + return SQL_RESULT_SUCCESS; + } + + bool ColumnMetadataQuery::DataAvailable() const + { + return cursor != meta.end(); + } + + int64_t ColumnMetadataQuery::AffectedRows() const + { + return 0; + } + + SqlResult ColumnMetadataQuery::MakeRequestGetColumnsMeta() + { + QueryGetColumnsMetaRequest req(schema, table, column); + QueryGetColumnsMetaResponse rsp; + + bool success = connection.SyncMessage(req, rsp); + + if (!success) + { + diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated."); + + return SQL_RESULT_ERROR; + } + + if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS) + { + LOG_MSG("Error: %s\n", rsp.GetError().c_str()); + + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError()); + + return SQL_RESULT_ERROR; + } + + meta = rsp.GetMeta(); + + for (size_t i = 0; i < meta.size(); ++i) + { + LOG_MSG("[%d] SchemaName: %s\n", i, meta[i].GetSchemaName().c_str()); + LOG_MSG("[%d] TableName: %s\n", i, meta[i].GetTableName().c_str()); + LOG_MSG("[%d] ColumnName: %s\n", i, meta[i].GetColumnName().c_str()); + LOG_MSG("[%d] ColumnTypeName: %s\n", i, meta[i].GetColumnTypeName().c_str()); + LOG_MSG("[%d] ColumnType: %d\n", i, meta[i].GetDataType()); + LOG_MSG("\n"); + } + + return SQL_RESULT_SUCCESS; + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/data_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/data_query.cpp b/modules/platforms/cpp/odbc/src/query/data_query.cpp new file mode 100644 index 0000000..4e9239b --- /dev/null +++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp @@ -0,0 +1,277 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ignite/odbc/connection.h" +#include "ignite/odbc/message.h" +#include "ignite/odbc/query/data_query.h" + +namespace ignite +{ + namespace odbc + { + namespace query + { + DataQuery::DataQuery(diagnostic::Diagnosable& diag, + Connection& connection, const std::string& sql, + const app::ParameterBindingMap& params) : + Query(diag), + connection(connection), + sql(sql), + params(params) + { + // No-op. + } + + DataQuery::~DataQuery() + { + Close(); + } + + SqlResult DataQuery::Execute() + { + if (cursor.get()) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query cursor is in open state already."); + + return SQL_RESULT_ERROR; + } + + return MakeRequestExecute(); + } + + const meta::ColumnMetaVector & DataQuery::GetMeta() const + { + return resultMeta; + } + + SqlResult DataQuery::FetchNextRow(app::ColumnBindingMap& columnBindings) + { + if (!cursor.get()) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + if (!cursor->HasNext()) + return SQL_RESULT_NO_DATA; + + if (cursor->NeedDataUpdate()) + { + SqlResult result = MakeRequestFetch(); + + if (result != SQL_RESULT_SUCCESS) + return result; + + if (!cursor->HasNext()) + return SQL_RESULT_NO_DATA; + } + else + cursor->Increment(); + + Row* row = cursor->GetRow(); + + if (!row) + { + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Unknown error."); + + return SQL_RESULT_ERROR; + } + + for (int32_t i = 1; i < row->GetSize() + 1; ++i) + { + app::ColumnBindingMap::iterator it = columnBindings.find(i); + + SqlResult result; + + if (it != columnBindings.end()) + result = row->ReadColumnToBuffer(i, it->second); + + if (result == SQL_RESULT_ERROR) + { + diag.AddStatusRecord(SQL_STATE_01S01_ERROR_IN_ROW, "Can not retrieve row column.", 0, i); + + return SQL_RESULT_ERROR; + } + } + + return SQL_RESULT_SUCCESS; + } + + SqlResult DataQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer) + { + if (!cursor.get()) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + Row* row = cursor->GetRow(); + + if (!row) + return SQL_RESULT_NO_DATA; + + SqlResult result = row->ReadColumnToBuffer(columnIdx, buffer); + + if (result == SQL_RESULT_ERROR) + { + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Unknown column type."); + + return SQL_RESULT_ERROR; + } + + return result; + } + + SqlResult DataQuery::Close() + { + if (!cursor.get()) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query cursor is not in open state."); + + return SQL_RESULT_ERROR; + } + + SqlResult result = MakeRequestClose(); + + if (result == SQL_RESULT_SUCCESS) + cursor.reset(); + + return result; + } + + bool DataQuery::DataAvailable() const + { + return cursor.get() && cursor->HasNext(); + } + + int64_t DataQuery::AffectedRows() const + { + // We are only support SELECT statements so we should not + // return anything particullar. + return 0; + } + + SqlResult DataQuery::MakeRequestExecute() + { + const std::string& cacheName = connection.GetCache(); + + QueryExecuteRequest req(cacheName, sql, params); + QueryExecuteResponse rsp; + + bool success = connection.SyncMessage(req, rsp); + + if (!success) + { + diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated."); + + return SQL_RESULT_ERROR; + } + + if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS) + { + LOG_MSG("Error: %s\n", rsp.GetError().c_str()); + + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError()); + + return SQL_RESULT_ERROR; + } + + cursor.reset(new Cursor(rsp.GetQueryId())); + + resultMeta.assign(rsp.GetMeta().begin(), rsp.GetMeta().end()); + + LOG_MSG("Query id: %lld\n", cursor->GetQueryId()); + + for (size_t i = 0; i < rsp.GetMeta().size(); ++i) + { + LOG_MSG("[%d] SchemaName: %s\n", i, rsp.GetMeta()[i].GetSchemaName().c_str()); + LOG_MSG("[%d] TypeName: %s\n", i, rsp.GetMeta()[i].GetTableName().c_str()); + LOG_MSG("[%d] ColumnName: %s\n", i, rsp.GetMeta()[i].GetColumnName().c_str()); + LOG_MSG("[%d] ColumnTypeName: %s\n", i, rsp.GetMeta()[i].GetColumnTypeName().c_str()); + LOG_MSG("[%d] ColumnType: %d\n", i, rsp.GetMeta()[i].GetDataType()); + LOG_MSG("\n"); + } + + return SQL_RESULT_SUCCESS; + } + + SqlResult DataQuery::MakeRequestClose() + { + QueryCloseRequest req(cursor->GetQueryId()); + QueryCloseResponse rsp; + + bool success = connection.SyncMessage(req, rsp); + + if (!success) + { + diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated."); + + return SQL_RESULT_ERROR; + } + + LOG_MSG("Query id: %lld\n", rsp.GetQueryId()); + + if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS) + { + LOG_MSG("Error: %s\n", rsp.GetError().c_str()); + + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError()); + + return SQL_RESULT_ERROR; + } + + return SQL_RESULT_SUCCESS; + } + + SqlResult DataQuery::MakeRequestFetch() + { + std::auto_ptr<ResultPage> resultPage(new ResultPage()); + + QueryFetchRequest req(cursor->GetQueryId(), ResultPage::DEFAULT_SIZE); + QueryFetchResponse rsp(*resultPage); + + bool success = connection.SyncMessage(req, rsp); + + LOG_MSG("Query id: %lld\n", rsp.GetQueryId()); + LOG_MSG("Request status: %s\n", success ? "Success" : "Failure"); + + if (!success) + { + diag.AddStatusRecord(SQL_STATE_HYT01_CONNECTIOIN_TIMEOUT, "Connection terminated."); + + return SQL_RESULT_ERROR; + } + + if (rsp.GetStatus() != RESPONSE_STATUS_SUCCESS) + { + LOG_MSG("Error: %s\n", rsp.GetError().c_str()); + + diag.AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, rsp.GetError()); + + return SQL_RESULT_ERROR; + } + + cursor->UpdateData(resultPage); + + return SQL_RESULT_SUCCESS; + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp b/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp new file mode 100644 index 0000000..78e1464 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/query/foreign_keys_query.cpp @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ignite/impl/binary/binary_common.h> + +#include "ignite/odbc/type_traits.h" +#include "ignite/odbc/connection.h" +#include "ignite/odbc/message.h" +#include "ignite/odbc/query/foreign_keys_query.h" + +namespace ignite +{ + namespace odbc + { + namespace query + { + ForeignKeysQuery::ForeignKeysQuery(diagnostic::Diagnosable& diag, Connection& connection, + const std::string& primaryCatalog, const std::string& primarySchema, + const std::string& primaryTable, const std::string& foreignCatalog, + const std::string& foreignSchema, const std::string& foreignTable) : + Query(diag), + connection(connection), + primaryCatalog(primaryCatalog), + primarySchema(primarySchema), + primaryTable(primaryTable), + foreignCatalog(foreignCatalog), + foreignSchema(foreignSchema), + foreignTable(foreignTable), + executed(false), + columnsMeta() + { + using namespace ignite::impl::binary; + using namespace ignite::odbc::type_traits; + + using meta::ColumnMeta; + + columnsMeta.reserve(14); + + const std::string sch(""); + const std::string tbl(""); + + columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_CAT", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_SCHEM", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "PKTABLE_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "PKCOLUMN_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_CAT", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_SCHEM", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "FKTABLE_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "FKCOLUMN_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "UPDATE_RULE", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "DELETE_RULE", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "FK_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "DEFERRABILITY", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + } + + ForeignKeysQuery::~ForeignKeysQuery() + { + // No-op. + } + + SqlResult ForeignKeysQuery::Execute() + { + executed = true; + + return SQL_RESULT_SUCCESS; + } + + const meta::ColumnMetaVector & ForeignKeysQuery::GetMeta() const + { + return columnsMeta; + } + + SqlResult ForeignKeysQuery::FetchNextRow(app::ColumnBindingMap & columnBindings) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + return SQL_RESULT_NO_DATA; + } + + SqlResult ForeignKeysQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + return SQL_RESULT_NO_DATA; + } + + SqlResult ForeignKeysQuery::Close() + { + executed = false; + + return SQL_RESULT_SUCCESS; + } + + bool ForeignKeysQuery::DataAvailable() const + { + return false; + } + int64_t ForeignKeysQuery::AffectedRows() const + { + return 0; + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/e8287063/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp b/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp new file mode 100644 index 0000000..b616db3 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/query/primary_keys_query.cpp @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ignite/impl/binary/binary_common.h> + +#include "ignite/odbc/type_traits.h" +#include "ignite/odbc/connection.h" +#include "ignite/odbc/message.h" +#include "ignite/odbc/query/primary_keys_query.h" + +namespace +{ + enum ResultColumn + { + /** Catalog name. NULL if not applicable to the data source. */ + TABLE_CAT = 1, + + /** Schema name. NULL if not applicable to the data source. */ + TABLE_SCHEM, + + /** Table name. */ + TABLE_NAME, + + /** Column name. */ + COLUMN_NAME, + + /** Column sequence number in key. */ + KEY_SEQ, + + /** Primary key name. */ + PK_NAME + }; +} + +namespace ignite +{ + namespace odbc + { + namespace query + { + PrimaryKeysQuery::PrimaryKeysQuery(diagnostic::Diagnosable& diag, + Connection& connection, const std::string& catalog, + const std::string& schema, const std::string& table) : + Query(diag), + connection(connection), + catalog(catalog), + schema(schema), + table(table), + executed(false), + columnsMeta() + { + using namespace ignite::impl::binary; + using namespace ignite::odbc::type_traits; + + using meta::ColumnMeta; + + columnsMeta.reserve(6); + + const std::string sch(""); + const std::string tbl(""); + + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_CAT", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_SCHEM", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "TABLE_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "COLUMN_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "KEY_SEQ", SqlTypeName::SMALLINT, IGNITE_TYPE_SHORT)); + columnsMeta.push_back(ColumnMeta(sch, tbl, "PK_NAME", SqlTypeName::VARCHAR, IGNITE_TYPE_STRING)); + } + + PrimaryKeysQuery::~PrimaryKeysQuery() + { + // No-op. + } + + SqlResult PrimaryKeysQuery::Execute() + { + if (executed) + Close(); + + meta.push_back(meta::PrimaryKeyMeta(catalog, schema, table, "_KEY", 1, "_KEY")); + + executed = true; + + cursor = meta.begin(); + + return SQL_RESULT_SUCCESS; + } + + const meta::ColumnMetaVector & PrimaryKeysQuery::GetMeta() const + { + return columnsMeta; + } + + SqlResult PrimaryKeysQuery::FetchNextRow(app::ColumnBindingMap & columnBindings) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + if (cursor == meta.end()) + return SQL_RESULT_NO_DATA; + + app::ColumnBindingMap::iterator it; + + for (it = columnBindings.begin(); it != columnBindings.end(); ++it) + GetColumn(it->first, it->second); + + ++cursor; + + return SQL_RESULT_SUCCESS; + } + + SqlResult PrimaryKeysQuery::GetColumn(uint16_t columnIdx, app::ApplicationDataBuffer& buffer) + { + if (!executed) + { + diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query was not executed."); + + return SQL_RESULT_ERROR; + } + + if (cursor == meta.end()) + return SQL_RESULT_NO_DATA; + + const meta::PrimaryKeyMeta& currentColumn = *cursor; + + switch (columnIdx) + { + case TABLE_CAT: + { + buffer.PutString(currentColumn.GetCatalogName()); + break; + } + + case TABLE_SCHEM: + { + buffer.PutString(currentColumn.GetSchemaName()); + break; + } + + case TABLE_NAME: + { + buffer.PutString(currentColumn.GetTableName()); + break; + } + + case COLUMN_NAME: + { + buffer.PutString(currentColumn.GetColumnName()); + break; + } + + case KEY_SEQ: + { + buffer.PutInt16(currentColumn.GetKeySeq()); + break; + } + + case PK_NAME: + { + buffer.PutString(currentColumn.GetKeyName()); + break; + } + + default: + break; + } + + return SQL_RESULT_SUCCESS; + } + + SqlResult PrimaryKeysQuery::Close() + { + meta.clear(); + + executed = false; + + return SQL_RESULT_SUCCESS; + } + + bool PrimaryKeysQuery::DataAvailable() const + { + return cursor != meta.end(); + } + + int64_t PrimaryKeysQuery::AffectedRows() const + { + return 0; + } + } + } +} +
