modules/platforms/cpp/ignite/odbc/app/application_data_buffer.cpp (1,189 lines of code) (raw):
/*
* 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/app/application_data_buffer.h>
#include <ignite/odbc/log.h>
#include <ignite/odbc/system/odbc_constants.h>
#include <ignite/odbc/utility.h>
#include "ignite/common/detail/bits.h"
#include <algorithm>
#include <chrono>
#include <cstring>
#include <ctime>
#include <sstream>
#include <string>
namespace {
using namespace ignite;
/**
* Convert string to wstring.
* Just copies bytes currently so basically only works for the ASCII character set.
*
* TODO: IGNITE-19943 Implement wstring support
*
* @param str String.
* @param str_len String length.
* @param wstr Wide string.
* @param wstr_len Wide string length.
* @return Conversation result.
*/
ignite::conversion_result string_to_wstring(
const char *str, std::int64_t str_len, SQLWCHAR *wstr, std::int64_t wstr_len) {
using namespace ignite;
if (wstr_len <= 0)
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
std::int64_t to_copy = std::min(str_len, wstr_len - 1);
if (to_copy <= 0) {
wstr[0] = 0;
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
}
for (int64_t i = 0; i < to_copy; ++i)
wstr[i] = str[i];
wstr[to_copy] = 0;
if (to_copy < str_len)
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
return conversion_result::AI_SUCCESS;
}
/**
* Convert Ignite date to C standard tm struct.
*
* @warning This is not a proper conversion and only works for using with strftime with certain format options.
* @param value Ignite date.
* @return A tm structure to use with strftime.
*/
tm date_to_tm_for_strftime(const ignite_date &value) {
tm tm_time{};
tm_time.tm_year = value.get_year() - 1900;
tm_time.tm_mon = value.get_month() - 1; // NOLINT(cert-str34-c)
tm_time.tm_mday = value.get_day_of_month(); // NOLINT(cert-str34-c)
return tm_time;
}
/**
* Convert Ignite time to C standard tm struct.
*
* @warning This is not a proper conversion and only works for using with strftime with certain format options.
* @param value Ignite time.
* @return A tm structure to use with strftime.
*/
tm time_to_tm_for_strftime(const ignite_time &value) {
tm tm_time{};
tm_time.tm_hour = value.get_hour(); // NOLINT(cert-str34-c)
tm_time.tm_min = value.get_minute(); // NOLINT(cert-str34-c)
tm_time.tm_sec = value.get_second(); // NOLINT(cert-str34-c)
return tm_time;
}
/**
* Convert Ignite date time to C standard tm struct.
*
* @warning This is not a proper conversion and only works for using with strftime with certain format options.
* @param value Ignite time.
* @return A tm structure to use with strftime.
*/
tm time_date_to_tm_for_strftime(const ignite_date_time &value) {
tm tm_time{};
tm_time.tm_year = value.get_year() - 1900;
tm_time.tm_mon = value.get_month() - 1; // NOLINT(cert-str34-c)
tm_time.tm_mday = value.get_day_of_month(); // NOLINT(cert-str34-c)
tm_time.tm_hour = value.get_hour(); // NOLINT(cert-str34-c)
tm_time.tm_min = value.get_minute(); // NOLINT(cert-str34-c)
tm_time.tm_sec = value.get_second(); // NOLINT(cert-str34-c)
return tm_time;
}
/**
* Convert time_t to struct tm.
*
* @param ctime Time.
* @return A tm instance.
*/
tm time_t_to_tm(time_t ctime) {
tm tm_time{};
IGNITE_SWITCH_WIN_OTHER(localtime_s(&tm_time, &ctime), localtime_r(&ctime, &tm_time));
return tm_time;
}
/**
* Convert Ignite timestamp to C standard tm struct.
*
* @warning This is not a proper conversion and only works for using with strftime with certain format options.
* @param value Ignite date.
* @return A tm structure to use with strftime.
*/
tm timestamp_to_tm(const ignite_timestamp &value) {
auto ctime = time_t(value.get_epoch_second());
return time_t_to_tm(ctime);
}
} // anonymous namespace
namespace ignite {
application_data_buffer::application_data_buffer(odbc_native_type type, void *buffer, SQLLEN buf_len, SQLLEN *res_len)
: m_type(type)
, m_buffer(buffer)
, m_buffer_len(std::max(buf_len, SQLLEN(0)))
, m_result_len(res_len)
, m_byte_offset(0)
, m_element_offset(0) {
}
template<typename T>
conversion_result application_data_buffer::put_num(T value) {
LOG_MSG("value: " << value);
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
switch (m_type) {
case odbc_native_type::AI_SIGNED_TINYINT: {
return put_num_to_num_buffer<signed char>(value);
}
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT: {
return put_num_to_num_buffer<unsigned char>(value);
}
case odbc_native_type::AI_SIGNED_SHORT: {
return put_num_to_num_buffer<SQLSMALLINT>(value);
}
case odbc_native_type::AI_UNSIGNED_SHORT: {
return put_num_to_num_buffer<SQLUSMALLINT>(value);
}
case odbc_native_type::AI_SIGNED_LONG: {
return put_num_to_num_buffer<SQLINTEGER>(value);
}
case odbc_native_type::AI_UNSIGNED_LONG: {
return put_num_to_num_buffer<SQLUINTEGER>(value);
}
case odbc_native_type::AI_SIGNED_BIGINT: {
return put_num_to_num_buffer<SQLBIGINT>(value);
}
case odbc_native_type::AI_UNSIGNED_BIGINT: {
return put_num_to_num_buffer<SQLUBIGINT>(value);
}
case odbc_native_type::AI_FLOAT: {
return put_num_to_num_buffer<SQLREAL>(value);
}
case odbc_native_type::AI_DOUBLE: {
return put_num_to_num_buffer<SQLDOUBLE>(value);
}
case odbc_native_type::AI_CHAR: {
return put_value_to_string_buffer<char>(value);
}
case odbc_native_type::AI_WCHAR: {
return put_value_to_string_buffer<wchar_t>(value);
}
case odbc_native_type::AI_NUMERIC: {
if (data_ptr) {
auto *out = reinterpret_cast<SQL_NUMERIC_STRUCT *>(data_ptr);
auto u_val = static_cast<std::uint64_t>(value < 0 ? -value : value);
out->precision = detail::digit_length(u_val);
out->scale = 0;
out->sign = value < 0 ? 0 : 1;
memset(out->val, 0, SQL_MAX_NUMERIC_LEN);
memcpy(out->val, &u_val, std::min<int>(SQL_MAX_NUMERIC_LEN, sizeof(u_val)));
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_NUMERIC_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_BINARY:
case odbc_native_type::AI_DEFAULT: {
if (data_ptr)
memcpy(data_ptr, &value, std::min(sizeof(value), static_cast<std::size_t>(m_buffer_len)));
if (res_len_ptr)
*res_len_ptr = sizeof(value);
return static_cast<std::size_t>(m_buffer_len) < sizeof(value) ? conversion_result::AI_VARLEN_DATA_TRUNCATED
: conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_TDATE:
case odbc_native_type::AI_TTIMESTAMP:
case odbc_native_type::AI_TTIME:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
template<typename TBuf, typename TIn>
conversion_result application_data_buffer::put_num_to_num_buffer(TIn value) {
void *data_ptr = get_data();
SQLLEN *res_len_ptr = get_result_len();
if (data_ptr) {
TBuf *out = reinterpret_cast<TBuf *>(data_ptr);
*out = static_cast<TBuf>(value);
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(TBuf));
return conversion_result::AI_SUCCESS;
}
template<typename CharT, typename Tin>
conversion_result application_data_buffer::put_value_to_string_buffer(const Tin &value) {
std::basic_stringstream<CharT> converter;
converter << value;
std::int32_t written = 0;
return put_string_to_string_buffer<CharT>(converter.str(), written);
}
template<typename CharT>
conversion_result application_data_buffer::put_value_to_string_buffer(const std::int8_t &value) {
std::basic_stringstream<CharT> converter;
converter << static_cast<int>(value);
std::int32_t written = 0;
return put_string_to_string_buffer<CharT>(converter.str(), written);
}
template<typename OutCharT, typename InCharT>
conversion_result application_data_buffer::put_string_to_string_buffer(
const std::basic_string<InCharT> &value, std::int32_t &written) {
written = 0;
auto char_size = static_cast<SQLLEN>(sizeof(OutCharT));
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(value.size());
if (!data_ptr)
return conversion_result::AI_SUCCESS;
if (m_buffer_len < char_size)
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
auto *out = reinterpret_cast<OutCharT *>(data_ptr);
SQLLEN outLen = (m_buffer_len / char_size) - 1;
SQLLEN to_copy = std::min<SQLLEN>(outLen, value.size());
for (SQLLEN i = 0; i < to_copy; ++i)
out[i] = value[i];
out[to_copy] = 0;
written = static_cast<std::int32_t>(to_copy);
if (to_copy < static_cast<SQLLEN>(value.size()))
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
return conversion_result::AI_SUCCESS;
}
conversion_result application_data_buffer::put_raw_data_to_buffer(void *data, std::size_t len, std::int32_t &written) {
auto s_len = static_cast<SQLLEN>(len);
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
if (res_len_ptr)
*res_len_ptr = s_len;
SQLLEN to_copy = std::min(m_buffer_len, s_len);
if (data_ptr != nullptr && to_copy > 0)
memcpy(data_ptr, data, static_cast<std::size_t>(to_copy));
written = static_cast<std::int32_t>(to_copy);
return to_copy < s_len ? conversion_result::AI_VARLEN_DATA_TRUNCATED : conversion_result::AI_SUCCESS;
}
conversion_result application_data_buffer::put_int8(int8_t value) {
return put_num(value);
}
conversion_result application_data_buffer::put_int16(int16_t value) {
return put_num(value);
}
conversion_result application_data_buffer::put_int32(std::int32_t value) {
return put_num(value);
}
conversion_result application_data_buffer::put_int64(int64_t value) {
return put_num(value);
}
conversion_result application_data_buffer::put_float(float value) {
return put_num(value);
}
conversion_result application_data_buffer::put_double(double value) {
return put_num(value);
}
conversion_result application_data_buffer::put_bool(bool value) {
return put_num(value ? 1 : 0);
}
conversion_result application_data_buffer::put_string(const std::string &value) {
std::int32_t written = 0;
return put_string(value, written);
}
conversion_result application_data_buffer::put_string(const std::string &value, std::int32_t &written) {
LOG_MSG("value: " << value);
switch (m_type) {
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
case odbc_native_type::AI_NUMERIC: {
std::stringstream converter;
converter << value;
int64_t numValue;
converter >> numValue;
written = static_cast<std::int32_t>(value.size());
return put_num(numValue);
}
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE: {
std::stringstream converter;
converter << value;
double numValue;
converter >> numValue;
written = static_cast<std::int32_t>(value.size());
return put_num(numValue);
}
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY:
case odbc_native_type::AI_DEFAULT: {
return put_string_to_string_buffer<char>(value, written);
}
case odbc_native_type::AI_WCHAR: {
return put_string_to_string_buffer<wchar_t>(value, written);
}
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_uuid(const uuid &value) {
LOG_MSG("Value: " << value);
SQLLEN *res_len_ptr = get_result_len();
switch (m_type) {
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY:
case odbc_native_type::AI_DEFAULT: {
return put_value_to_string_buffer<char>(value);
}
case odbc_native_type::AI_WCHAR: {
return put_value_to_string_buffer<wchar_t>(value);
}
case odbc_native_type::AI_GUID: {
auto *guid = reinterpret_cast<SQLGUID *>(get_data());
guid->Data1 = static_cast<uint32_t>(value.get_most_significant_bits() >> 32);
guid->Data2 = static_cast<uint16_t>(value.get_most_significant_bits() >> 16);
guid->Data3 = static_cast<uint16_t>(value.get_most_significant_bits());
std::uint64_t lsb = value.get_least_significant_bits();
for (std::size_t i = 0; i < sizeof(guid->Data4); ++i)
guid->Data4[i] = (lsb >> (sizeof(guid->Data4) - i - 1) * 8) & 0xFF;
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQLGUID));
return conversion_result::AI_SUCCESS;
}
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_binary_data(void *data, std::size_t len, std::int32_t &written) {
switch (m_type) {
case odbc_native_type::AI_BINARY:
case odbc_native_type::AI_DEFAULT: {
return put_raw_data_to_buffer(data, len, written);
}
case odbc_native_type::AI_CHAR: {
std::stringstream converter;
for (std::size_t i = 0; i < len; ++i) {
auto *dataBytes = reinterpret_cast<std::uint8_t *>(data);
converter << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned>(dataBytes[i]);
}
return put_string_to_string_buffer<char>(converter.str(), written);
}
case odbc_native_type::AI_WCHAR: {
std::wstringstream converter;
for (std::size_t i = 0; i < len; ++i) {
auto *dataBytes = reinterpret_cast<std::uint8_t *>(data);
converter << std::hex << std::setfill(L'0') << std::setw(2) << static_cast<unsigned>(dataBytes[i]);
}
return put_string_to_string_buffer<wchar_t>(converter.str(), written);
}
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_null() {
SQLLEN *res_len_ptr = get_result_len();
if (!res_len_ptr)
return conversion_result::AI_INDICATOR_NEEDED;
*res_len_ptr = SQL_NULL_DATA;
return conversion_result::AI_SUCCESS;
}
conversion_result application_data_buffer::put_decimal(const big_decimal &value) {
SQLLEN *res_len_ptr = get_result_len();
switch (m_type) {
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT: {
put_num<int64_t>(value.to_int64());
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE: {
put_num<double>(value.to_double());
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_WCHAR: {
std::stringstream converter;
converter << value;
std::int32_t dummy = 0;
return put_string(converter.str(), dummy);
}
case odbc_native_type::AI_NUMERIC: {
auto *numeric = reinterpret_cast<SQL_NUMERIC_STRUCT *>(get_data());
auto sign = value.is_negative() ? 0 : 1;
big_decimal zero_scaled;
value.set_scale(0, zero_scaled);
if (zero_scaled.is_negative())
zero_scaled.negate();
const big_integer &unscaled = zero_scaled.get_unscaled_value();
std::vector<std::byte> bytes_buffer = unscaled.to_bytes();
for (std::int32_t i = 0; i < SQL_MAX_NUMERIC_LEN; ++i) {
std::ptrdiff_t buf_idx = std::ptrdiff_t(bytes_buffer.size()) - 1 - i;
if (buf_idx >= 0)
numeric->val[i] = SQLCHAR(bytes_buffer[buf_idx]);
else
numeric->val[i] = 0;
}
numeric->scale = 0;
numeric->sign = sign;
numeric->precision = unscaled.get_precision();
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_NUMERIC_STRUCT));
if (bytes_buffer.size() > SQL_MAX_NUMERIC_LEN)
return conversion_result::AI_FRACTIONAL_TRUNCATED;
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_BINARY:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_date(const ignite_date &value) {
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
constexpr auto val_len = SQLLEN(sizeof("HHHH-MM-DD"));
auto tm_time = date_to_tm_for_strftime(value);
return put_tm_to_string(tm_time, val_len, "%Y-%m-%d");
}
case odbc_native_type::AI_TDATE: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_DATE_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(value.get_year());
buffer->month = SQLUSMALLINT(value.get_month()); // NOLINT(cert-str34-c)
buffer->day = SQLUSMALLINT(value.get_day_of_month()); // NOLINT(cert-str34-c)
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_DATE_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_TTIMESTAMP: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(value.get_year());
buffer->month = SQLUSMALLINT(value.get_month()); // NOLINT(cert-str34-c)
buffer->day = SQLUSMALLINT(value.get_day_of_month()); // NOLINT(cert-str34-c)
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_TTIME:
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE:
case odbc_native_type::AI_NUMERIC:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_timestamp(const ignite_timestamp &value) {
auto *res_len_ptr = get_result_len();
void *data_ptr = get_data();
auto tm_time = timestamp_to_tm(value);
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
constexpr auto val_len = SQLLEN(sizeof("HHHH-MM-DD HH:MM:SS"));
return put_tm_to_string(tm_time, val_len, "%Y-%m-%d %H:%M:%S");
}
case odbc_native_type::AI_TDATE: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_DATE_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(tm_time.tm_year + 1900);
buffer->month = tm_time.tm_mon + 1;
buffer->day = tm_time.tm_mday;
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_DATE_STRUCT));
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_TTIME: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIME_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->hour = tm_time.tm_hour;
buffer->minute = tm_time.tm_min;
buffer->second = tm_time.tm_sec;
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIME_STRUCT));
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_TTIMESTAMP: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(tm_time.tm_year + 1900);
buffer->month = tm_time.tm_mon + 1;
buffer->day = tm_time.tm_mday;
buffer->hour = tm_time.tm_hour;
buffer->minute = tm_time.tm_min;
buffer->second = tm_time.tm_sec;
buffer->fraction = value.get_nano();
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE:
case odbc_native_type::AI_NUMERIC:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_time(const ignite_time &value) {
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
const auto val_len = SQLLEN(sizeof("HH:MM:SS"));
auto tm_time = time_to_tm_for_strftime(value);
return put_tm_to_string(tm_time, val_len, "%H:%M:%S");
}
case odbc_native_type::AI_TTIME: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIME_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->hour = SQLSMALLINT(value.get_hour());
buffer->minute = SQLSMALLINT(value.get_minute());
buffer->second = SQLSMALLINT(value.get_second());
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIME_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_TTIMESTAMP: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto tm_time = time_t_to_tm(now);
// According to ODBC specification, those should be set to current date.
buffer->year = SQLSMALLINT(tm_time.tm_year + 1900);
buffer->month = tm_time.tm_mon + 1;
buffer->day = tm_time.tm_mday;
buffer->hour = SQLSMALLINT(value.get_hour());
buffer->minute = SQLSMALLINT(value.get_minute());
buffer->second = SQLSMALLINT(value.get_second());
buffer->fraction = value.get_nano();
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE:
case odbc_native_type::AI_NUMERIC:
case odbc_native_type::AI_TDATE:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_date_time(const ignite_date_time &value) {
SQLLEN *res_len_ptr = get_result_len();
void *data_ptr = get_data();
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
const auto val_len = SQLLEN(sizeof("HHHH-MM-DD HH:MM:SS"));
auto tm_time = time_date_to_tm_for_strftime(value);
return put_tm_to_string(tm_time, val_len, "%Y-%m-%d %H:%M:%S");
}
case odbc_native_type::AI_TDATE: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_DATE_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(value.get_year());
buffer->month = SQLSMALLINT(value.get_month());
buffer->day = SQLSMALLINT(value.get_day_of_month());
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_DATE_STRUCT));
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_TTIME: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIME_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->hour = SQLSMALLINT(value.get_hour());
buffer->minute = SQLSMALLINT(value.get_minute());
buffer->second = SQLSMALLINT(value.get_second());
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIME_STRUCT));
return conversion_result::AI_FRACTIONAL_TRUNCATED;
}
case odbc_native_type::AI_TTIMESTAMP: {
if (data_ptr) {
auto *buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT *>(data_ptr);
memset(buffer, 0, sizeof(*buffer));
buffer->year = SQLSMALLINT(value.get_year());
buffer->month = SQLSMALLINT(value.get_month());
buffer->day = SQLSMALLINT(value.get_day_of_month());
buffer->hour = SQLSMALLINT(value.get_hour());
buffer->minute = SQLSMALLINT(value.get_minute());
buffer->second = SQLSMALLINT(value.get_second());
buffer->fraction = value.get_nano();
}
if (res_len_ptr)
*res_len_ptr = static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
return conversion_result::AI_SUCCESS;
}
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE:
case odbc_native_type::AI_NUMERIC:
default:
break;
}
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
conversion_result application_data_buffer::put_tm_to_string(tm &tm_time, SQLLEN val_len, const char *fmt) {
void *data_ptr = get_data();
SQLLEN *res_len_ptr = get_result_len();
if (res_len_ptr)
*res_len_ptr = std::min(val_len, get_size());
if (!data_ptr) {
if (res_len_ptr)
*res_len_ptr = val_len;
return conversion_result::AI_SUCCESS;
}
switch (m_type) {
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
auto *buffer = reinterpret_cast<char *>(data_ptr);
strftime(buffer, get_size(), fmt, &tm_time);
break;
}
case odbc_native_type::AI_WCHAR: {
auto *buffer = reinterpret_cast<SQLWCHAR *>(data_ptr);
auto *tmp = reinterpret_cast<char *>(alloca(val_len));
strftime(tmp, val_len, fmt, &tm_time);
string_to_wstring(&tmp[0], int64_t(val_len), buffer, get_size());
break;
}
default: {
return conversion_result::AI_UNSUPPORTED_CONVERSION;
}
}
if (SQLLEN(val_len) > get_size())
return conversion_result::AI_VARLEN_DATA_TRUNCATED;
return conversion_result::AI_SUCCESS;
}
std::string application_data_buffer::get_string(std::size_t maxLen) const {
std::string res;
switch (m_type) {
case odbc_native_type::AI_CHAR: {
std::size_t param_len = get_input_size();
if (!param_len)
break;
res = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
if (res.size() > maxLen)
res.resize(maxLen);
break;
}
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT: {
std::stringstream converter;
converter << get_num<int64_t>();
res = converter.str();
break;
}
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_BIGINT: {
std::stringstream converter;
converter << get_num<std::uint64_t>();
res = converter.str();
break;
}
case odbc_native_type::AI_FLOAT: {
std::stringstream converter;
converter << get_num<float>();
res = converter.str();
break;
}
case odbc_native_type::AI_NUMERIC:
case odbc_native_type::AI_DOUBLE: {
std::stringstream converter;
converter << get_num<double>();
res = converter.str();
break;
}
default:
break;
}
return res;
}
int8_t application_data_buffer::get_int8() const {
return get_num<int8_t>();
}
int16_t application_data_buffer::get_int16() const {
return get_num<int16_t>();
}
std::int32_t application_data_buffer::get_int32() const {
return get_num<std::int32_t>();
}
int64_t application_data_buffer::get_int64() const {
return get_num<int64_t>();
}
float application_data_buffer::get_float() const {
return get_num<float>();
}
double application_data_buffer::get_double() const {
return get_num<double>();
}
uuid application_data_buffer::get_uuid() const {
uuid res;
switch (m_type) {
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
std::stringstream converter;
converter << str;
converter >> res;
break;
}
case odbc_native_type::AI_GUID: {
const auto *guid = reinterpret_cast<const SQLGUID *>(get_data());
std::uint64_t msb = static_cast<std::uint64_t>(guid->Data1) << 32
| static_cast<std::uint64_t>(guid->Data2) << 16 | static_cast<std::uint64_t>(guid->Data3);
std::uint64_t lsb = 0;
for (std::size_t i = 0; i < sizeof(guid->Data4); ++i)
lsb |= std::uint64_t(guid->Data4[i]) << (sizeof(guid->Data4) - i - 1) * 8;
res = uuid(std::int64_t(msb), std::int64_t(lsb));
break;
}
default:
break;
}
return res;
}
const void *application_data_buffer::get_data() const {
return apply_offset(m_buffer, get_element_size());
}
const SQLLEN *application_data_buffer::get_result_len() const {
return apply_offset(m_result_len, sizeof(*m_result_len));
}
void *application_data_buffer::get_data() {
return apply_offset(m_buffer, get_element_size());
}
SQLLEN *application_data_buffer::get_result_len() {
return apply_offset(m_result_len, sizeof(*m_result_len));
}
template<typename T, typename V>
inline V LoadPrimitive(const void *data) {
T res = T();
std::memcpy(&res, data, sizeof(res));
return static_cast<V>(res);
}
template<typename T>
T application_data_buffer::get_num() const {
T res = T();
switch (m_type) {
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = get_string(param_len);
std::stringstream converter;
converter << str;
// Workaround for char types which are recognized as symbolic types and not numeric types.
if (sizeof(T) == 1) {
short tmp;
converter >> tmp;
res = static_cast<T>(tmp);
} else
converter >> res;
break;
}
case odbc_native_type::AI_SIGNED_TINYINT: {
res = LoadPrimitive<int8_t, T>(get_data());
break;
}
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT: {
res = LoadPrimitive<std::uint8_t, T>(get_data());
break;
}
case odbc_native_type::AI_SIGNED_SHORT: {
res = LoadPrimitive<int16_t, T>(get_data());
break;
}
case odbc_native_type::AI_UNSIGNED_SHORT: {
res = LoadPrimitive<uint16_t, T>(get_data());
break;
}
case odbc_native_type::AI_SIGNED_LONG: {
res = LoadPrimitive<std::int32_t, T>(get_data());
break;
}
case odbc_native_type::AI_UNSIGNED_LONG: {
res = LoadPrimitive<uint32_t, T>(get_data());
break;
}
case odbc_native_type::AI_SIGNED_BIGINT: {
res = LoadPrimitive<int64_t, T>(get_data());
break;
}
case odbc_native_type::AI_UNSIGNED_BIGINT: {
res = LoadPrimitive<std::uint64_t, T>(get_data());
break;
}
case odbc_native_type::AI_FLOAT: {
res = LoadPrimitive<float, T>(get_data());
break;
}
case odbc_native_type::AI_DOUBLE: {
res = LoadPrimitive<double, T>(get_data());
break;
}
case odbc_native_type::AI_NUMERIC: {
const auto *numeric = reinterpret_cast<const SQL_NUMERIC_STRUCT *>(get_data());
big_decimal dec(reinterpret_cast<const int8_t *>(numeric->val), SQL_MAX_NUMERIC_LEN, numeric->scale,
numeric->sign ? 1 : -1, false);
res = static_cast<T>(dec.to_int64());
break;
}
default:
break;
}
return res;
}
ignite_date application_data_buffer::get_date() const {
switch (m_type) {
case odbc_native_type::AI_TDATE: {
const auto *buffer = reinterpret_cast<const SQL_DATE_STRUCT *>(get_data());
return {buffer->year, buffer->month, buffer->day};
}
case odbc_native_type::AI_TTIMESTAMP: {
const auto *buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT *>(get_data());
return {buffer->year, buffer->month, buffer->day};
}
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
std::int32_t year;
std::int32_t month;
std::int32_t day_of_month;
sscanf(str.c_str(), "%d-%d-%d", &year, &month, &day_of_month); // NOLINT(cert-err34-c)
return {year, month, day_of_month};
}
default:
break;
}
return {};
}
ignite_date_time application_data_buffer::get_date_time() const {
switch (m_type) {
case odbc_native_type::AI_TDATE: {
const auto *buffer = reinterpret_cast<const SQL_DATE_STRUCT *>(get_data());
return {{buffer->year, buffer->month, buffer->day}, {}};
}
case odbc_native_type::AI_TTIME: {
const auto *buffer = reinterpret_cast<const SQL_TIME_STRUCT *>(get_data());
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto tm_time = time_t_to_tm(now);
// According to ODBC specification, date part of the value should be set to the current date.
return {{tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday},
{std::int8_t(buffer->hour), std::int8_t(buffer->minute), std::int8_t(buffer->second), 0}};
break;
}
case odbc_native_type::AI_TTIMESTAMP: {
const auto *buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT *>(get_data());
return {{buffer->year, buffer->month, buffer->day},
{std::int8_t(buffer->hour), std::int8_t(buffer->minute), std::int8_t(buffer->second),
std::int32_t(buffer->fraction)}};
break;
}
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
int year = 0;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
int nano = 0;
sscanf(str.c_str(), "%d-%d-%d %d:%d:%d.%d", // NOLINT(cert-err34-c)
&year, &month, &day, &hour, &minute, &second, &nano);
return {{year, month, day}, {std::int8_t(hour), std::int8_t(minute), std::int8_t(second), nano}};
}
default:
break;
}
return {};
}
ignite_timestamp application_data_buffer::get_timestamp() const {
tm tm_time{};
std::memset(&tm_time, 0, sizeof(tm_time));
tm_time.tm_isdst = -1;
std::int32_t nanos = 0;
switch (m_type) {
case odbc_native_type::AI_TDATE: {
const auto *buffer = reinterpret_cast<const SQL_DATE_STRUCT *>(get_data());
tm_time.tm_year = buffer->year - 1900;
tm_time.tm_mon = buffer->month - 1;
tm_time.tm_mday = buffer->day;
break;
}
case odbc_native_type::AI_TTIME: {
const auto *buffer = reinterpret_cast<const SQL_TIME_STRUCT *>(get_data());
tm_time.tm_year = 70;
tm_time.tm_mday = 1;
tm_time.tm_hour = buffer->hour;
tm_time.tm_min = buffer->minute;
tm_time.tm_sec = buffer->second;
break;
}
case odbc_native_type::AI_TTIMESTAMP: {
const auto *buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT *>(get_data());
tm_time.tm_year = buffer->year - 1900;
tm_time.tm_mon = buffer->month - 1;
tm_time.tm_mday = buffer->day;
tm_time.tm_hour = buffer->hour;
tm_time.tm_min = buffer->minute;
tm_time.tm_sec = buffer->second;
nanos = std::int32_t(buffer->fraction);
break;
}
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
sscanf(str.c_str(), "%d-%d-%d %d:%d:%d.%d", &tm_time.tm_year, &tm_time.tm_mon, // NOLINT(cert-err34-c)
&tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min, &tm_time.tm_sec, &nanos);
tm_time.tm_year = tm_time.tm_year - 1900;
tm_time.tm_mon = tm_time.tm_mon - 1;
break;
}
default:
break;
}
if (nanos < 0)
nanos = 0;
if (nanos > 999'999'999)
nanos = 999'999'999;
auto ctime = mktime(&tm_time);
return {ctime, nanos};
}
ignite_time application_data_buffer::get_time() const {
switch (m_type) {
case odbc_native_type::AI_TTIME: {
const auto *buffer = reinterpret_cast<const SQL_TIME_STRUCT *>(get_data());
return {std::int_fast8_t(buffer->hour), std::int_fast8_t(buffer->minute), std::int_fast8_t(buffer->second)};
}
case odbc_native_type::AI_TTIMESTAMP: {
const auto *buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT *>(get_data());
return {std::int_fast8_t(buffer->hour), std::int_fast8_t(buffer->minute), std::int_fast8_t(buffer->second),
std::int32_t(buffer->fraction)};
}
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = sql_string_to_string(
reinterpret_cast<const unsigned char *>(get_data()), static_cast<std::int32_t>(param_len));
std::int32_t hour{};
std::int32_t min{};
std::int32_t sec{};
std::int32_t nano{};
sscanf(str.c_str(), "%d:%d:%d.%d", &hour, &min, &sec, &nano); // NOLINT(cert-err34-c)
return {std::int8_t(hour), std::int8_t(min), std::int8_t(sec), nano};
}
default:
break;
}
return {};
}
void application_data_buffer::get_decimal(big_decimal &val) const {
switch (m_type) {
case odbc_native_type::AI_CHAR: {
SQLLEN param_len = get_input_size();
if (!param_len)
break;
std::string str = get_string(param_len);
std::stringstream converter;
converter << str;
converter >> val;
break;
}
case odbc_native_type::AI_SIGNED_TINYINT:
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_SIGNED_SHORT:
case odbc_native_type::AI_SIGNED_LONG:
case odbc_native_type::AI_SIGNED_BIGINT: {
val.assign_int64(get_num<int64_t>());
break;
}
case odbc_native_type::AI_UNSIGNED_TINYINT:
case odbc_native_type::AI_UNSIGNED_SHORT:
case odbc_native_type::AI_UNSIGNED_LONG:
case odbc_native_type::AI_UNSIGNED_BIGINT: {
val.assign_uint64(get_num<std::uint64_t>());
break;
}
case odbc_native_type::AI_FLOAT:
case odbc_native_type::AI_DOUBLE: {
val.assign_double(get_num<double>());
break;
}
case odbc_native_type::AI_NUMERIC: {
const auto *numeric = reinterpret_cast<const SQL_NUMERIC_STRUCT *>(get_data());
big_decimal dec(reinterpret_cast<const int8_t *>(numeric->val), SQL_MAX_NUMERIC_LEN, numeric->scale,
numeric->sign ? 1 : -1, false);
swap(val, dec);
break;
}
default: {
val.assign_int64(0);
break;
}
}
}
template<typename T>
T *application_data_buffer::apply_offset(T *ptr, std::size_t elemSize) const {
if (!ptr)
return ptr;
return get_pointer_with_offset(ptr, m_byte_offset + elemSize * m_element_offset);
}
bool application_data_buffer::is_data_at_exec() const {
const SQLLEN *res_len_ptr = get_result_len();
if (!res_len_ptr)
return false;
auto s_len = static_cast<std::int32_t>(*res_len_ptr);
return s_len <= SQL_LEN_DATA_AT_EXEC_OFFSET || s_len == SQL_DATA_AT_EXEC;
}
SQLLEN application_data_buffer::get_data_at_exec_size() const {
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY: {
const SQLLEN *res_len_ptr = get_result_len();
if (!res_len_ptr)
return 0;
auto s_len = static_cast<std::int32_t>(*res_len_ptr);
if (s_len <= SQL_LEN_DATA_AT_EXEC_OFFSET)
s_len = SQL_LEN_DATA_AT_EXEC(s_len);
else
s_len = 0;
if (m_type == odbc_native_type::AI_WCHAR)
s_len *= 2;
return s_len;
}
case odbc_native_type::AI_SIGNED_SHORT:
return static_cast<SQLLEN>(sizeof(SQLSMALLINT));
case odbc_native_type::AI_UNSIGNED_SHORT:
return static_cast<SQLLEN>(sizeof(SQLUSMALLINT));
case odbc_native_type::AI_SIGNED_LONG:
return static_cast<SQLLEN>(sizeof(SQLINTEGER));
case odbc_native_type::AI_UNSIGNED_LONG:
return static_cast<SQLLEN>(sizeof(SQLUINTEGER));
case odbc_native_type::AI_FLOAT:
return static_cast<SQLLEN>(sizeof(SQLFLOAT));
case odbc_native_type::AI_DOUBLE:
return static_cast<SQLLEN>(sizeof(SQLDOUBLE));
case odbc_native_type::AI_BIT:
return static_cast<SQLLEN>(sizeof(SQLCHAR));
case odbc_native_type::AI_SIGNED_TINYINT:
return static_cast<SQLLEN>(sizeof(SQLSCHAR));
case odbc_native_type::AI_UNSIGNED_TINYINT:
return static_cast<SQLLEN>(sizeof(SQLCHAR));
case odbc_native_type::AI_SIGNED_BIGINT:
case odbc_native_type::AI_UNSIGNED_BIGINT:
return static_cast<SQLLEN>(sizeof(SQLBIGINT));
case odbc_native_type::AI_TDATE:
return static_cast<SQLLEN>(sizeof(SQL_DATE_STRUCT));
case odbc_native_type::AI_TTIME:
return static_cast<SQLLEN>(sizeof(SQL_TIME_STRUCT));
case odbc_native_type::AI_TTIMESTAMP:
return static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
case odbc_native_type::AI_NUMERIC:
return static_cast<SQLLEN>(sizeof(SQL_NUMERIC_STRUCT));
case odbc_native_type::AI_GUID:
return static_cast<SQLLEN>(sizeof(SQLGUID));
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_UNSUPPORTED:
default:
break;
}
return 0;
}
SQLLEN application_data_buffer::get_element_size() const {
switch (m_type) {
case odbc_native_type::AI_WCHAR:
case odbc_native_type::AI_CHAR:
case odbc_native_type::AI_BINARY:
return m_buffer_len;
case odbc_native_type::AI_SIGNED_SHORT:
return static_cast<SQLLEN>(sizeof(SQLSMALLINT));
case odbc_native_type::AI_UNSIGNED_SHORT:
return static_cast<SQLLEN>(sizeof(SQLUSMALLINT));
case odbc_native_type::AI_SIGNED_LONG:
return static_cast<SQLLEN>(sizeof(SQLUINTEGER));
case odbc_native_type::AI_UNSIGNED_LONG:
return static_cast<SQLLEN>(sizeof(SQLINTEGER));
case odbc_native_type::AI_FLOAT:
return static_cast<SQLLEN>(sizeof(SQLREAL));
case odbc_native_type::AI_DOUBLE:
return static_cast<SQLLEN>(sizeof(SQLDOUBLE));
case odbc_native_type::AI_SIGNED_TINYINT:
return static_cast<SQLLEN>(sizeof(SQLSCHAR));
case odbc_native_type::AI_BIT:
case odbc_native_type::AI_UNSIGNED_TINYINT:
return static_cast<SQLLEN>(sizeof(SQLCHAR));
case odbc_native_type::AI_SIGNED_BIGINT:
return static_cast<SQLLEN>(sizeof(SQLBIGINT));
case odbc_native_type::AI_UNSIGNED_BIGINT:
return static_cast<SQLLEN>(sizeof(SQLUBIGINT));
case odbc_native_type::AI_TDATE:
return static_cast<SQLLEN>(sizeof(SQL_DATE_STRUCT));
case odbc_native_type::AI_TTIME:
return static_cast<SQLLEN>(sizeof(SQL_TIME_STRUCT));
case odbc_native_type::AI_TTIMESTAMP:
return static_cast<SQLLEN>(sizeof(SQL_TIMESTAMP_STRUCT));
case odbc_native_type::AI_NUMERIC:
return static_cast<SQLLEN>(sizeof(SQL_NUMERIC_STRUCT));
case odbc_native_type::AI_GUID:
return static_cast<SQLLEN>(sizeof(SQLGUID));
case odbc_native_type::AI_DEFAULT:
case odbc_native_type::AI_UNSUPPORTED:
default:
break;
}
return 0;
}
SQLLEN application_data_buffer::get_input_size() const {
if (!is_data_at_exec()) {
const SQLLEN *len = get_result_len();
return len ? *len : SQL_NTS;
}
return get_data_at_exec_size();
}
} // namespace ignite