blob: 28aa37b4539c5d3d09195b317a4c1b4b4793573e [file]
/*
* 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/log.h"
#include "ignite/odbc/system/odbc_constants.h"
#include "ignite/odbc/utility.h"
#include "ignite/odbc/config/configuration.h"
#include "ignite/odbc/odbc.h"
#include "ignite/odbc/sql_connection.h"
#include "ignite/odbc/sql_environment.h"
#include "ignite/odbc/sql_statement.h"
#include "ignite/odbc/type_traits.h"
#include <algorithm>
#ifdef __JETBRAINS_IDE__
# pragma clang diagnostic push
# pragma ide diagnostic ignored "readability-non-const-parameter"
#endif
namespace ignite {
diagnosable *diagnosable_from_handle(SQLSMALLINT handle_type, void *handle) {
switch (handle_type) {
case SQL_HANDLE_ENV: {
auto *env = reinterpret_cast<sql_environment *>(handle);
return static_cast<diagnosable *>(env);
}
case SQL_HANDLE_DBC: {
auto *conn = reinterpret_cast<sql_connection *>(handle);
return static_cast<diagnosable *>(conn);
}
case SQL_HANDLE_STMT: {
auto *statement = reinterpret_cast<sql_statement *>(handle);
return static_cast<diagnosable *>(statement);
}
default:
break;
}
return nullptr;
}
SQLRETURN SQLGetInfo(
SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValue, SQLSMALLINT infoValueMax, SQLSMALLINT *length) {
LOG_MSG("SQLGetInfo called: " << infoType << " (" << connection_info::info_type_to_string(infoType) << "), "
<< std::hex << reinterpret_cast<size_t>(infoValue) << ", " << infoValueMax << ", "
<< std::hex << reinterpret_cast<size_t>(length));
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->get_info(infoType, infoValue, infoValueMax, length);
return connection->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE *result) {
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: {
auto *connection = reinterpret_cast<sql_connection *>(parent);
if (!connection)
return SQL_INVALID_HANDLE;
if (result)
*result = nullptr;
connection->get_diagnostic_records().reset();
connection->add_status_record(sql_state::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 = nullptr;
return SQL_ERROR;
}
SQLRETURN SQLAllocEnv(SQLHENV *env) {
LOG_MSG("SQLAllocEnv called");
*env = reinterpret_cast<SQLHENV>(new sql_environment());
return SQL_SUCCESS;
}
SQLRETURN SQLAllocConnect(SQLHENV env, SQLHDBC *conn) {
LOG_MSG("SQLAllocConnect called");
*conn = SQL_NULL_HDBC;
auto *environment = reinterpret_cast<sql_environment *>(env);
if (!environment)
return SQL_INVALID_HANDLE;
sql_connection *connection = environment->create_connection();
if (!connection)
return environment->get_diagnostic_records().get_return_code();
*conn = reinterpret_cast<SQLHDBC>(connection);
return SQL_SUCCESS;
}
SQLRETURN SQLAllocStmt(SQLHDBC conn, SQLHSTMT *stmt) {
LOG_MSG("SQLAllocStmt called");
*stmt = SQL_NULL_HDBC;
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
auto *statement = connection->create_statement();
*stmt = reinterpret_cast<SQLHSTMT>(statement);
return connection->get_diagnostic_records().get_return_code();
}
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) {
LOG_MSG("SQLFreeEnv called: " << env);
auto *environment = reinterpret_cast<sql_environment *>(env);
if (!environment)
return SQL_INVALID_HANDLE;
delete environment;
return SQL_SUCCESS;
}
SQLRETURN SQLFreeConnect(SQLHDBC conn) {
LOG_MSG("SQLFreeConnect called");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->deregister();
delete connection;
return SQL_SUCCESS;
}
SQLRETURN SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option) {
LOG_MSG("SQLFreeStmt called [option=" << option << ']');
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
if (option == SQL_DROP) {
delete statement;
return SQL_SUCCESS;
}
statement->free_resources(option);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLCloseCursor(SQLHSTMT stmt) {
LOG_MSG("SQLCloseCursor called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
statement->close();
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLCHAR *inConnectionString,
SQLSMALLINT inConnectionStringLen, SQLCHAR *outConnectionString, SQLSMALLINT outConnectionStringBufferLen,
SQLSMALLINT *outConnectionStringLen, SQLUSMALLINT driverCompletion) {
UNUSED_VALUE(driverCompletion);
LOG_MSG("SQLDriverConnect called");
if (inConnectionString)
LOG_MSG("Connection String: [" << inConnectionString << "]");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
std::string connectStr = sql_string_to_string(inConnectionString, inConnectionStringLen);
connection->establish(connectStr, windowHandle);
diagnostic_record_storage &diag = connection->get_diagnostic_records();
if (!diag.is_successful())
return diag.get_return_code();
size_t result_len = copy_string_to_buffer(
connectStr, reinterpret_cast<char *>(outConnectionString), static_cast<size_t>(outConnectionStringBufferLen));
if (outConnectionStringLen)
*outConnectionStringLen = static_cast<SQLSMALLINT>(result_len);
if (outConnectionString)
LOG_MSG(outConnectionString);
return diag.get_return_code();
}
SQLRETURN SQLConnect(SQLHDBC conn, SQLCHAR *server_name, SQLSMALLINT server_name_len, SQLCHAR *user_name,
SQLSMALLINT user_name_len, SQLCHAR *auth, SQLSMALLINT auth_len) {
LOG_MSG("SQLConnect called\n");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
std::string dsn = sql_string_to_string(server_name, server_name_len);
LOG_MSG("DSN: " << dsn);
// TODO: IGNITE-19210 Add DSN support
std::string auth_identity = sql_string_to_string(user_name, user_name_len);
std::string auth_secret = sql_string_to_string(auth, auth_len);
connection->establish({auth_identity, auth_secret});
return connection->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLDisconnect(SQLHDBC conn) {
LOG_MSG("SQLDisconnect called");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->release();
return connection->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER query_len) {
LOG_MSG("SQLPrepare called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string sql = sql_string_to_string(query, query_len);
LOG_MSG("SQL: " << sql);
statement->prepare_sql_query(sql);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLExecute(SQLHSTMT stmt) {
LOG_MSG("SQLExecute called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->execute_sql_query();
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER query_len) {
LOG_MSG("SQLExecDirect called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string sql = sql_string_to_string(query, query_len);
LOG_MSG("SQL: " << sql);
statement->execute_sql_query(sql);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col_num, SQLSMALLINT target_type, SQLPOINTER target_value,
SQLLEN buffer_length, SQLLEN *str_length_or_indicator) {
LOG_MSG("SQLBindCol called: index=" << col_num << ", type=" << target_type << ", target_value="
<< reinterpret_cast<size_t>(target_value) << ", buffer_length=" << buffer_length
<< ", lengthInd=" << reinterpret_cast<size_t>(str_length_or_indicator));
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->bind_column(col_num, target_type, target_value, buffer_length, str_length_or_indicator);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLFetch(SQLHSTMT stmt) {
LOG_MSG("SQLFetch called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->fetch_row();
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orientation, SQLLEN offset) {
LOG_MSG("SQLFetchScroll called");
LOG_MSG("Orientation: " << orientation << " Offset: " << offset);
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->fetch_scroll(orientation, offset);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLExtendedFetch(
SQLHSTMT stmt, SQLUSMALLINT orientation, SQLLEN offset, SQLULEN *row_count, SQLUSMALLINT *row_status_array) {
LOG_MSG("SQLExtendedFetch called");
SQLRETURN res = SQLFetchScroll(stmt, SQLSMALLINT(orientation), offset);
if (res == SQL_SUCCESS) {
if (row_count)
*row_count = 1;
if (row_status_array)
row_status_array[0] = SQL_ROW_SUCCESS;
} else if (res == SQL_NO_DATA && row_count)
*row_count = 0;
return res;
}
SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *column_num) {
LOG_MSG("SQLNumResultCols called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
int32_t res = statement->get_column_number();
if (column_num) {
*column_num = static_cast<SQLSMALLINT>(res);
LOG_MSG("column_num: " << *column_num);
}
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLTables(SQLHSTMT stmt, SQLCHAR *catalog_name, SQLSMALLINT catalog_name_len, SQLCHAR *schema_name,
SQLSMALLINT schema_name_len, SQLCHAR *table_name, SQLSMALLINT table_name_len, SQLCHAR *table_type,
SQLSMALLINT table_type_len) {
LOG_MSG("SQLTables called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string catalog = sql_string_to_string(catalog_name, catalog_name_len);
std::string schema = sql_string_to_string(schema_name, schema_name_len);
std::string table = sql_string_to_string(table_name, table_name_len);
std::string tableTypeStr = sql_string_to_string(table_type, table_type_len);
LOG_MSG("catalog: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
LOG_MSG("table_type: " << tableTypeStr);
statement->execute_get_tables_meta_query(catalog, schema, table, tableTypeStr);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLColumns(SQLHSTMT stmt, SQLCHAR *catalog_name, SQLSMALLINT catalog_name_len, SQLCHAR *schema_name,
SQLSMALLINT schema_name_len, SQLCHAR *table_name, SQLSMALLINT table_name_len, SQLCHAR *column_name,
SQLSMALLINT column_name_len) {
LOG_MSG("SQLColumns called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string catalog = sql_string_to_string(catalog_name, catalog_name_len);
std::string schema = sql_string_to_string(schema_name, schema_name_len);
std::string table = sql_string_to_string(table_name, table_name_len);
std::string column = sql_string_to_string(column_name, column_name_len);
LOG_MSG("catalog: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
LOG_MSG("column: " << column);
statement->execute_get_columns_meta_query(schema, table, column);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLMoreResults(SQLHSTMT stmt) {
LOG_MSG("SQLMoreResults called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->more_results();
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT param_idx, SQLSMALLINT io_type, SQLSMALLINT buffer_type,
SQLSMALLINT param_sql_type, SQLULEN column_size, SQLSMALLINT dec_digits, SQLPOINTER buffer, SQLLEN buffer_len,
SQLLEN *res_len) {
LOG_MSG("SQLBindParameter called: " << param_idx << ", " << buffer_type << ", " << param_sql_type);
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->bind_parameter(
param_idx, io_type, buffer_type, param_sql_type, column_size, dec_digits, buffer, buffer_len, res_len);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLNativeSql(SQLHDBC conn, SQLCHAR *in_query, SQLINTEGER in_query_len, SQLCHAR *out_query_buffer,
SQLINTEGER out_query_buffer_len, SQLINTEGER *out_query_len) {
UNUSED_VALUE(conn);
LOG_MSG("SQLNativeSql called");
std::string in = sql_string_to_string(in_query, in_query_len);
copy_string_to_buffer(in, reinterpret_cast<char *>(out_query_buffer), static_cast<size_t>(out_query_buffer_len));
if (out_query_len)
*out_query_len = std::min(out_query_buffer_len, static_cast<SQLINTEGER>(in.size()));
return SQL_SUCCESS;
}
SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT column_num, SQLUSMALLINT field_id, SQLPOINTER str_attr,
SQLSMALLINT buffer_len, SQLSMALLINT *str_attr_len, SQLLEN *numeric_attr) {
LOG_MSG("SQLColAttribute called: " << field_id << " (" << column_meta::attr_id_to_string(field_id) << ")");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
// This is a special case
if (field_id == SQL_DESC_COUNT) {
SQLSMALLINT val = 0;
SQLRETURN res = SQLNumResultCols(stmt, &val);
if (numeric_attr && res == SQL_SUCCESS)
*numeric_attr = val;
return res;
}
statement->get_column_attribute(
column_num, field_id, reinterpret_cast<char *>(str_attr), buffer_len, str_attr_len, numeric_attr);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT column_num, SQLCHAR *column_name_buf,
SQLSMALLINT column_name_buf_len, SQLSMALLINT *column_name_len, SQLSMALLINT *data_type, SQLULEN *column_size,
SQLSMALLINT *decimal_digits, SQLSMALLINT *nullable) {
LOG_MSG("SQLDescribeCol called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->get_column_attribute(column_num, SQL_DESC_NAME, reinterpret_cast<char *>(column_name_buf),
column_name_buf_len, column_name_len, nullptr);
SQLLEN dataTypeRes;
SQLLEN columnSizeRes;
SQLLEN decimalDigitsRes;
SQLLEN nullableRes;
statement->get_column_attribute(column_num, SQL_DESC_TYPE, nullptr, 0, nullptr, &dataTypeRes);
statement->get_column_attribute(column_num, SQL_DESC_PRECISION, nullptr, 0, nullptr, &columnSizeRes);
statement->get_column_attribute(column_num, SQL_DESC_SCALE, nullptr, 0, nullptr, &decimalDigitsRes);
statement->get_column_attribute(column_num, SQL_DESC_NULLABLE, nullptr, 0, nullptr, &nullableRes);
LOG_MSG("column_num: " << column_num);
LOG_MSG("dataTypeRes: " << dataTypeRes);
LOG_MSG("columnSizeRes: " << columnSizeRes);
LOG_MSG("decimalDigitsRes: " << decimalDigitsRes);
LOG_MSG("nullableRes: " << nullableRes);
LOG_MSG("column_name_buf: " << (column_name_buf ? reinterpret_cast<const char *>(column_name_buf) : "<null>"));
LOG_MSG("column_name_len: " << (column_name_len ? *column_name_len : -1));
if (data_type)
*data_type = static_cast<SQLSMALLINT>(dataTypeRes);
if (column_size)
*column_size = static_cast<SQLULEN>(columnSizeRes);
if (decimal_digits)
*decimal_digits = static_cast<SQLSMALLINT>(decimalDigitsRes);
if (nullable)
*nullable = static_cast<SQLSMALLINT>(nullableRes);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN *row_count) {
LOG_MSG("SQLRowCount called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
int64_t res = statement->affected_rows();
LOG_MSG("Row count: " << res);
if (row_count)
*row_count = static_cast<SQLLEN>(res);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLForeignKeys(SQLHSTMT stmt, SQLCHAR *primary_catalog_name, SQLSMALLINT primary_catalog_name_len,
SQLCHAR *primary_schema_name, SQLSMALLINT primary_schema_name_len, SQLCHAR *primary_table_name,
SQLSMALLINT primary_table_name_len, SQLCHAR *foreign_catalog_name, SQLSMALLINT foreign_catalog_name_len,
SQLCHAR *foreign_schema_name, SQLSMALLINT foreign_schema_name_len, SQLCHAR *foreign_table_name,
SQLSMALLINT foreign_table_name_len) {
LOG_MSG("SQLForeignKeys called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string primary_catalog = sql_string_to_string(primary_catalog_name, primary_catalog_name_len);
std::string primary_schema = sql_string_to_string(primary_schema_name, primary_schema_name_len);
std::string primary_table = sql_string_to_string(primary_table_name, primary_table_name_len);
std::string foreign_catalog = sql_string_to_string(foreign_catalog_name, foreign_catalog_name_len);
std::string foreign_schema = sql_string_to_string(foreign_schema_name, foreign_schema_name_len);
std::string foreign_table = sql_string_to_string(foreign_table_name, foreign_table_name_len);
LOG_MSG("primary_catalog: " << primary_catalog);
LOG_MSG("primary_schema: " << primary_schema);
LOG_MSG("primary_table: " << primary_table);
LOG_MSG("foreign_catalog: " << foreign_catalog);
LOG_MSG("foreign_schema: " << foreign_schema);
LOG_MSG("foreign_table: " << foreign_table);
statement->execute_get_foreign_keys_query(
primary_catalog, primary_schema, primary_table, foreign_catalog, foreign_schema, foreign_table);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLGetStmtAttr(
SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER value_buf, SQLINTEGER value_buf_len, SQLINTEGER *value_res_len) {
LOG_MSG("SQLGetStmtAttr called");
#ifdef _DEBUG
LOG_MSG("Attr: " << statement_attr_id_to_string(attr) << " (" << attr << ")");
#endif //_DEBUG
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->get_attribute(attr, value_buf, value_buf_len, value_res_len);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER value_len) {
LOG_MSG("SQLSetStmtAttr called: " << attr);
#ifdef _DEBUG
LOG_MSG("Attr: " << statement_attr_id_to_string(attr) << " (" << attr << ")");
#endif //_DEBUG
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->set_attribute(attr, value, value_len);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLPrimaryKeys(SQLHSTMT stmt, SQLCHAR *catalog_name, SQLSMALLINT catalog_name_len, SQLCHAR *schema_name,
SQLSMALLINT schema_name_len, SQLCHAR *table_name, SQLSMALLINT table_name_len) {
LOG_MSG("SQLPrimaryKeys called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string catalog = sql_string_to_string(catalog_name, catalog_name_len);
std::string schema = sql_string_to_string(schema_name, schema_name_len);
std::string table = sql_string_to_string(table_name, table_name_len);
LOG_MSG("catalog: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
statement->execute_get_primary_keys_query(catalog, schema, table);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *param_cnt) {
LOG_MSG("SQLNumParams called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
if (param_cnt) {
uint16_t param_num = 0;
statement->get_parameters_number(param_num);
*param_cnt = static_cast<SQLSMALLINT>(param_num);
}
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLGetDiagField(SQLSMALLINT handle_type, SQLHANDLE handle, SQLSMALLINT rec_num, SQLSMALLINT diag_id,
SQLPOINTER buffer, SQLSMALLINT buffer_len, SQLSMALLINT *res_len) {
LOG_MSG("SQLGetDiagField called: " << rec_num);
auto *diag = diagnosable_from_handle(handle_type, handle);
SQLLEN out_res_len;
sql_result result = sql_result::AI_NO_DATA;
if (diag) {
application_data_buffer out_buffer(odbc_native_type::AI_DEFAULT, buffer, buffer_len, &out_res_len);
auto field = diagnostic_field_to_internal(diag_id);
result = diag->get_diagnostic_records().get_field(rec_num, field, out_buffer);
}
if (res_len && result == sql_result::AI_SUCCESS)
*res_len = static_cast<SQLSMALLINT>(out_res_len);
return sql_result_to_return_code(result);
}
SQLRETURN SQLGetDiagRec(SQLSMALLINT handle_type, SQLHANDLE handle, SQLSMALLINT rec_num, SQLCHAR *sql_state,
SQLINTEGER *native_error, SQLCHAR *msg_buffer, SQLSMALLINT msg_buffer_len, SQLSMALLINT *msg_len) {
LOG_MSG("SQLGetDiagRec called");
auto *diag = diagnosable_from_handle(handle_type, handle);
const diagnostic_record_storage *records = diag ? &diag->get_diagnostic_records() : nullptr;
if (rec_num < 1 || msg_buffer_len < 0)
return SQL_ERROR;
if (!records || rec_num > records->get_status_records_number())
return SQL_NO_DATA;
const diagnostic_record &record = records->get_status_record(rec_num);
if (sql_state)
copy_string_to_buffer(record.get_sql_state(), reinterpret_cast<char *>(sql_state), 6);
if (native_error)
*native_error = 0;
const std::string &errMsg = record.get_message_text();
if (!msg_buffer || msg_buffer_len < static_cast<SQLSMALLINT>(errMsg.size() + 1)) {
if (!msg_len)
return SQL_ERROR;
copy_string_to_buffer(errMsg, reinterpret_cast<char *>(msg_buffer), static_cast<size_t>(msg_buffer_len));
*msg_len = static_cast<SQLSMALLINT>(errMsg.size());
return SQL_SUCCESS_WITH_INFO;
}
copy_string_to_buffer(errMsg, reinterpret_cast<char *>(msg_buffer), static_cast<size_t>(msg_buffer_len));
if (msg_len)
*msg_len = static_cast<SQLSMALLINT>(errMsg.size());
return SQL_SUCCESS;
}
SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT type) {
LOG_MSG("SQLGetTypeInfo called: [type=" << type << ']');
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->execute_get_type_info_query(static_cast<int16_t>(type));
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLEndTran(SQLSMALLINT handle_type, SQLHANDLE handle, SQLSMALLINT completion_type) {
LOG_MSG("SQLEndTran called");
SQLRETURN result;
switch (handle_type) {
case SQL_HANDLE_ENV: {
auto *env = reinterpret_cast<sql_environment *>(handle);
if (!env)
return SQL_INVALID_HANDLE;
if (completion_type == SQL_COMMIT)
env->transaction_commit();
else
env->transaction_rollback();
result = env->get_diagnostic_records().get_return_code();
break;
}
case SQL_HANDLE_DBC: {
auto *conn = reinterpret_cast<sql_connection *>(handle);
if (!conn)
return SQL_INVALID_HANDLE;
if (completion_type == SQL_COMMIT)
conn->transaction_commit();
else
conn->transaction_rollback();
result = conn->get_diagnostic_records().get_return_code();
break;
}
default: {
result = SQL_INVALID_HANDLE;
break;
}
}
return result;
}
SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col_num, SQLSMALLINT target_type, SQLPOINTER target_value,
SQLLEN buffer_length, SQLLEN *str_length_or_indicator) {
LOG_MSG("SQLGetData called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
odbc_native_type driver_type = to_driver_type(target_type);
application_data_buffer data_buffer(driver_type, target_value, buffer_length, str_length_or_indicator);
statement->get_column_data(col_num, data_buffer);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER value_len) {
LOG_MSG("SQLSetEnvAttr called");
LOG_MSG("Attribute: " << attr << ", Value: " << (size_t) value);
auto *environment = reinterpret_cast<sql_environment *>(env);
if (!environment)
return SQL_INVALID_HANDLE;
environment->set_attribute(attr, value, value_len);
return environment->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLGetEnvAttr(
SQLHENV env, SQLINTEGER attr, SQLPOINTER value_buf, SQLINTEGER value_buf_len, SQLINTEGER *value_res_len) {
LOG_MSG("SQLGetEnvAttr called");
auto *environment = reinterpret_cast<sql_environment *>(env);
if (!environment)
return SQL_INVALID_HANDLE;
SQLLEN out_res_len;
application_data_buffer out_buffer(
odbc_native_type::AI_SIGNED_LONG, value_buf, static_cast<int32_t>(value_buf_len), &out_res_len);
environment->get_attribute(attr, out_buffer);
if (value_res_len)
*value_res_len = static_cast<SQLSMALLINT>(out_res_len);
return environment->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id_type, SQLCHAR *catalog_name, SQLSMALLINT catalog_name_len,
SQLCHAR *schema_name, SQLSMALLINT schema_name_len, SQLCHAR *table_name, SQLSMALLINT table_name_len,
SQLUSMALLINT scope, SQLUSMALLINT nullable) {
LOG_MSG("SQLSpecialColumns called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
std::string catalog = sql_string_to_string(catalog_name, catalog_name_len);
std::string schema = sql_string_to_string(schema_name, schema_name_len);
std::string table = sql_string_to_string(table_name, table_name_len);
LOG_MSG("catalog: " << catalog);
LOG_MSG("schema: " << schema);
LOG_MSG("table: " << table);
statement->execute_special_columns_query(id_type, catalog, schema, table, scope, nullable);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLParamData(SQLHSTMT stmt, SQLPOINTER *value) {
LOG_MSG("SQLParamData called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->select_param(value);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN str_length_or_indicator) {
LOG_MSG("SQLPutData called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->put_data(data, str_length_or_indicator);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT param_num, SQLSMALLINT *data_type, SQLULEN *param_size,
SQLSMALLINT *decimal_digits, SQLSMALLINT *nullable) {
LOG_MSG("SQLDescribeParam called");
auto *statement = reinterpret_cast<sql_statement *>(stmt);
if (!statement)
return SQL_INVALID_HANDLE;
statement->describe_param(param_num, data_type, param_size, decimal_digits, nullable);
return statement->get_diagnostic_records().get_return_code();
}
SQLRETURN SQLError(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, SQLCHAR *state, SQLINTEGER *error, SQLCHAR *msg_buf,
SQLSMALLINT msg_buf_len, SQLSMALLINT *msg_res_len) {
LOG_MSG("SQLError called");
diagnosable *diag = nullptr;
if (env != nullptr)
diag = diagnosable_from_handle(SQL_HANDLE_ENV, env);
else if (conn != nullptr)
diag = diagnosable_from_handle(SQL_HANDLE_DBC, conn);
else if (stmt != nullptr)
diag = diagnosable_from_handle(SQL_HANDLE_STMT, stmt);
else
return SQL_INVALID_HANDLE;
diagnostic_record_storage &records = diag->get_diagnostic_records();
int32_t rec_num = records.get_last_non_retrieved();
if (rec_num < 1 || rec_num > records.get_status_records_number())
return SQL_NO_DATA;
diagnostic_record &record = records.get_status_record(rec_num);
record.mark_retrieved();
if (state)
copy_string_to_buffer(record.get_sql_state(), reinterpret_cast<char *>(state), 6);
if (error)
*error = 0;
SQLLEN out_res_len;
application_data_buffer out_buffer(odbc_native_type::AI_CHAR, msg_buf, msg_buf_len, &out_res_len);
out_buffer.put_string(record.get_message_text());
if (msg_res_len)
*msg_res_len = static_cast<SQLSMALLINT>(out_res_len);
return SQL_SUCCESS;
}
SQLRETURN SQL_API SQLGetConnectAttr(
SQLHDBC conn, SQLINTEGER attr, SQLPOINTER value_buf, SQLINTEGER value_buf_len, SQLINTEGER *value_res_len) {
LOG_MSG("SQLGetConnectAttr called");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->get_attribute(attr, value_buf, value_buf_len, value_res_len);
return connection->get_diagnostic_records().get_return_code();
}
SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER value, SQLINTEGER value_len) {
LOG_MSG("SQLSetConnectAttr called(" << attr << ", " << value << ")");
auto *connection = reinterpret_cast<sql_connection *>(conn);
if (!connection)
return SQL_INVALID_HANDLE;
connection->set_attribute(attr, value, value_len);
return connection->get_diagnostic_records().get_return_code();
}
} // namespace ignite
#ifdef __JETBRAINS_IDE__
# pragma clang diagnostic pop
#endif