Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6B8062007D1 for ; Thu, 12 May 2016 08:41:59 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 67839160A2B; Thu, 12 May 2016 06:41:59 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 492EF160A1B for ; Thu, 12 May 2016 08:41:57 +0200 (CEST) Received: (qmail 74412 invoked by uid 500); 12 May 2016 06:41:56 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 74221 invoked by uid 99); 12 May 2016 06:41:56 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 May 2016 06:41:56 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id CD239E032D; Thu, 12 May 2016 06:41:55 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: akuznetsov@apache.org To: commits@ignite.apache.org Date: Thu, 12 May 2016 06:41:59 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [05/60] [abbrv] ignite git commit: IGNITE-1786: Implemented ODBC driver. archived-at: Thu, 12 May 2016 06:41:59 -0000 http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp new file mode 100644 index 0000000..600dc86 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp @@ -0,0 +1,1216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "ignite/impl/binary/binary_utils.h" + +#include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/app/application_data_buffer.h" +#include "ignite/odbc/utility.h" + +namespace ignite +{ + namespace odbc + { + namespace app + { + using ignite::impl::binary::BinaryUtils; + + ApplicationDataBuffer::ApplicationDataBuffer() : + type(type_traits::IGNITE_ODBC_C_TYPE_UNSUPPORTED), buffer(0), buflen(0), reslen(0), offset(0) + { + // No-op. + } + + ApplicationDataBuffer::ApplicationDataBuffer(type_traits::IgniteSqlType type, + void* buffer, SqlLen buflen, SqlLen* reslen, size_t** offset) : + type(type), buffer(buffer), buflen(buflen), reslen(reslen), offset(offset) + { + // No-op. + } + + ApplicationDataBuffer::ApplicationDataBuffer(const ApplicationDataBuffer & other) : + type(other.type), buffer(other.buffer), buflen(other.buflen), reslen(other.reslen), offset(other.offset) + { + // No-op. + } + + ApplicationDataBuffer::~ApplicationDataBuffer() + { + // No-op. + } + + ApplicationDataBuffer & ApplicationDataBuffer::operator=(const ApplicationDataBuffer & other) + { + type = other.type; + buffer = other.buffer; + buflen = other.buflen; + reslen = other.reslen; + offset = other.offset; + + return *this; + } + + template + void ApplicationDataBuffer::PutNum(T value) + { + using namespace type_traits; + switch (type) + { + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_FLOAT: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_DOUBLE: + { + PutNumToNumBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_CHAR: + { + PutValToStrBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + PutValToStrBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_NUMERIC: + { + if (GetData()) + { + SQL_NUMERIC_STRUCT* out = + reinterpret_cast(GetData()); + + out->precision = 20; // Max int64_t precision + out->scale = 0; + out->sign = value < 0 ? 2 : 1; + + memset(out->val, 0, SQL_MAX_NUMERIC_LEN); + + int64_t intVal = static_cast(std::abs(value)); + + memcpy(out->val, &intVal, std::min(SQL_MAX_NUMERIC_LEN, sizeof(intVal))); + } + break; + } + + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + if (GetData()) + { + if (buflen >= sizeof(value)) + { + memcpy(GetData(), &value, sizeof(value)); + + if (GetResLen()) + *GetResLen() = sizeof(value); + } + else + { + memcpy(GetData(), &value, static_cast(buflen)); + + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + else if (GetResLen()) + { + *GetResLen() = sizeof(value); + } + break; + } + + case IGNITE_ODBC_C_TYPE_TDATE: + { + PutDate(Date(static_cast(value))); + + break; + } + + case IGNITE_ODBC_C_TYPE_TTIMESTAMP: + { + PutTimestamp(Timestamp(static_cast(value))); + + break; + } + + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + } + + template + void ApplicationDataBuffer::PutNumToNumBuffer(Tin value) + { + if (GetData()) + { + Tbuf* out = reinterpret_cast(GetData()); + *out = static_cast(value); + } + } + + template + void ApplicationDataBuffer::PutValToStrBuffer(const Tin & value) + { + typedef std::basic_stringstream ConverterType; + + ConverterType converter; + + converter << value; + + PutStrToStrBuffer(converter.str()); + } + + template + void ApplicationDataBuffer::PutValToStrBuffer(const int8_t & value) + { + typedef std::basic_stringstream ConverterType; + + ConverterType converter; + + converter << static_cast(value); + + PutStrToStrBuffer(converter.str()); + } + + template + void ApplicationDataBuffer::PutStrToStrBuffer(const std::basic_string& value) + { + SqlLen charSize = static_cast(sizeof(OutCharT)); + + if (GetData()) + { + if (buflen >= charSize) + { + OutCharT* out = reinterpret_cast(GetData()); + + SqlLen outLen = (buflen / charSize) - 1; + + SqlLen toCopy = std::min(outLen, value.size()); + + for (SqlLen i = 0; i < toCopy; ++i) + out[i] = value[i]; + + out[toCopy] = 0; + } + + if (GetResLen()) + { + if (buflen >= static_cast((value.size() + 1) * charSize)) + *GetResLen() = static_cast(value.size()); + else + *GetResLen() = SQL_NO_TOTAL; + } + } + else if (GetResLen()) + *GetResLen() = value.size(); + } + + void ApplicationDataBuffer::PutRawDataToBuffer(void *data, size_t len) + { + SqlLen ilen = static_cast(len); + + if (GetData()) + { + size_t toCopy = static_cast(std::min(buflen, ilen)); + + memcpy(GetData(), data, toCopy); + + if (GetResLen()) + { + if (buflen >= ilen) + *GetResLen() = ilen; + else + *GetResLen() = SQL_NO_TOTAL; + } + } + else if (GetResLen()) + *GetResLen() = ilen; + } + + void ApplicationDataBuffer::PutInt8(int8_t value) + { + PutNum(value); + } + + void ApplicationDataBuffer::PutInt16(int16_t value) + { + PutNum(value); + } + + void ApplicationDataBuffer::PutInt32(int32_t value) + { + PutNum(value); + } + + void ApplicationDataBuffer::PutInt64(int64_t value) + { + PutNum(value); + } + + void ApplicationDataBuffer::PutFloat(float value) + { + PutNum(value); + } + + void ApplicationDataBuffer::PutDouble(double value) + { + PutNum(value); + } + + int32_t ApplicationDataBuffer::PutString(const std::string & value) + { + using namespace type_traits; + + int32_t used = 0; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_NUMERIC: + { + std::stringstream converter(value); + + int64_t numValue; + + converter >> numValue; + + PutNum(numValue); + + used = static_cast(value.size()); + + break; + } + + case IGNITE_ODBC_C_TYPE_FLOAT: + case IGNITE_ODBC_C_TYPE_DOUBLE: + { + std::stringstream converter(value); + + double numValue; + + converter >> numValue; + + PutNum(numValue); + + used = static_cast(value.size()); + + break; + } + + case IGNITE_ODBC_C_TYPE_CHAR: + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + PutStrToStrBuffer(value); + + used = static_cast(GetSize()) - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + PutStrToStrBuffer(value); + + used = (static_cast(GetSize()) / 2) - 1; + + break; + } + + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + + return used < 0 ? 0 : used; + } + + void ApplicationDataBuffer::PutGuid(const Guid & value) + { + using namespace type_traits; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + PutValToStrBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + PutValToStrBuffer(value); + break; + } + + case IGNITE_ODBC_C_TYPE_GUID: + { + SQLGUID* guid = reinterpret_cast(GetData()); + + guid->Data1 = static_cast(value.GetMostSignificantBits() >> 32); + guid->Data2 = static_cast(value.GetMostSignificantBits() >> 16); + guid->Data3 = static_cast(value.GetMostSignificantBits()); + + uint64_t lsb = value.GetLeastSignificantBits(); + for (size_t i = 0; i < sizeof(guid->Data4); ++i) + guid->Data4[i] = (lsb >> (sizeof(guid->Data4) - i - 1) * 8) & 0xFF; + + break; + } + + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + } + + int32_t ApplicationDataBuffer::PutBinaryData(void *data, size_t len) + { + using namespace type_traits; + + int32_t used = 0; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + PutRawDataToBuffer(data, len); + + used = static_cast(GetSize()); + + break; + } + + case IGNITE_ODBC_C_TYPE_CHAR: + { + std::stringstream converter; + + uint8_t *dataBytes = reinterpret_cast(data); + + for (size_t i = 0; i < len; ++i) + { + converter << std::hex + << std::setfill('0') + << std::setw(2) + << static_cast(dataBytes[i]); + } + + PutStrToStrBuffer(converter.str()); + + used = static_cast(GetSize()) - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + std::wstringstream converter; + + uint8_t *dataBytes = reinterpret_cast(data); + + for (size_t i = 0; i < len; ++i) + { + converter << std::hex + << std::setfill('0') + << std::setw(2) + << static_cast(dataBytes[i]); + } + + PutStrToStrBuffer(converter.str()); + + used = static_cast(GetSize() / 2) - 1; + + break; + } + + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + + return used < 0 ? 0 : used; + } + + void ApplicationDataBuffer::PutNull() + { + if (GetResLen()) + *GetResLen() = SQL_NULL_DATA; + } + + void ApplicationDataBuffer::PutDecimal(const Decimal& value) + { + using namespace type_traits; + switch (type) + { + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_FLOAT: + case IGNITE_ODBC_C_TYPE_DOUBLE: + case IGNITE_ODBC_C_TYPE_CHAR: + case IGNITE_ODBC_C_TYPE_WCHAR: + case IGNITE_ODBC_C_TYPE_NUMERIC: + { + PutNum(static_cast(value)); + + break; + } + + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + if (GetData()) + memcpy(GetData(), &value, std::min(static_cast(buflen), sizeof(value))); + + if (GetResLen()) + *GetResLen() = sizeof(value); + + break; + } + + case IGNITE_ODBC_C_TYPE_BINARY: + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + } + + void ApplicationDataBuffer::PutDate(const Date& value) + { + using namespace type_traits; + + tm tmTime; + + BinaryUtils::DateToCTm(value, tmTime); + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + { + char* buffer = reinterpret_cast(GetData()); + + if (buffer) + { + strftime(buffer, GetSize(), "%Y-%m-%d", &tmTime); + + if (GetResLen()) + *GetResLen() = strlen(buffer); + } + else if (GetResLen()) + *GetResLen() = sizeof("HHHH-MM-DD") - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + SQLWCHAR* buffer = reinterpret_cast(GetData()); + + if (buffer) + { + std::string tmp(GetSize(), 0); + + strftime(&tmp[0], GetSize(), "%Y-%m-%d", &tmTime); + + SqlLen toCopy = std::min(static_cast(strlen(tmp.c_str()) + 1), GetSize()); + + for (SqlLen i = 0; i < toCopy; ++i) + buffer[i] = tmp[i]; + + buffer[toCopy] = 0; + + if (GetResLen()) + *GetResLen() = toCopy; + } + else if (GetResLen()) + *GetResLen() = sizeof("HHHH-MM-DD") - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_TDATE: + { + SQL_DATE_STRUCT* buffer = reinterpret_cast(GetData()); + + buffer->year = tmTime.tm_year + 1900; + buffer->month = tmTime.tm_mon + 1; + buffer->day = tmTime.tm_mday; + + break; + } + + case IGNITE_ODBC_C_TYPE_TTIMESTAMP: + { + SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast(GetData()); + + buffer->year = tmTime.tm_year + 1900; + buffer->month = tmTime.tm_mon + 1; + buffer->day = tmTime.tm_mday; + buffer->hour = tmTime.tm_hour; + buffer->minute = tmTime.tm_min; + buffer->second = tmTime.tm_sec; + buffer->fraction = 0; + + break; + } + + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + if (GetData()) + memcpy(GetData(), &value, std::min(static_cast(buflen), sizeof(value))); + + if (GetResLen()) + *GetResLen() = sizeof(value); + + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_FLOAT: + case IGNITE_ODBC_C_TYPE_DOUBLE: + case IGNITE_ODBC_C_TYPE_NUMERIC: + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + } + + void ApplicationDataBuffer::PutTimestamp(const Timestamp& value) + { + using namespace type_traits; + + tm tmTime; + + BinaryUtils::TimestampToCTm(value, tmTime); + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + { + char* buffer = reinterpret_cast(GetData()); + + if (buffer) + { + strftime(buffer, GetSize(), "%Y-%m-%d %H:%M:%S", &tmTime); + + if (GetResLen()) + *GetResLen() = strlen(buffer); + } + else if (GetResLen()) + *GetResLen() = sizeof("HHHH-MM-DD HH:MM:SS") - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_WCHAR: + { + SQLWCHAR* buffer = reinterpret_cast(GetData()); + + if (buffer) + { + std::string tmp(GetSize(), 0); + + strftime(&tmp[0], GetSize(), "%Y-%m-%d %H:%M:%S", &tmTime); + + SqlLen toCopy = std::min(static_cast(strlen(tmp.c_str()) + 1), GetSize()); + + for (SqlLen i = 0; i < toCopy; ++i) + buffer[i] = tmp[i]; + + buffer[toCopy] = 0; + + if (GetResLen()) + *GetResLen() = toCopy; + } + else if (GetResLen()) + *GetResLen() = sizeof("HHHH-MM-DD HH:MM:SS") - 1; + + break; + } + + case IGNITE_ODBC_C_TYPE_TDATE: + { + SQL_DATE_STRUCT* buffer = reinterpret_cast(GetData()); + + buffer->year = tmTime.tm_year + 1900; + buffer->month = tmTime.tm_mon + 1; + buffer->day = tmTime.tm_mday; + + break; + } + + case IGNITE_ODBC_C_TYPE_TTIMESTAMP: + { + SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast(GetData()); + + buffer->year = tmTime.tm_year + 1900; + buffer->month = tmTime.tm_mon + 1; + buffer->day = tmTime.tm_mday; + buffer->hour = tmTime.tm_hour; + buffer->minute = tmTime.tm_min; + buffer->second = tmTime.tm_sec; + buffer->fraction = value.GetSecondFraction(); + + break; + } + + case IGNITE_ODBC_C_TYPE_BINARY: + case IGNITE_ODBC_C_TYPE_DEFAULT: + { + if (GetData()) + memcpy(GetData(), &value, std::min(static_cast(buflen), sizeof(value))); + + if (GetResLen()) + *GetResLen() = sizeof(value); + + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + case IGNITE_ODBC_C_TYPE_FLOAT: + case IGNITE_ODBC_C_TYPE_DOUBLE: + case IGNITE_ODBC_C_TYPE_NUMERIC: + default: + { + if (GetResLen()) + *GetResLen() = SQL_NO_TOTAL; + } + } + } + + std::string ApplicationDataBuffer::GetString(size_t maxLen) const + { + using namespace type_traits; + std::string res; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + { + res.assign(reinterpret_cast(GetData()), + std::min(maxLen, static_cast(buflen))); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + { + std::stringstream converter; + + converter << GetNum(); + + res = converter.str(); + + break; + } + + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + { + std::stringstream converter; + + converter << GetNum(); + + res = converter.str(); + + break; + } + + case IGNITE_ODBC_C_TYPE_FLOAT: + { + std::stringstream converter; + + converter << GetNum(); + + res = converter.str(); + + break; + } + + case IGNITE_ODBC_C_TYPE_NUMERIC: + case IGNITE_ODBC_C_TYPE_DOUBLE: + { + std::stringstream converter; + + converter << GetNum(); + + res = converter.str(); + + break; + } + + default: + break; + } + + return res; + } + + int8_t ApplicationDataBuffer::GetInt8() const + { + return GetNum(); + } + + int16_t ApplicationDataBuffer::GetInt16() const + { + return GetNum(); + } + + int32_t ApplicationDataBuffer::GetInt32() const + { + return GetNum(); + } + + int64_t ApplicationDataBuffer::GetInt64() const + { + return GetNum(); + } + + float ApplicationDataBuffer::GetFloat() const + { + return GetNum(); + } + + double ApplicationDataBuffer::GetDouble() const + { + return GetNum(); + } + + Guid ApplicationDataBuffer::GetGuid() const + { + using namespace type_traits; + + Guid res; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + { + std::string str(reinterpret_cast(GetData()), static_cast(buflen)); + + std::stringstream converter(str); + + converter >> res; + + break; + } + + case IGNITE_ODBC_C_TYPE_GUID: + { + const SQLGUID* guid = reinterpret_cast(GetData()); + + uint64_t msb = static_cast(guid->Data1) << 32 | + static_cast(guid->Data2) << 16 | + static_cast(guid->Data3); + + uint64_t lsb = 0; + + for (size_t i = 0; i < sizeof(guid->Data4); ++i) + lsb = guid->Data4[i] << (sizeof(guid->Data4) - i - 1) * 8; + + res = Guid(msb, lsb); + + break; + } + + default: + break; + } + + return res; + } + + const void* ApplicationDataBuffer::GetData() const + { + return ApplyOffset(buffer); + } + + const SqlLen* ApplicationDataBuffer::GetResLen() const + { + return ApplyOffset(reslen); + } + + void* ApplicationDataBuffer::GetData() + { + return ApplyOffset(buffer); + } + + SqlLen* ApplicationDataBuffer::GetResLen() + { + return ApplyOffset(reslen); + } + + template + T ApplicationDataBuffer::GetNum() const + { + using namespace type_traits; + + T res = 0; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_CHAR: + { + std::string str = GetString(static_cast(buflen)); + + std::stringstream converter(str); + + // Workaround for char types which are recognised as + // symbolyc types and not numeric types. + if (sizeof(T) == 1) + { + short tmp; + + converter >> tmp; + + res = static_cast(tmp); + } + else + converter >> res; + + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_BIT: + case IGNITE_ODBC_C_TYPE_UNSIGNED_TINYINT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_SHORT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_SHORT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_LONG: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_LONG: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_SIGNED_BIGINT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_UNSIGNED_BIGINT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_FLOAT: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_DOUBLE: + { + res = static_cast(*reinterpret_cast(GetData())); + break; + } + + case IGNITE_ODBC_C_TYPE_NUMERIC: + { + const SQL_NUMERIC_STRUCT* numeric = + reinterpret_cast(GetData()); + + int64_t resInt; + + // TODO: implement propper conversation from numeric type. + memcpy(&resInt, numeric->val, std::min(SQL_MAX_NUMERIC_LEN, sizeof(resInt))); + + if (numeric->sign == 2) + resInt *= -1; + + double resDouble = static_cast(resInt); + + for (SQLSCHAR scale = numeric->scale; scale > 0; --scale) + resDouble /= 10.0; + + res = static_cast(resDouble); + + break; + } + + default: + break; + } + + return res; + } + + Date ApplicationDataBuffer::GetDate() const + { + using namespace type_traits; + + tm tmTime = { 0 }; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_TDATE: + { + const SQL_DATE_STRUCT* buffer = reinterpret_cast(GetData()); + + tmTime.tm_year = buffer->year - 1900; + tmTime.tm_mon = buffer->month - 1; + tmTime.tm_mday = buffer->day; + + break; + } + + case IGNITE_ODBC_C_TYPE_TTIMESTAMP: + { + const SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast(GetData()); + + tmTime.tm_year = buffer->year - 1900; + tmTime.tm_mon = buffer->month - 1; + tmTime.tm_mday = buffer->day; + tmTime.tm_hour = buffer->hour; + tmTime.tm_min = buffer->minute; + tmTime.tm_sec = buffer->second; + + break; + } + + case IGNITE_ODBC_C_TYPE_CHAR: + { + std::string str = utility::SqlStringToString( + reinterpret_cast(GetData()), + static_cast(GetSize())); + + sscanf(str.c_str(), "%d-%d-%d %d:%d:%d", &tmTime.tm_year, &tmTime.tm_mon, + &tmTime.tm_mday, &tmTime.tm_hour, &tmTime.tm_min, &tmTime.tm_sec); + + tmTime.tm_year = tmTime.tm_year - 1900; + tmTime.tm_mon = tmTime.tm_mon - 1; + + break; + } + + default: + break; + } + + return BinaryUtils::CTmToDate(tmTime); + } + + Timestamp ApplicationDataBuffer::GetTimestamp() const + { + using namespace type_traits; + + tm tmTime = { 0 }; + + int32_t nanos = 0; + + switch (type) + { + case IGNITE_ODBC_C_TYPE_TDATE: + { + const SQL_DATE_STRUCT* buffer = reinterpret_cast(GetData()); + + tmTime.tm_year = buffer->year - 1900; + tmTime.tm_mon = buffer->month - 1; + tmTime.tm_mday = buffer->day; + + break; + } + + case IGNITE_ODBC_C_TYPE_TTIMESTAMP: + { + const SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast(GetData()); + + tmTime.tm_year = buffer->year - 1900; + tmTime.tm_mon = buffer->month - 1; + tmTime.tm_mday = buffer->day; + tmTime.tm_hour = buffer->hour; + tmTime.tm_min = buffer->minute; + tmTime.tm_sec = buffer->second; + + nanos = buffer->fraction; + + break; + } + + case IGNITE_ODBC_C_TYPE_CHAR: + { + std::string str = utility::SqlStringToString( + reinterpret_cast(GetData()), + static_cast(GetSize())); + + sscanf(str.c_str(), "%d-%d-%d %d:%d:%d", &tmTime.tm_year, &tmTime.tm_mon, + &tmTime.tm_mday, &tmTime.tm_hour, &tmTime.tm_min, &tmTime.tm_sec); + + tmTime.tm_year = tmTime.tm_year - 1900; + tmTime.tm_mon = tmTime.tm_mon - 1; + + break; + } + + default: + break; + } + + return BinaryUtils::CTmToTimestamp(tmTime, nanos); + } + + template + T* ApplicationDataBuffer::ApplyOffset(T* ptr) const + { + if (!ptr || !offset || !*offset) + return ptr; + + return utility::GetPointerWithOffset(ptr, **offset); + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/app/parameter.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/app/parameter.cpp b/modules/platforms/cpp/odbc/src/app/parameter.cpp new file mode 100644 index 0000000..3ced3e8 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/app/parameter.cpp @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/app/parameter.h" +#include "ignite/odbc/utility.h" + +namespace ignite +{ + namespace odbc + { + namespace app + { + Parameter::Parameter() : + buffer(), + sqlType(), + columnSize(), + decDigits() + { + // No-op. + } + + Parameter::Parameter(const ApplicationDataBuffer& buffer, int16_t sqlType, + size_t columnSize, int16_t decDigits) : + buffer(buffer), + sqlType(sqlType), + columnSize(columnSize), + decDigits(decDigits) + { + // No-op. + } + + Parameter::Parameter(const Parameter & other) : + buffer(other.buffer), + sqlType(other.sqlType), + columnSize(other.columnSize), + decDigits(other.decDigits) + { + // No-op. + } + + Parameter::~Parameter() + { + // No-op. + } + + Parameter& Parameter::operator=(const Parameter &other) + { + buffer = other.buffer; + sqlType = other.sqlType; + columnSize = other.columnSize; + decDigits = other.decDigits; + + return *this; + } + + void Parameter::Write(ignite::impl::binary::BinaryWriterImpl& writer) const + { + switch (sqlType) + { + case SQL_CHAR: + case SQL_VARCHAR: + case SQL_LONGVARCHAR: + { + utility::WriteString(writer, buffer.GetString(columnSize)); + break; + } + + case SQL_SMALLINT: + { + writer.WriteInt16(buffer.GetInt16()); + break; + } + + case SQL_INTEGER: + { + writer.WriteInt32(buffer.GetInt32()); + break; + } + + case SQL_FLOAT: + { + writer.WriteFloat(buffer.GetFloat()); + break; + } + + case SQL_DOUBLE: + { + writer.WriteDouble(buffer.GetDouble()); + break; + } + + case SQL_TINYINT: + { + writer.WriteInt8(buffer.GetInt8()); + break; + } + + case SQL_BIT: + { + writer.WriteBool(buffer.GetInt8() != 0); + break; + } + + case SQL_BIGINT: + { + writer.WriteInt64(buffer.GetInt64()); + break; + } + + case SQL_DATE: + { + writer.WriteDate(buffer.GetDate()); + break; + } + + case SQL_TIMESTAMP: + { + writer.WriteTimestamp(buffer.GetTimestamp()); + break; + } + + case SQL_BINARY: + case SQL_VARBINARY: + case SQL_LONGVARBINARY: + { + writer.WriteInt8Array(reinterpret_cast(buffer.GetData()), + static_cast(buffer.GetSize())); + break; + } + + case SQL_GUID: + { + writer.WriteGuid(buffer.GetGuid()); + + break; + } + + case SQL_DECIMAL: + { + //TODO: Add Decimal type support. + break; + } + + default: + break; + } + } + + ApplicationDataBuffer & Parameter::GetBuffer() + { + return buffer; + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/column.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/column.cpp b/modules/platforms/cpp/odbc/src/column.cpp new file mode 100644 index 0000000..61a55ca --- /dev/null +++ b/modules/platforms/cpp/odbc/src/column.cpp @@ -0,0 +1,488 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ignite/odbc/utility.h" +#include "ignite/odbc/column.h" + +namespace +{ + using namespace ignite::impl::interop; + using namespace ignite::impl::binary; + + bool GetObjectLength(InteropInputStream& stream, int32_t& len) + { + InteropStreamPositionGuard guard(stream); + + int8_t hdr = stream.ReadInt8(); + + if (hdr != IGNITE_HDR_FULL) + return false; + + int8_t protoVer = stream.ReadInt8(); + + if (protoVer != IGNITE_PROTO_VER) + return false; + + // Skipping flags + stream.ReadInt16(); + + // Skipping typeId + stream.ReadInt32(); + + // Skipping hash code + stream.ReadInt32(); + + len = stream.ReadInt32(); + + return true; + } + + /** + * Read column header and restores position if the column is of + * complex type. + * @return Column type header. + */ + int8_t ReadColumnHeader(ignite::impl::interop::InteropInputStream& stream) + { + using namespace ignite::impl::binary; + + int32_t headerPos = stream.Position(); + + int8_t hdr = stream.ReadInt8(); + + // Check if we need to restore position - to read complex types + // stream should have unread header, but for primitive types it + // should not. + switch (hdr) + { + case IGNITE_TYPE_BYTE: + case IGNITE_TYPE_SHORT: + case IGNITE_TYPE_CHAR: + case IGNITE_TYPE_INT: + case IGNITE_TYPE_LONG: + case IGNITE_TYPE_FLOAT: + case IGNITE_TYPE_DOUBLE: + case IGNITE_TYPE_BOOL: + case IGNITE_HDR_NULL: + { + // No-op. + break; + } + + default: + { + // Restoring position. + stream.Position(headerPos); + break; + } + } + + return hdr; + } +} + +namespace ignite +{ + namespace odbc + { + Column::Column() : + type(0), startPos(-1), endPos(-1), offset(0), size(0) + { + // No-op. + } + + Column::Column(const Column& other) : + type(other.type), startPos(other.startPos), endPos(other.endPos), + offset(other.offset), size(other.size) + { + // No-op. + } + + Column& Column::operator=(const Column& other) + { + type = other.type; + startPos = other.startPos; + endPos = other.endPos; + offset = other.offset; + size = other.size; + + return *this; + } + + Column::~Column() + { + // No-op. + } + + Column::Column(ignite::impl::binary::BinaryReaderImpl& reader) : + type(0), startPos(-1), endPos(-1), offset(0), size(0) + { + ignite::impl::interop::InteropInputStream* stream = reader.GetStream(); + + if (!stream) + return; + + InteropStreamPositionGuard guard(*stream); + + int32_t sizeTmp = 0; + + int8_t hdr = ReadColumnHeader(*stream); + + int32_t startPosTmp = stream->Position(); + + switch (hdr) + { + case IGNITE_HDR_NULL: + { + sizeTmp = 1; + + break; + } + + case IGNITE_TYPE_BYTE: + { + reader.ReadInt8(); + + sizeTmp = 1; + + break; + } + + case IGNITE_TYPE_BOOL: + { + reader.ReadBool(); + + sizeTmp = 1; + + break; + } + + case IGNITE_TYPE_SHORT: + case IGNITE_TYPE_CHAR: + { + reader.ReadInt16(); + + sizeTmp = 2; + + break; + } + + case IGNITE_TYPE_FLOAT: + { + reader.ReadFloat(); + + sizeTmp = 4; + + break; + } + + case IGNITE_TYPE_INT: + { + reader.ReadInt32(); + + sizeTmp = 4; + + break; + } + + case IGNITE_TYPE_DOUBLE: + { + reader.ReadDouble(); + + sizeTmp = 8; + + break; + } + + case IGNITE_TYPE_LONG: + { + reader.ReadInt64(); + + sizeTmp = 8; + + break; + } + + case IGNITE_TYPE_STRING: + { + std::string str; + utility::ReadString(reader, str); + + sizeTmp = static_cast(str.size()); + + break; + } + + case IGNITE_TYPE_UUID: + { + reader.ReadGuid(); + + sizeTmp = 16; + + break; + } + + case IGNITE_HDR_FULL: + { + int32_t len; + + if (!GetObjectLength(*stream, len)) + return; + + sizeTmp = len; + + stream->Position(stream->Position() + len); + + break; + } + + case IGNITE_TYPE_DECIMAL: + { + Decimal res; + + utility::ReadDecimal(reader, res); + + sizeTmp = res.GetLength() + 8; + + break; + } + + case IGNITE_TYPE_DATE: + { + reader.ReadDate(); + + sizeTmp = 8; + + break; + } + + case IGNITE_TYPE_TIMESTAMP: + { + reader.ReadTimestamp(); + + sizeTmp = 12; + + break; + } + + default: + { + // This is a fail case. + return; + } + } + + type = hdr; + startPos = startPosTmp; + endPos = stream->Position(); + size = sizeTmp; + } + + SqlResult Column::ReadToBuffer(ignite::impl::binary::BinaryReaderImpl& reader, + app::ApplicationDataBuffer& dataBuf) + { + using namespace ignite::impl::binary; + using namespace ignite::impl::interop; + + if (!IsValid()) + return SQL_RESULT_ERROR; + + if (GetUnreadDataLength() == 0) + { + dataBuf.PutNull(); + + return SQL_RESULT_NO_DATA; + } + + ignite::impl::interop::InteropInputStream* stream = reader.GetStream(); + + if (!stream) + return SQL_RESULT_ERROR; + + InteropStreamPositionGuard guard(*stream); + + stream->Position(startPos); + + switch (type) + { + case IGNITE_TYPE_BYTE: + { + dataBuf.PutInt8(reader.ReadInt8()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_SHORT: + case IGNITE_TYPE_CHAR: + { + dataBuf.PutInt16(reader.ReadInt16()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_INT: + { + dataBuf.PutInt32(reader.ReadInt32()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_LONG: + { + dataBuf.PutInt64(reader.ReadInt64()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_FLOAT: + { + dataBuf.PutFloat(reader.ReadFloat()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_DOUBLE: + { + dataBuf.PutDouble(reader.ReadDouble()); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_BOOL: + { + dataBuf.PutInt8(reader.ReadBool() ? 1 : 0); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_STRING: + { + std::string str; + utility::ReadString(reader, str); + + int32_t written = dataBuf.PutString(str.substr(offset)); + + IncreaseOffset(written); + + break; + } + + case IGNITE_TYPE_UUID: + { + Guid guid = reader.ReadGuid(); + + dataBuf.PutGuid(guid); + + IncreaseOffset(size); + + break; + } + + case IGNITE_HDR_NULL: + { + dataBuf.PutNull(); + + IncreaseOffset(size); + + break; + } + + case IGNITE_HDR_FULL: + { + int32_t len; + + if (!GetObjectLength(*stream, len)) + return SQL_RESULT_ERROR; + + std::vector data(len); + + stream->ReadInt8Array(&data[0], static_cast(data.size())); + + int32_t written = dataBuf.PutBinaryData(data.data() + offset, static_cast(len - offset)); + + IncreaseOffset(written); + + break; + } + + case IGNITE_TYPE_DECIMAL: + { + Decimal res; + + utility::ReadDecimal(reader, res); + + dataBuf.PutDecimal(res); + + IncreaseOffset(size); + + break; + } + + case IGNITE_TYPE_DATE: + { + Date date = reader.ReadDate(); + + dataBuf.PutDate(date); + + break; + } + + case IGNITE_TYPE_TIMESTAMP: + { + Timestamp ts = reader.ReadTimestamp(); + + dataBuf.PutTimestamp(ts); + + break; + } + + default: + { + // This is a fail case. Return false. + return SQL_RESULT_ERROR; + } + } + + return SQL_RESULT_SUCCESS; + } + + void Column::IncreaseOffset(int32_t value) + { + offset += value; + + if (offset > size) + offset = size; + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/common_types.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/common_types.cpp b/modules/platforms/cpp/odbc/src/common_types.cpp new file mode 100644 index 0000000..276d9fd --- /dev/null +++ b/modules/platforms/cpp/odbc/src/common_types.cpp @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/common_types.h" + +namespace ignite +{ + namespace odbc + { + int SqlResultToReturnCode(SqlResult result) + { + switch (result) + { + case SQL_RESULT_SUCCESS: + return SQL_SUCCESS; + + case SQL_RESULT_SUCCESS_WITH_INFO: + return SQL_SUCCESS_WITH_INFO; + + case SQL_RESULT_NO_DATA: + return SQL_NO_DATA; + + case SQL_RESULT_ERROR: + default: + return SQL_ERROR; + } + } + + DiagnosticField DiagnosticFieldToInternal(int16_t field) + { + switch (field) + { + case SQL_DIAG_CURSOR_ROW_COUNT: + return IGNITE_SQL_DIAG_HEADER_CURSOR_ROW_COUNT; + + case SQL_DIAG_DYNAMIC_FUNCTION: + return IGNITE_SQL_DIAG_HEADER_DYNAMIC_FUNCTION; + + case SQL_DIAG_DYNAMIC_FUNCTION_CODE: + return IGNITE_SQL_DIAG_HEADER_DYNAMIC_FUNCTION_CODE; + + case SQL_DIAG_NUMBER: + return IGNITE_SQL_DIAG_HEADER_NUMBER; + + case SQL_DIAG_RETURNCODE: + return IGNITE_SQL_DIAG_HEADER_RETURNCODE; + + case SQL_DIAG_ROW_COUNT: + return IGNITE_SQL_DIAG_HEADER_ROW_COUNT; + + case SQL_DIAG_CLASS_ORIGIN: + return IGNITE_SQL_DIAG_STATUS_CLASS_ORIGIN; + + case SQL_DIAG_COLUMN_NUMBER: + return IGNITE_SQL_DIAG_STATUS_COLUMN_NUMBER; + + case SQL_DIAG_CONNECTION_NAME: + return IGNITE_SQL_DIAG_STATUS_CONNECTION_NAME; + + case SQL_DIAG_MESSAGE_TEXT: + return IGNITE_SQL_DIAG_STATUS_MESSAGE_TEXT; + + case SQL_DIAG_NATIVE: + return IGNITE_SQL_DIAG_STATUS_NATIVE; + + case SQL_DIAG_ROW_NUMBER: + return IGNITE_SQL_DIAG_STATUS_ROW_NUMBER; + + case SQL_DIAG_SERVER_NAME: + return IGNITE_SQL_DIAG_STATUS_SERVER_NAME; + + case SQL_DIAG_SQLSTATE: + return IGNITE_SQL_DIAG_STATUS_SQLSTATE; + + case SQL_DIAG_SUBCLASS_ORIGIN: + return IGNITE_SQL_DIAG_STATUS_SUBCLASS_ORIGIN; + + default: + break; + } + + return IGNITE_SQL_DIAG_UNKNOWN; + } + + EnvironmentAttribute EnvironmentAttributeToInternal(int32_t attr) + { + switch (attr) + { + case SQL_ATTR_ODBC_VERSION: + return IGNITE_SQL_ENV_ATTR_ODBC_VERSION; + + case SQL_ATTR_OUTPUT_NTS: + return IGNITE_SQL_ENV_ATTR_OUTPUT_NTS; + + default: + break; + } + + return IGNITE_SQL_ENV_ATTR_UNKNOWN; + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/src/config/configuration.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/config/configuration.cpp b/modules/platforms/cpp/odbc/src/config/configuration.cpp new file mode 100644 index 0000000..8d57dee --- /dev/null +++ b/modules/platforms/cpp/odbc/src/config/configuration.cpp @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include "ignite/odbc/utility.h" +#include "ignite/odbc/config/configuration.h" + +namespace ignite +{ + namespace odbc + { + namespace config + { + /** Default values for configuration. */ + namespace dflt + { + /** Default value for DSN attribute. */ + const std::string dsn = "Default Apache Ignite DSN"; + + /** Default value for Driver attribute. */ + const std::string driver = "Apache Ignite"; + + /** Default value for host attribute. */ + const std::string host = "localhost"; + + /** Default value for port attribute. */ + const uint16_t port = 10800; + + /** Default value for cache attribute. */ + const std::string cache = ""; + } + + /** Connection attribute keywords. */ + namespace attrkey + { + /** Connection attribute keyword for DSN attribute. */ + const std::string dsn = "dsn"; + + /** Connection attribute keyword for Driver attribute. */ + const std::string driver = "driver"; + + /** Connection attribute keyword for server host attribute. */ + const std::string host = "server"; + + /** Connection attribute keyword for server port attribute. */ + const std::string port = "port"; + + /** Connection attribute keyword for cache attribute. */ + const std::string cache = "cache"; + } + + Configuration::Configuration() : + dsn(dflt::dsn), driver(dflt::driver), + host(dflt::host), port(dflt::port), + cache(dflt::cache) + { + // No-op. + } + + Configuration::~Configuration() + { + // No-op. + } + + void Configuration::FillFromConnectString(const char* str, size_t len) + { + ArgumentMap connect_attributes; + + // Ignoring terminating zero byte if present. + // Some Driver Managers pass zero-terminated connection string + // while others don't. + if (len && !str[len - 1]) + --len; + + ParseAttributeList(str, len, ';', connect_attributes); + + ArgumentMap::const_iterator it; + + it = connect_attributes.find(attrkey::dsn); + if (it != connect_attributes.end()) + dsn = it->second; + else + dsn.clear(); + + it = connect_attributes.find(attrkey::driver); + if (it != connect_attributes.end()) + driver = it->second; + else + driver = dflt::driver; + + it = connect_attributes.find(attrkey::host); + if (it != connect_attributes.end()) + host = it->second; + else + host = dflt::host; + + it = connect_attributes.find(attrkey::port); + if (it != connect_attributes.end()) + port = atoi(it->second.c_str()); + else + port = dflt::port; + + it = connect_attributes.find(attrkey::cache); + if (it != connect_attributes.end()) + cache = it->second; + else + cache = dflt::cache; + } + + void Configuration::FillFromConnectString(const std::string& str) + { + FillFromConnectString(str.data(), str.size()); + } + + std::string Configuration::ToConnectString() const + { + std::stringstream connect_string_buffer; + + if (!driver.empty()) + connect_string_buffer << attrkey::driver << "={" << driver << "};"; + + if (!host.empty()) + connect_string_buffer << attrkey::host << '=' << host << ';'; + + if (port) + connect_string_buffer << attrkey::port << '=' << port << ';'; + + if (!dsn.empty()) + connect_string_buffer << attrkey::dsn << '=' << dsn << ';'; + + if (!cache.empty()) + connect_string_buffer << attrkey::cache << '=' << cache << ';'; + + return connect_string_buffer.str(); + } + + void Configuration::FillFromConfigAttributes(const char * attributes) + { + ArgumentMap config_attributes; + + size_t len = 0; + + // Getting list length. List is terminated by two '\0'. + while (attributes[len] || attributes[len + 1]) + ++len; + + ++len; + + ParseAttributeList(attributes, len, '\0', config_attributes); + + ArgumentMap::const_iterator it; + + it = config_attributes.find(attrkey::dsn); + if (it != config_attributes.end()) + dsn = it->second; + else + dsn = dflt::dsn; + + it = config_attributes.find(attrkey::driver); + if (it != config_attributes.end()) + driver = it->second; + else + driver.clear(); + + it = config_attributes.find(attrkey::host); + if (it != config_attributes.end()) + host = it->second; + else + host.clear(); + + it = config_attributes.find(attrkey::port); + if (it != config_attributes.end()) + port = atoi(it->second.c_str()); + else + port = 0; + + it = config_attributes.find(attrkey::cache); + if (it != config_attributes.end()) + cache = it->second; + else + cache.clear(); + } + + void Configuration::ParseAttributeList(const char * str, size_t len, char delimeter, ArgumentMap & args) const + { + std::string connect_str(str, len); + args.clear(); + + while (!connect_str.empty()) + { + size_t attr_begin = connect_str.rfind(delimeter); + + if (attr_begin == std::string::npos) + attr_begin = 0; + else + ++attr_begin; + + size_t attr_eq_pos = connect_str.rfind('='); + + if (attr_eq_pos == std::string::npos) + attr_eq_pos = 0; + + if (attr_begin < attr_eq_pos) + { + const char* key_begin = connect_str.data() + attr_begin; + const char* key_end = connect_str.data() + attr_eq_pos; + + const char* value_begin = connect_str.data() + attr_eq_pos + 1; + const char* value_end = connect_str.data() + connect_str.size(); + + std::string key = utility::RemoveSurroundingSpaces(key_begin, key_end); + std::string value = utility::RemoveSurroundingSpaces(value_begin, value_end); + + utility::IntoLower(key); + + if (value.front() == '{' && value.back() == '}') + value = value.substr(1, value.size() - 2); + + args[key] = value; + } + + if (!attr_begin) + break; + + connect_str.erase(attr_begin - 1); + } + } + } + } +} +