blob: f297ec44e99352c2d60ea2f47108e602ee27d6fd [file] [log] [blame]
/*
* 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/log.h"
#include "ignite/odbc/utility.h"
#include "ignite/odbc/system/odbc_constants.h"
#include "ignite/odbc/config/connection_string_parser.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/dsn_config.h"
#include "ignite/odbc.h"
namespace ignite
{
SQLRETURN SQLGetInfo(SQLHDBC conn,
SQLUSMALLINT infoType,
SQLPOINTER infoValue,
SQLSMALLINT infoValueMax,
SQLSMALLINT* length)
{
using odbc::Connection;
using odbc::config::ConnectionInfo;
LOG_MSG("SQLGetInfo called: "
<< infoType << " (" << ConnectionInfo::InfoTypeToString(infoType) << "), "
<< std::hex << reinterpret_cast<size_t>(infoValue) << ", " << infoValueMax << ", "
<< std::hex << reinterpret_cast<size_t>(length));
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->GetInfo(infoType, infoValue, infoValueMax, length);
return connection->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result)
{
//LOG_MSG("SQLAllocHandle called");
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:
{
using odbc::Connection;
Connection *connection = reinterpret_cast<Connection*>(parent);
if (!connection)
return SQL_INVALID_HANDLE;
if (result)
*result = 0;
connection->GetDiagnosticRecords().Reset();
connection->AddStatusRecord(odbc::SqlState::SIM001_FUNCTION_NOT_SUPPORTED,
"The HandleType argument was SQL_HANDLE_DESC, and "
"the driver does not support allocating a descriptor handle");
return SQL_ERROR;
}
default:
break;
}
*result = 0;
return SQL_ERROR;
}
SQLRETURN SQLAllocEnv(SQLHENV* env)
{
using odbc::Environment;
LOG_MSG("SQLAllocEnv called");
*env = reinterpret_cast<SQLHENV>(new Environment());
return SQL_SUCCESS;
}
SQLRETURN SQLAllocConnect(SQLHENV env, SQLHDBC* conn)
{
using odbc::Environment;
using odbc::Connection;
LOG_MSG("SQLAllocConnect called");
*conn = SQL_NULL_HDBC;
Environment *environment = reinterpret_cast<Environment*>(env);
if (!environment)
return SQL_INVALID_HANDLE;
Connection *connection = environment->CreateConnection();
if (!connection)
return environment->GetDiagnosticRecords().GetReturnCode();
*conn = reinterpret_cast<SQLHDBC>(connection);
return SQL_SUCCESS;
}
SQLRETURN SQLAllocStmt(SQLHDBC conn, SQLHSTMT* stmt)
{
using odbc::Connection;
using odbc::Statement;
LOG_MSG("SQLAllocStmt called");
*stmt = SQL_NULL_HDBC;
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
Statement *statement = connection->CreateStatement();
*stmt = reinterpret_cast<SQLHSTMT>(statement);
return connection->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle)
{
switch (type)
{
case SQL_HANDLE_ENV:
return SQLFreeEnv(handle);
case SQL_HANDLE_DBC:
return SQLFreeConnect(handle);
case SQL_HANDLE_STMT:
return SQLFreeStmt(handle, SQL_DROP);
case SQL_HANDLE_DESC:
default:
break;
}
return SQL_ERROR;
}
SQLRETURN SQLFreeEnv(SQLHENV env)
{
using odbc::Environment;
LOG_MSG("SQLFreeEnv called: " << env);
Environment *environment = reinterpret_cast<Environment*>(env);
if (!environment)
return SQL_INVALID_HANDLE;
delete environment;
return SQL_SUCCESS;
}
SQLRETURN SQLFreeConnect(SQLHDBC conn)
{
using odbc::Connection;
LOG_MSG("SQLFreeConnect called");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->Deregister();
delete connection;
return SQL_SUCCESS;
}
SQLRETURN SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option)
{
using odbc::Statement;
LOG_MSG("SQLFreeStmt called [option=" << option << ']');
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
if (option == SQL_DROP)
{
delete statement;
return SQL_SUCCESS;
}
statement->FreeResources(option);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLCloseCursor(SQLHSTMT stmt)
{
using odbc::Statement;
LOG_MSG("SQLCloseCursor called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
statement->Close();
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLDriverConnect(SQLHDBC conn,
SQLHWND windowHandle,
SQLCHAR* inConnectionString,
SQLSMALLINT inConnectionStringLen,
SQLCHAR* outConnectionString,
SQLSMALLINT outConnectionStringBufferLen,
SQLSMALLINT* outConnectionStringLen,
SQLUSMALLINT driverCompletion)
{
IGNITE_UNUSED(driverCompletion);
using odbc::Connection;
using odbc::diagnostic::DiagnosticRecordStorage;
using utility::SqlStringToString;
using utility::CopyStringToBuffer;
UNREFERENCED_PARAMETER(windowHandle);
LOG_MSG("SQLDriverConnect called");
if (inConnectionString)
LOG_MSG("Connection String: [" << inConnectionString << "]");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
std::string connectStr = SqlStringToString(inConnectionString, inConnectionStringLen);
connection->Establish(connectStr);
const DiagnosticRecordStorage& diag = connection->GetDiagnosticRecords();
if (!diag.IsSuccessful())
return diag.GetReturnCode();
size_t reslen = CopyStringToBuffer(connectStr,
reinterpret_cast<char*>(outConnectionString),
static_cast<size_t>(outConnectionStringBufferLen));
if (outConnectionStringLen)
*outConnectionStringLen = static_cast<SQLSMALLINT>(reslen);
if (outConnectionString)
LOG_MSG(outConnectionString);
return diag.GetReturnCode();
}
SQLRETURN SQLConnect(SQLHDBC conn,
SQLCHAR* serverName,
SQLSMALLINT serverNameLen,
SQLCHAR* userName,
SQLSMALLINT userNameLen,
SQLCHAR* auth,
SQLSMALLINT authLen)
{
IGNITE_UNUSED(userName);
IGNITE_UNUSED(userNameLen);
IGNITE_UNUSED(auth);
IGNITE_UNUSED(authLen);
using odbc::Connection;
using odbc::config::Configuration;
using utility::SqlStringToString;
LOG_MSG("SQLConnect called\n");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
odbc::config::Configuration config;
std::string dsn = SqlStringToString(serverName, serverNameLen);
LOG_MSG("DSN: " << dsn);
odbc::ReadDsnConfiguration(dsn.c_str(), config, &connection->GetDiagnosticRecords());
connection->Establish(config);
return connection->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLDisconnect(SQLHDBC conn)
{
using odbc::Connection;
LOG_MSG("SQLDisconnect called");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->Release();
return connection->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen)
{
using odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLPrepare called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string sql = SqlStringToString(query, queryLen);
LOG_MSG("SQL: " << sql);
statement->PrepareSqlQuery(sql);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLExecute(SQLHSTMT stmt)
{
using odbc::Statement;
LOG_MSG("SQLExecute called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->ExecuteSqlQuery();
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen)
{
using odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLExecDirect called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string sql = SqlStringToString(query, queryLen);
LOG_MSG("SQL: " << sql);
statement->ExecuteSqlQuery(sql);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLBindCol(SQLHSTMT stmt,
SQLUSMALLINT colNum,
SQLSMALLINT targetType,
SQLPOINTER targetValue,
SQLLEN bufferLength,
SQLLEN* strLengthOrIndicator)
{
using namespace odbc::type_traits;
using odbc::Statement;
using odbc::app::ApplicationDataBuffer;
LOG_MSG("SQLBindCol called: index=" << colNum << ", type=" << targetType <<
", targetValue=" << reinterpret_cast<size_t>(targetValue) <<
", bufferLength=" << bufferLength <<
", lengthInd=" << reinterpret_cast<size_t>(strLengthOrIndicator));
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->BindColumn(colNum, targetType, targetValue, bufferLength, strLengthOrIndicator);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLFetch(SQLHSTMT stmt)
{
using odbc::Statement;
LOG_MSG("SQLFetch called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->FetchRow();
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orientation, SQLLEN offset)
{
using odbc::Statement;
LOG_MSG("SQLFetchScroll called");
LOG_MSG("Orientation: " << orientation << " Offset: " << offset);
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->FetchScroll(orientation, offset);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLExtendedFetch(SQLHSTMT stmt,
SQLUSMALLINT orientation,
SQLLEN offset,
SQLULEN* rowCount,
SQLUSMALLINT* rowStatusArray)
{
LOG_MSG("SQLExtendedFetch called");
SQLRETURN res = SQLFetchScroll(stmt, orientation, offset);
if (res == SQL_SUCCESS)
{
if (rowCount)
*rowCount = 1;
if (rowStatusArray)
rowStatusArray[0] = SQL_ROW_SUCCESS;
}
else if (res == SQL_NO_DATA && rowCount)
*rowCount = 0;
return res;
}
SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *columnNum)
{
using odbc::Statement;
using odbc::meta::ColumnMetaVector;
LOG_MSG("SQLNumResultCols called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
int32_t res = statement->GetColumnNumber();
if (columnNum)
{
*columnNum = static_cast<SQLSMALLINT>(res);
LOG_MSG("columnNum: " << *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 odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLTables called");
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: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
LOG_MSG("tableType: " << tableTypeStr);
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 odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLColumns called");
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: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
LOG_MSG("column: " << column);
statement->ExecuteGetColumnsMetaQuery(schema, table, column);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLMoreResults(SQLHSTMT stmt)
{
using odbc::Statement;
LOG_MSG("SQLMoreResults called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->MoreResults();
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLBindParameter(SQLHSTMT stmt,
SQLUSMALLINT paramIdx,
SQLSMALLINT ioType,
SQLSMALLINT bufferType,
SQLSMALLINT paramSqlType,
SQLULEN columnSize,
SQLSMALLINT decDigits,
SQLPOINTER buffer,
SQLLEN bufferLen,
SQLLEN* resLen)
{
using odbc::Statement;
LOG_MSG("SQLBindParameter called: " << paramIdx << ", " << bufferType << ", " << paramSqlType);
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->BindParameter(paramIdx, ioType, bufferType, paramSqlType, columnSize, decDigits, buffer, bufferLen, resLen);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLNativeSql(SQLHDBC conn,
SQLCHAR* inQuery,
SQLINTEGER inQueryLen,
SQLCHAR* outQueryBuffer,
SQLINTEGER outQueryBufferLen,
SQLINTEGER* outQueryLen)
{
IGNITE_UNUSED(conn);
using namespace utility;
LOG_MSG("SQLNativeSql called");
std::string in = SqlStringToString(inQuery, inQueryLen);
CopyStringToBuffer(in, reinterpret_cast<char*>(outQueryBuffer),
static_cast<size_t>(outQueryBufferLen));
if (outQueryLen)
*outQueryLen = std::min(outQueryBufferLen, static_cast<SQLINTEGER>(in.size()));
return SQL_SUCCESS;
}
SQLRETURN SQLColAttribute(SQLHSTMT stmt,
SQLUSMALLINT columnNum,
SQLUSMALLINT fieldId,
SQLPOINTER strAttr,
SQLSMALLINT bufferLen,
SQLSMALLINT* strAttrLen,
SQLLEN* numericAttr)
{
using odbc::Statement;
using odbc::meta::ColumnMetaVector;
using odbc::meta::ColumnMeta;
LOG_MSG("SQLColAttribute called: " << 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 (numericAttr && res == SQL_SUCCESS)
*numericAttr = val;
return res;
}
statement->GetColumnAttribute(columnNum, fieldId, reinterpret_cast<char*>(strAttr),
bufferLen, strAttrLen, numericAttr);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLDescribeCol(SQLHSTMT stmt,
SQLUSMALLINT columnNum,
SQLCHAR* columnNameBuf,
SQLSMALLINT columnNameBufLen,
SQLSMALLINT* columnNameLen,
SQLSMALLINT* dataType,
SQLULEN* columnSize,
SQLSMALLINT* decimalDigits,
SQLSMALLINT* nullable)
{
using odbc::Statement;
using odbc::SqlLen;
LOG_MSG("SQLDescribeCol called");
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: " << columnNum);
LOG_MSG("dataTypeRes: " << dataTypeRes);
LOG_MSG("columnSizeRes: " << columnSizeRes);
LOG_MSG("decimalDigitsRes: " << decimalDigitsRes);
LOG_MSG("nullableRes: " << nullableRes);
LOG_MSG("columnNameBuf: " << (columnNameBuf ? reinterpret_cast<const char*>(columnNameBuf) : "<null>"));
LOG_MSG("columnNameLen: " << (columnNameLen ? *columnNameLen : -1));
if (dataType)
*dataType = static_cast<SQLSMALLINT>(dataTypeRes);
if (columnSize)
*columnSize = static_cast<SQLULEN>(columnSizeRes);
if (decimalDigits)
*decimalDigits = static_cast<SQLSMALLINT>(decimalDigitsRes);
if (nullable)
*nullable = static_cast<SQLSMALLINT>(nullableRes);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCnt)
{
using odbc::Statement;
LOG_MSG("SQLRowCount called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
int64_t res = statement->AffectedRows();
LOG_MSG("Row count: " << res);
if (rowCnt)
*rowCnt = static_cast<SQLLEN>(res);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLForeignKeys(SQLHSTMT stmt,
SQLCHAR* primaryCatalogName,
SQLSMALLINT primaryCatalogNameLen,
SQLCHAR* primarySchemaName,
SQLSMALLINT primarySchemaNameLen,
SQLCHAR* primaryTableName,
SQLSMALLINT primaryTableNameLen,
SQLCHAR* foreignCatalogName,
SQLSMALLINT foreignCatalogNameLen,
SQLCHAR* foreignSchemaName,
SQLSMALLINT foreignSchemaNameLen,
SQLCHAR* foreignTableName,
SQLSMALLINT foreignTableNameLen)
{
using odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLForeignKeys called");
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: " << primaryCatalog);
LOG_MSG("primarySchema: " << primarySchema);
LOG_MSG("primaryTable: " << primaryTable);
LOG_MSG("foreignCatalog: " << foreignCatalog);
LOG_MSG("foreignSchema: " << foreignSchema);
LOG_MSG("foreignTable: " << foreignTable);
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 odbc::Statement;
LOG_MSG("SQLGetStmtAttr called");
#ifdef _DEBUG
using odbc::type_traits::StatementAttrIdToString;
LOG_MSG("Attr: " << StatementAttrIdToString(attr) << " (" << attr << ")");
#endif //_DEBUG
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->GetAttribute(attr, valueBuf, valueBufLen, valueResLen);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt,
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER valueLen)
{
using odbc::Statement;
LOG_MSG("SQLSetStmtAttr called: " << attr);
#ifdef _DEBUG
using odbc::type_traits::StatementAttrIdToString;
LOG_MSG("Attr: " << StatementAttrIdToString(attr) << " (" << attr << ")");
#endif //_DEBUG
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->SetAttribute(attr, value, valueLen);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLPrimaryKeys(SQLHSTMT stmt,
SQLCHAR* catalogName,
SQLSMALLINT catalogNameLen,
SQLCHAR* schemaName,
SQLSMALLINT schemaNameLen,
SQLCHAR* tableName,
SQLSMALLINT tableNameLen)
{
using odbc::Statement;
using utility::SqlStringToString;
LOG_MSG("SQLPrimaryKeys called");
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: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
statement->ExecuteGetPrimaryKeysQuery(catalog, schema, table);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLNumParams(SQLHSTMT stmt, SQLSMALLINT* paramCnt)
{
using odbc::Statement;
LOG_MSG("SQLNumParams called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
if (paramCnt)
{
uint16_t paramNum = 0;
statement->GetParametersNumber(paramNum);
*paramCnt = static_cast<SQLSMALLINT>(paramNum);
}
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLGetDiagField(SQLSMALLINT handleType,
SQLHANDLE handle,
SQLSMALLINT recNum,
SQLSMALLINT diagId,
SQLPOINTER buffer,
SQLSMALLINT bufferLen,
SQLSMALLINT* resLen)
{
using namespace odbc;
using namespace odbc::diagnostic;
using namespace odbc::type_traits;
using odbc::app::ApplicationDataBuffer;
LOG_MSG("SQLGetDiagField called: " << recNum);
SqlLen outResLen;
ApplicationDataBuffer outBuffer(OdbcNativeType::AI_DEFAULT, buffer, bufferLen, &outResLen);
SqlResult::Type result;
DiagnosticField::Type 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 = SqlResult::AI_NO_DATA;
break;
}
}
if (resLen && result == SqlResult::AI_SUCCESS)
*resLen = static_cast<SQLSMALLINT>(outResLen);
return SqlResultToReturnCode(result);
}
SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType,
SQLHANDLE handle,
SQLSMALLINT recNum,
SQLCHAR* sqlState,
SQLINTEGER* nativeError,
SQLCHAR* msgBuffer,
SQLSMALLINT msgBufferLen,
SQLSMALLINT* msgLen)
{
using namespace utility;
using namespace odbc;
using namespace odbc::diagnostic;
using namespace odbc::type_traits;
using odbc::app::ApplicationDataBuffer;
LOG_MSG("SQLGetDiagRec called");
const DiagnosticRecordStorage* records = 0;
switch (handleType)
{
case SQL_HANDLE_ENV:
case SQL_HANDLE_DBC:
case SQL_HANDLE_STMT:
{
Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle);
if (!diag)
return SQL_INVALID_HANDLE;
records = &diag->GetDiagnosticRecords();
break;
}
default:
return SQL_INVALID_HANDLE;
}
if (recNum < 1 || msgBufferLen < 0)
return SQL_ERROR;
if (!records || 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;
const std::string& errMsg = record.GetMessageText();
if (!msgBuffer || msgBufferLen < static_cast<SQLSMALLINT>(errMsg.size() + 1))
{
if (!msgLen)
return SQL_ERROR;
CopyStringToBuffer(errMsg, reinterpret_cast<char*>(msgBuffer), static_cast<size_t>(msgBufferLen));
*msgLen = static_cast<SQLSMALLINT>(errMsg.size());
return SQL_SUCCESS_WITH_INFO;
}
CopyStringToBuffer(errMsg, reinterpret_cast<char*>(msgBuffer), static_cast<size_t>(msgBufferLen));
if (msgLen)
*msgLen = static_cast<SQLSMALLINT>(errMsg.size());
return SQL_SUCCESS;
}
SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT type)
{
using odbc::Statement;
LOG_MSG("SQLGetTypeInfo called: [type=" << type << ']');
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->ExecuteGetTypeInfoQuery(static_cast<int16_t>(type));
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLEndTran(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT completionType)
{
using namespace odbc;
LOG_MSG("SQLEndTran called");
SQLRETURN result;
switch (handleType)
{
case SQL_HANDLE_ENV:
{
Environment *env = reinterpret_cast<Environment*>(handle);
if (!env)
return SQL_INVALID_HANDLE;
if (completionType == SQL_COMMIT)
env->TransactionCommit();
else
env->TransactionRollback();
result = env->GetDiagnosticRecords().GetReturnCode();
break;
}
case SQL_HANDLE_DBC:
{
Connection *conn = reinterpret_cast<Connection*>(handle);
if (!conn)
return SQL_INVALID_HANDLE;
if (completionType == SQL_COMMIT)
conn->TransactionCommit();
else
conn->TransactionRollback();
result = conn->GetDiagnosticRecords().GetReturnCode();
break;
}
default:
{
result = SQL_INVALID_HANDLE;
break;
}
}
return result;
}
SQLRETURN SQLGetData(SQLHSTMT stmt,
SQLUSMALLINT colNum,
SQLSMALLINT targetType,
SQLPOINTER targetValue,
SQLLEN bufferLength,
SQLLEN* strLengthOrIndicator)
{
using namespace odbc::type_traits;
using odbc::Statement;
using odbc::app::ApplicationDataBuffer;
LOG_MSG("SQLGetData called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
OdbcNativeType::Type 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 odbc::Environment;
LOG_MSG("SQLSetEnvAttr called");
LOG_MSG("Attribute: " << attr << ", Value: " << (size_t)value);
Environment *environment = reinterpret_cast<Environment*>(env);
if (!environment)
return SQL_INVALID_HANDLE;
environment->SetAttribute(attr, value, valueLen);
return environment->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLGetEnvAttr(SQLHENV env,
SQLINTEGER attr,
SQLPOINTER valueBuf,
SQLINTEGER valueBufLen,
SQLINTEGER* valueResLen)
{
using namespace odbc;
using namespace type_traits;
using app::ApplicationDataBuffer;
LOG_MSG("SQLGetEnvAttr called");
Environment *environment = reinterpret_cast<Environment*>(env);
if (!environment)
return SQL_INVALID_HANDLE;
SqlLen outResLen;
ApplicationDataBuffer outBuffer(OdbcNativeType::AI_SIGNED_LONG, valueBuf,
static_cast<int32_t>(valueBufLen), &outResLen);
environment->GetAttribute(attr, outBuffer);
if (valueResLen)
*valueResLen = static_cast<SQLSMALLINT>(outResLen);
return environment->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLSpecialColumns(SQLHSTMT stmt,
SQLSMALLINT idType,
SQLCHAR* catalogName,
SQLSMALLINT catalogNameLen,
SQLCHAR* schemaName,
SQLSMALLINT schemaNameLen,
SQLCHAR* tableName,
SQLSMALLINT tableNameLen,
SQLSMALLINT scope,
SQLSMALLINT nullable)
{
using namespace odbc;
using utility::SqlStringToString;
LOG_MSG("SQLSpecialColumns called");
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: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
statement->ExecuteSpecialColumnsQuery(idType, catalog, schema, table, scope, nullable);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLParamData(SQLHSTMT stmt, SQLPOINTER* value)
{
using namespace ignite::odbc;
LOG_MSG("SQLParamData called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->SelectParam(value);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN strLengthOrIndicator)
{
using namespace ignite::odbc;
LOG_MSG("SQLPutData called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->PutData(data, strLengthOrIndicator);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLDescribeParam(SQLHSTMT stmt,
SQLUSMALLINT paramNum,
SQLSMALLINT* dataType,
SQLULEN* paramSize,
SQLSMALLINT* decimalDigits,
SQLSMALLINT* nullable)
{
using namespace ignite::odbc;
LOG_MSG("SQLDescribeParam called");
Statement *statement = reinterpret_cast<Statement*>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->DescribeParam(paramNum, dataType, paramSize, decimalDigits, nullable);
return statement->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQLError(SQLHENV env,
SQLHDBC conn,
SQLHSTMT stmt,
SQLCHAR* state,
SQLINTEGER* error,
SQLCHAR* msgBuf,
SQLSMALLINT msgBufLen,
SQLSMALLINT* msgResLen)
{
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("SQLError called");
SQLHANDLE handle = 0;
if (env != 0)
handle = static_cast<SQLHANDLE>(env);
else if (conn != 0)
handle = static_cast<SQLHANDLE>(conn);
else if (stmt != 0)
handle = static_cast<SQLHANDLE>(stmt);
else
return SQL_INVALID_HANDLE;
Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle);
DiagnosticRecordStorage& records = diag->GetDiagnosticRecords();
int32_t recNum = records.GetLastNonRetrieved();
if (recNum < 1 || recNum > records.GetStatusRecordsNumber())
return SQL_NO_DATA;
DiagnosticRecord& record = records.GetStatusRecord(recNum);
record.MarkRetrieved();
if (state)
CopyStringToBuffer(record.GetSqlState(), reinterpret_cast<char*>(state), 6);
if (error)
*error = 0;
SqlLen outResLen;
ApplicationDataBuffer outBuffer(OdbcNativeType::AI_CHAR, msgBuf, msgBufLen, &outResLen);
outBuffer.PutString(record.GetMessageText());
if (msgResLen)
*msgResLen = static_cast<SQLSMALLINT>(outResLen);
return SQL_SUCCESS;
}
SQLRETURN SQL_API SQLGetConnectAttr(SQLHDBC conn,
SQLINTEGER attr,
SQLPOINTER valueBuf,
SQLINTEGER valueBufLen,
SQLINTEGER* valueResLen)
{
using namespace odbc;
using namespace type_traits;
using app::ApplicationDataBuffer;
LOG_MSG("SQLGetConnectAttr called");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->GetAttribute(attr, valueBuf, valueBufLen, valueResLen);
return connection->GetDiagnosticRecords().GetReturnCode();
}
SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC conn,
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER valueLen)
{
using odbc::Connection;
LOG_MSG("SQLSetConnectAttr called(" << attr << ", " << value << ")");
Connection *connection = reinterpret_cast<Connection*>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->SetAttribute(attr, value, valueLen);
return connection->GetDiagnosticRecords().GetReturnCode();
}
} // namespace ignite;