mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2026-05-06 02:37:20 +02:00
Major plugin refactor and cleanup.
Switched to POCO library for unified platform/library interface. Deprecated the external module API. It was creating more problems than solving. Removed most built-in libraries in favor of system libraries for easier maintenance. Cleaned and secured code with help from static analyzers.
This commit is contained in:
Vendored
+541
@@ -0,0 +1,541 @@
|
||||
//
|
||||
// Binder.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Binder
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/Binder.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/Connector.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <sql.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
Binder::Binder(const StatementHandle& rStmt,
|
||||
std::size_t maxFieldSize,
|
||||
Binder::ParameterBinding dataBinding,
|
||||
const TypeInfo* pDataTypes):
|
||||
_rStmt(rStmt),
|
||||
_paramBinding(dataBinding),
|
||||
_pTypeInfo(pDataTypes),
|
||||
_paramSetSize(0),
|
||||
_maxFieldSize(maxFieldSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Binder::~Binder()
|
||||
{
|
||||
freeMemory();
|
||||
}
|
||||
|
||||
|
||||
void Binder::freeMemory()
|
||||
{
|
||||
LengthPtrVec::iterator itLen = _lengthIndicator.begin();
|
||||
LengthPtrVec::iterator itLenEnd = _lengthIndicator.end();
|
||||
for(; itLen != itLenEnd; ++itLen) delete *itLen;
|
||||
|
||||
LengthVecVec::iterator itVecLen = _vecLengthIndicator.begin();
|
||||
LengthVecVec::iterator itVecLenEnd = _vecLengthIndicator.end();
|
||||
for (; itVecLen != itVecLenEnd; ++itVecLen) delete *itVecLen;
|
||||
|
||||
TimeMap::iterator itT = _times.begin();
|
||||
TimeMap::iterator itTEnd = _times.end();
|
||||
for(; itT != itTEnd; ++itT) delete itT->first;
|
||||
|
||||
DateMap::iterator itD = _dates.begin();
|
||||
DateMap::iterator itDEnd = _dates.end();
|
||||
for(; itD != itDEnd; ++itD) delete itD->first;
|
||||
|
||||
TimestampMap::iterator itTS = _timestamps.begin();
|
||||
TimestampMap::iterator itTSEnd = _timestamps.end();
|
||||
for(; itTS != itTSEnd; ++itTS) delete itTS->first;
|
||||
|
||||
StringMap::iterator itStr = _strings.begin();
|
||||
StringMap::iterator itStrEnd = _strings.end();
|
||||
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
|
||||
|
||||
CharPtrVec::iterator itChr = _charPtrs.begin();
|
||||
CharPtrVec::iterator endChr = _charPtrs.end();
|
||||
for (; itChr != endChr; ++itChr) std::free(*itChr);
|
||||
|
||||
UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin();
|
||||
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
|
||||
for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
|
||||
|
||||
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
||||
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
||||
for (; itBool != endBool; ++itBool) delete [] *itBool;
|
||||
|
||||
DateVecVec::iterator itDateVec = _dateVecVec.begin();
|
||||
DateVecVec::iterator itDateVecEnd = _dateVecVec.end();
|
||||
for (; itDateVec != itDateVecEnd; ++itDateVec) delete *itDateVec;
|
||||
|
||||
TimeVecVec::iterator itTimeVec = _timeVecVec.begin();
|
||||
TimeVecVec::iterator itTimeVecEnd = _timeVecVec.end();
|
||||
for (; itTimeVec != itTimeVecEnd; ++itTimeVec) delete *itTimeVec;
|
||||
|
||||
DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin();
|
||||
DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end();
|
||||
for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec;
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
||||
{
|
||||
SQLPOINTER pVal = 0;
|
||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits, val.size());
|
||||
|
||||
if (isOutBound(dir))
|
||||
{
|
||||
getColumnOrParameterSize(pos, size);
|
||||
char* pChar = (char*) std::calloc(size, sizeof(char));
|
||||
pVal = (SQLPOINTER) pChar;
|
||||
_outParams.insert(ParamMap::value_type(pVal, size));
|
||||
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
|
||||
}
|
||||
else if (isInBound(dir))
|
||||
{
|
||||
pVal = (SQLPOINTER) val.c_str();
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
}
|
||||
else
|
||||
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
|
||||
|
||||
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);
|
||||
|
||||
if (PB_AT_EXEC == _paramBinding)
|
||||
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
toODBCDirection(dir),
|
||||
SQL_C_CHAR,
|
||||
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
|
||||
(SQLUINTEGER) colSize,
|
||||
0,
|
||||
pVal,
|
||||
(SQLINTEGER) size,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir)
|
||||
{
|
||||
typedef UTF16String::value_type CharT;
|
||||
|
||||
SQLPOINTER pVal = 0;
|
||||
SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits);
|
||||
|
||||
if (isOutBound(dir))
|
||||
{
|
||||
getColumnOrParameterSize(pos, size);
|
||||
CharT* pChar = (CharT*)std::calloc(size, 1);
|
||||
pVal = (SQLPOINTER)pChar;
|
||||
_outParams.insert(ParamMap::value_type(pVal, size));
|
||||
_utf16Strings.insert(UTF16StringMap::value_type(pChar, const_cast<UTF16String*>(&val)));
|
||||
}
|
||||
else if (isInBound(dir))
|
||||
{
|
||||
pVal = (SQLPOINTER)val.c_str();
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
}
|
||||
else
|
||||
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
|
||||
|
||||
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);
|
||||
|
||||
if (PB_AT_EXEC == _paramBinding)
|
||||
{
|
||||
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
|
||||
}
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT)pos + 1,
|
||||
toODBCDirection(dir),
|
||||
SQL_C_WCHAR,
|
||||
SQL_WLONGVARCHAR,
|
||||
(SQLUINTEGER)colSize,
|
||||
0,
|
||||
pVal,
|
||||
(SQLINTEGER)size,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const Date& val, Direction dir)
|
||||
{
|
||||
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT);
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = size;
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT;
|
||||
Utility::dateSync(*pDS, val);
|
||||
|
||||
_dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
|
||||
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
toODBCDirection(dir),
|
||||
SQL_C_TYPE_DATE,
|
||||
SQL_TYPE_DATE,
|
||||
colSize,
|
||||
decDigits,
|
||||
(SQLPOINTER) pDS,
|
||||
0,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(Date)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const Time& val, Direction dir)
|
||||
{
|
||||
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIME_STRUCT);
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = size;
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
SQL_TIME_STRUCT* pTS = new SQL_TIME_STRUCT;
|
||||
Utility::timeSync(*pTS, val);
|
||||
|
||||
_times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
|
||||
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
toODBCDirection(dir),
|
||||
SQL_C_TYPE_TIME,
|
||||
SQL_TYPE_TIME,
|
||||
colSize,
|
||||
decDigits,
|
||||
(SQLPOINTER) pTS,
|
||||
0,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(Time)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
|
||||
{
|
||||
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT);
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = size;
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
SQL_TIMESTAMP_STRUCT* pTS = new SQL_TIMESTAMP_STRUCT;
|
||||
Utility::dateTimeSync(*pTS, val);
|
||||
|
||||
_timestamps.insert(TimestampMap::value_type(pTS, const_cast<DateTime*>(&val)));
|
||||
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
toODBCDirection(dir),
|
||||
SQL_C_TYPE_TIMESTAMP,
|
||||
SQL_TYPE_TIMESTAMP,
|
||||
colSize,
|
||||
decDigits,
|
||||
(SQLPOINTER) pTS,
|
||||
0,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(DateTime)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
||||
{
|
||||
if (isOutBound(dir) || !isInBound(dir))
|
||||
throw NotImplementedException("NULL parameter type can only be inbound.");
|
||||
|
||||
_inParams.insert(ParamMap::value_type(SQLPOINTER(0), SQLINTEGER(0)));
|
||||
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = SQL_NULL_DATA;
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
SQL_PARAM_INPUT,
|
||||
SQL_C_STINYINT,
|
||||
Utility::sqlDataType(SQL_C_STINYINT),
|
||||
colSize,
|
||||
decDigits,
|
||||
0,
|
||||
0,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
|
||||
{
|
||||
ParamMap::const_iterator it = _inParams.find(pAddr);
|
||||
if (it != _inParams.end()) return it->second;
|
||||
|
||||
it = _outParams.find(pAddr);
|
||||
if (it != _outParams.end()) return it->second;
|
||||
|
||||
throw NotFoundException("Requested data size not found.");
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir)
|
||||
{
|
||||
throw NotImplementedException("char* binding not implemented, Use std::string instead.");
|
||||
}
|
||||
|
||||
|
||||
SQLSMALLINT Binder::toODBCDirection(Direction dir) const
|
||||
{
|
||||
bool in = isInBound(dir);
|
||||
bool out = isOutBound(dir);
|
||||
SQLSMALLINT ioType = SQL_PARAM_TYPE_UNKNOWN;
|
||||
if (in && out) ioType = SQL_PARAM_INPUT_OUTPUT;
|
||||
else if(in) ioType = SQL_PARAM_INPUT;
|
||||
else if(out) ioType = SQL_PARAM_OUTPUT;
|
||||
else throw Poco::IllegalStateException("Binder not bound (must be [in] OR [out]).");
|
||||
|
||||
return ioType;
|
||||
}
|
||||
|
||||
|
||||
void Binder::synchronize()
|
||||
{
|
||||
if (_dates.size())
|
||||
{
|
||||
DateMap::iterator it = _dates.begin();
|
||||
DateMap::iterator end = _dates.end();
|
||||
for(; it != end; ++it)
|
||||
Utility::dateSync(*it->second, *it->first);
|
||||
}
|
||||
|
||||
if (_times.size())
|
||||
{
|
||||
TimeMap::iterator it = _times.begin();
|
||||
TimeMap::iterator end = _times.end();
|
||||
for(; it != end; ++it)
|
||||
Utility::timeSync(*it->second, *it->first);
|
||||
}
|
||||
|
||||
if (_timestamps.size())
|
||||
{
|
||||
TimestampMap::iterator it = _timestamps.begin();
|
||||
TimestampMap::iterator end = _timestamps.end();
|
||||
for(; it != end; ++it)
|
||||
Utility::dateTimeSync(*it->second, *it->first);
|
||||
}
|
||||
|
||||
if (_strings.size())
|
||||
{
|
||||
StringMap::iterator it = _strings.begin();
|
||||
StringMap::iterator end = _strings.end();
|
||||
for(; it != end; ++it)
|
||||
it->second->assign(it->first, std::strlen(it->first));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::reset()
|
||||
{
|
||||
freeMemory();
|
||||
LengthPtrVec().swap(_lengthIndicator);
|
||||
_inParams.clear();
|
||||
_outParams.clear();
|
||||
_dates.clear();
|
||||
_times.clear();
|
||||
_timestamps.clear();
|
||||
_strings.clear();
|
||||
_dateVecVec.clear();
|
||||
_timeVecVec.clear();
|
||||
_dateTimeVecVec.clear();
|
||||
_charPtrs.clear();
|
||||
_boolPtrs.clear();
|
||||
_containers.clear();
|
||||
_paramSetSize = 0;
|
||||
}
|
||||
|
||||
|
||||
void Binder::getColSizeAndPrecision(std::size_t pos,
|
||||
SQLSMALLINT cDataType,
|
||||
SQLINTEGER& colSize,
|
||||
SQLSMALLINT& decDigits,
|
||||
std::size_t actualSize)
|
||||
{
|
||||
// Not all drivers are equally willing to cooperate in this matter.
|
||||
// Hence the funky flow control.
|
||||
DynamicAny tmp;
|
||||
bool found(false);
|
||||
if (_pTypeInfo)
|
||||
{
|
||||
found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp);
|
||||
if (found) colSize = tmp;
|
||||
if (actualSize > colSize)
|
||||
{
|
||||
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
|
||||
pos, actualSize, static_cast<long>(colSize)));
|
||||
}
|
||||
found = _pTypeInfo->tryGetInfo(cDataType, "MINIMUM_SCALE", tmp);
|
||||
if (found)
|
||||
{
|
||||
decDigits = tmp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Parameter p(_rStmt, pos);
|
||||
colSize = (SQLINTEGER) p.columnSize();
|
||||
decDigits = (SQLSMALLINT) p.decimalDigits();
|
||||
return;
|
||||
}
|
||||
catch (StatementException&)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ODBCMetaColumn c(_rStmt, pos);
|
||||
colSize = (SQLINTEGER) c.length();
|
||||
decDigits = (SQLSMALLINT) c.precision();
|
||||
return;
|
||||
}
|
||||
catch (StatementException&)
|
||||
{
|
||||
}
|
||||
|
||||
// last check, just in case
|
||||
if ((0 != colSize) && (actualSize > colSize))
|
||||
{
|
||||
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
|
||||
pos, actualSize, static_cast<long>(colSize)));
|
||||
}
|
||||
|
||||
// no success, set to zero and hope for the best
|
||||
// (most drivers do not require these most of the times anyway)
|
||||
colSize = 0;
|
||||
decDigits = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size)
|
||||
{
|
||||
std::size_t colSize = 0;
|
||||
std::size_t paramSize = 0;
|
||||
|
||||
try
|
||||
{
|
||||
ODBCMetaColumn col(_rStmt, pos);
|
||||
colSize = col.length();
|
||||
}
|
||||
catch (StatementException&) { }
|
||||
|
||||
try
|
||||
{
|
||||
Parameter p(_rStmt, pos);
|
||||
paramSize = p.columnSize();
|
||||
}
|
||||
catch (StatementException&)
|
||||
{
|
||||
size = DEFAULT_PARAM_SIZE;
|
||||
//On Linux, PostgreSQL driver segfaults on SQLGetDescField, so this is disabled for now
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
SQLHDESC hIPD = 0;
|
||||
if (!Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0)))
|
||||
{
|
||||
SQLUINTEGER sz = 0;
|
||||
if (!Utility::isError(SQLGetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) &&
|
||||
sz > 0)
|
||||
{
|
||||
size = sz;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (colSize > 0 && paramSize > 0)
|
||||
size = colSize < paramSize ? static_cast<SQLINTEGER>(colSize) : static_cast<SQLINTEGER>(paramSize);
|
||||
else if (colSize > 0)
|
||||
size = static_cast<SQLINTEGER>(colSize);
|
||||
else if (paramSize > 0)
|
||||
size = static_cast<SQLINTEGER>(paramSize);
|
||||
|
||||
if (size > _maxFieldSize) size = static_cast<SQLINTEGER>(_maxFieldSize);
|
||||
}
|
||||
|
||||
|
||||
void Binder::setParamSetSize(std::size_t length)
|
||||
{
|
||||
if (0 == _paramSetSize)
|
||||
{
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, SQL_IS_UINTEGER)) ||
|
||||
Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
|
||||
throw StatementException(_rStmt, "SQLSetStmtAttr()");
|
||||
|
||||
_paramSetSize = static_cast<SQLINTEGER>(length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// ConnectionHandle.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: ConnectionHandle
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ConnectionHandle.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
ConnectionHandle::ConnectionHandle(EnvironmentHandle* pEnvironment):
|
||||
_pEnvironment(pEnvironment ? pEnvironment : new EnvironmentHandle),
|
||||
_hdbc(SQL_NULL_HDBC),
|
||||
_ownsEnvironment(pEnvironment ? false : true)
|
||||
{
|
||||
if (Utility::isError(SQLAllocHandle(SQL_HANDLE_DBC,
|
||||
_pEnvironment->handle(),
|
||||
&_hdbc)))
|
||||
{
|
||||
throw ODBCException("Could not allocate connection handle.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ConnectionHandle::~ConnectionHandle()
|
||||
{
|
||||
try
|
||||
{
|
||||
SQLDisconnect(_hdbc);
|
||||
SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_DBC, _hdbc);
|
||||
|
||||
if (_ownsEnvironment) delete _pEnvironment;
|
||||
|
||||
poco_assert (!Utility::isError(rc));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Connector.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Connector
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/Connector.h"
|
||||
#include "Poco/Data/ODBC/SessionImpl.h"
|
||||
#include "Poco/Data/SessionFactory.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
const std::string Connector::KEY("ODBC");
|
||||
bool Connector::_bindStringToLongVarChar(true);
|
||||
|
||||
|
||||
Connector::Connector()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Connector::~Connector()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
|
||||
std::size_t timeout)
|
||||
{
|
||||
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
|
||||
}
|
||||
|
||||
|
||||
void Connector::registerConnector()
|
||||
{
|
||||
Poco::Data::SessionFactory::instance().add(new Connector());
|
||||
}
|
||||
|
||||
|
||||
void Connector::unregisterConnector()
|
||||
{
|
||||
Poco::Data::SessionFactory::instance().remove(KEY);
|
||||
}
|
||||
|
||||
|
||||
void Connector::bindStringToLongVarChar(bool flag)
|
||||
{
|
||||
_bindStringToLongVarChar = flag;
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// EnvironmentHandle.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: EnvironmentHandle
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
EnvironmentHandle::EnvironmentHandle(): _henv(SQL_NULL_HENV)
|
||||
{
|
||||
if (Utility::isError(SQLAllocHandle(SQL_HANDLE_ENV,
|
||||
SQL_NULL_HANDLE,
|
||||
&_henv)) ||
|
||||
Utility::isError(SQLSetEnvAttr(_henv,
|
||||
SQL_ATTR_ODBC_VERSION,
|
||||
(SQLPOINTER) SQL_OV_ODBC3,
|
||||
0)))
|
||||
{
|
||||
throw ODBCException("Could not initialize environment.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EnvironmentHandle::~EnvironmentHandle()
|
||||
{
|
||||
try
|
||||
{
|
||||
SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_ENV, _henv);
|
||||
poco_assert (!Utility::isError(rc));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+1329
File diff suppressed because it is too large
Load Diff
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// ODBCException.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: ODBCException
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include <typeinfo>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(ODBCException, Poco::Data::DataException, "Generic ODBC error")
|
||||
POCO_IMPLEMENT_EXCEPTION(InsufficientStorageException, ODBCException, "Insufficient storage error")
|
||||
POCO_IMPLEMENT_EXCEPTION(UnknownDataLengthException, ODBCException, "Unknown length of remaining data")
|
||||
POCO_IMPLEMENT_EXCEPTION(DataTruncatedException, ODBCException, "Variable length character or binary data truncated")
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// ODBCMetaColumn.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: ODBCMetaColumn
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position) :
|
||||
MetaColumn(position),
|
||||
_rStmt(rStmt)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
ODBCMetaColumn::~ODBCMetaColumn()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ODBCMetaColumn::getDescription()
|
||||
{
|
||||
std::memset(_columnDesc.name, 0, NAME_BUFFER_LENGTH);
|
||||
_columnDesc.nameBufferLength = 0;
|
||||
_columnDesc.dataType = 0;
|
||||
_columnDesc.size = 0;
|
||||
_columnDesc.decimalDigits = 0;
|
||||
_columnDesc.isNullable = 0;
|
||||
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLDescribeCol(_rStmt,
|
||||
(SQLUSMALLINT) position() + 1, // ODBC columns are 1-based
|
||||
_columnDesc.name,
|
||||
NAME_BUFFER_LENGTH,
|
||||
&_columnDesc.nameBufferLength,
|
||||
&_columnDesc.dataType,
|
||||
&_columnDesc.size,
|
||||
&_columnDesc.decimalDigits,
|
||||
&_columnDesc.isNullable)))
|
||||
{
|
||||
throw StatementException(_rStmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ODBCMetaColumn::isUnsigned() const
|
||||
{
|
||||
SQLLEN val = 0;
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLColAttribute(_rStmt,
|
||||
(SQLUSMALLINT)position() + 1, // ODBC columns are 1-based
|
||||
SQL_DESC_UNSIGNED,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&val)))
|
||||
{
|
||||
throw StatementException(_rStmt);
|
||||
}
|
||||
return (val == SQL_TRUE);
|
||||
}
|
||||
|
||||
|
||||
void ODBCMetaColumn::init()
|
||||
{
|
||||
getDescription();
|
||||
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLColAttribute(_rStmt,
|
||||
(SQLUSMALLINT) position() + 1, // ODBC columns are 1-based
|
||||
SQL_DESC_LENGTH,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&_dataLength)))
|
||||
{
|
||||
throw StatementException(_rStmt);
|
||||
}
|
||||
|
||||
setName(std::string((char*) _columnDesc.name));
|
||||
setLength(_columnDesc.size);
|
||||
setPrecision(_columnDesc.decimalDigits);
|
||||
setNullable(SQL_NULLABLE == _columnDesc.isNullable);
|
||||
switch(_columnDesc.dataType)
|
||||
{
|
||||
case SQL_BIT:
|
||||
setType(MetaColumn::FDT_BOOL); break;
|
||||
|
||||
case SQL_CHAR:
|
||||
case SQL_VARCHAR:
|
||||
case SQL_LONGVARCHAR:
|
||||
#ifdef SQL_GUID
|
||||
case SQL_GUID:
|
||||
#endif
|
||||
setType(MetaColumn::FDT_STRING); break;
|
||||
|
||||
case SQL_WCHAR:
|
||||
case SQL_WVARCHAR:
|
||||
case SQL_WLONGVARCHAR:
|
||||
setType(MetaColumn::FDT_WSTRING); break;
|
||||
|
||||
case SQL_TINYINT:
|
||||
setType(isUnsigned() ? MetaColumn::FDT_UINT8 : MetaColumn::FDT_INT8);
|
||||
break;
|
||||
|
||||
case SQL_SMALLINT:
|
||||
setType(isUnsigned() ? MetaColumn::FDT_UINT16 : MetaColumn::FDT_INT16);
|
||||
break;
|
||||
|
||||
case SQL_INTEGER:
|
||||
setType(isUnsigned() ? MetaColumn::FDT_UINT32 : MetaColumn::FDT_INT32);
|
||||
break;
|
||||
|
||||
case SQL_BIGINT:
|
||||
setType(isUnsigned() ? MetaColumn::FDT_UINT64 : MetaColumn::FDT_INT64);
|
||||
break;
|
||||
|
||||
case SQL_DOUBLE:
|
||||
case SQL_FLOAT:
|
||||
setType(MetaColumn::FDT_DOUBLE); break;
|
||||
|
||||
case SQL_NUMERIC:
|
||||
case SQL_DECIMAL:
|
||||
// Oracle has no INTEGER type - it's essentially NUMBER with 38 whole and
|
||||
// 0 fractional digits. It also does not recognize SQL_BIGINT type,
|
||||
// so the workaround here is to hardcode it to 32 or 64 bit integer
|
||||
if (0 == _columnDesc.decimalDigits)
|
||||
{
|
||||
if (_columnDesc.size > 9)
|
||||
setType(MetaColumn::FDT_INT64);
|
||||
else
|
||||
setType(MetaColumn::FDT_INT32);
|
||||
}
|
||||
else
|
||||
{
|
||||
setType(MetaColumn::FDT_DOUBLE);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_REAL:
|
||||
setType(MetaColumn::FDT_FLOAT); break;
|
||||
|
||||
case SQL_BINARY:
|
||||
case SQL_VARBINARY:
|
||||
case SQL_LONGVARBINARY:
|
||||
case -98:// IBM DB2 non-standard type
|
||||
setType(MetaColumn::FDT_BLOB); break;
|
||||
|
||||
case SQL_TYPE_DATE:
|
||||
setType(MetaColumn::FDT_DATE); break;
|
||||
|
||||
case SQL_TYPE_TIME:
|
||||
setType(MetaColumn::FDT_TIME); break;
|
||||
|
||||
case SQL_TYPE_TIMESTAMP:
|
||||
setType(MetaColumn::FDT_TIMESTAMP); break;
|
||||
|
||||
default:
|
||||
throw DataFormatException("Unsupported data type.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+458
@@ -0,0 +1,458 @@
|
||||
//
|
||||
// ODBCStatementImpl.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: ODBCStatementImpl
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
||||
#include "Poco/Data/ODBC/ConnectionHandle.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/AbstractPreparation.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#pragma warning(disable:4312)// 'type cast' : conversion from 'std::size_t' to 'SQLPOINTER' of greater size
|
||||
#endif
|
||||
|
||||
|
||||
using Poco::DataFormatException;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
const std::string ODBCStatementImpl::INVALID_CURSOR_STATE = "24000";
|
||||
|
||||
|
||||
ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession):
|
||||
Poco::Data::StatementImpl(rSession),
|
||||
_rConnection(rSession.dbc()),
|
||||
_stmt(rSession.dbc()),
|
||||
_stepCalled(false),
|
||||
_nextResponse(0),
|
||||
_prepared(false),
|
||||
_affectedRowCount(0),
|
||||
_canCompile(true)
|
||||
{
|
||||
int queryTimeout = rSession.queryTimeout();
|
||||
if (queryTimeout >= 0)
|
||||
{
|
||||
SQLULEN uqt = static_cast<SQLULEN>(queryTimeout);
|
||||
SQLSetStmtAttr(_stmt,
|
||||
SQL_ATTR_QUERY_TIMEOUT,
|
||||
(SQLPOINTER) uqt,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ODBCStatementImpl::~ODBCStatementImpl()
|
||||
{
|
||||
ColumnPtrVecVec::iterator it = _columnPtrs.begin();
|
||||
ColumnPtrVecVec::iterator end = _columnPtrs.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
ColumnPtrVec::iterator itC = it->begin();
|
||||
ColumnPtrVec::iterator endC = it->end();
|
||||
for (; itC != endC; ++itC) delete *itC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::compileImpl()
|
||||
{
|
||||
if (!_canCompile) return;
|
||||
|
||||
_stepCalled = false;
|
||||
_nextResponse = 0;
|
||||
|
||||
if (_preparations.size())
|
||||
PreparatorVec().swap(_preparations);
|
||||
|
||||
addPreparator();
|
||||
|
||||
Binder::ParameterBinding bind = session().getFeature("autoBind") ?
|
||||
Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
|
||||
|
||||
const TypeInfo* pDT = 0;
|
||||
try
|
||||
{
|
||||
Poco::Any dti = session().getProperty("dataTypeInfo");
|
||||
pDT = AnyCast<const TypeInfo*>(dti);
|
||||
}
|
||||
catch (NotSupportedException&)
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
|
||||
|
||||
_pBinder = new Binder(_stmt, maxFieldSize, bind, pDT);
|
||||
|
||||
makeInternalExtractors();
|
||||
doPrepare();
|
||||
|
||||
_canCompile = false;
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::makeInternalExtractors()
|
||||
{
|
||||
if (hasData() && !extractions().size())
|
||||
{
|
||||
try
|
||||
{
|
||||
fillColumns();
|
||||
}
|
||||
catch (DataFormatException&)
|
||||
{
|
||||
if (isStoredProcedure()) return;
|
||||
throw;
|
||||
}
|
||||
|
||||
makeExtractors(columnsReturned());
|
||||
fixupExtraction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::addPreparator()
|
||||
{
|
||||
if (0 == _preparations.size())
|
||||
{
|
||||
std::string statement(toString());
|
||||
if (statement.empty())
|
||||
throw ODBCException("Empty statements are illegal");
|
||||
|
||||
Preparator::DataExtraction ext = session().getFeature("autoExtract") ?
|
||||
Preparator::DE_BOUND : Preparator::DE_MANUAL;
|
||||
|
||||
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
|
||||
|
||||
_preparations.push_back(new Preparator(_stmt, statement, maxFieldSize, ext));
|
||||
}
|
||||
else
|
||||
_preparations.push_back(new Preparator(*_preparations[0]));
|
||||
|
||||
_extractors.push_back(new Extractor(_stmt, _preparations.back()));
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::doPrepare()
|
||||
{
|
||||
if (session().getFeature("autoExtract") && hasData())
|
||||
{
|
||||
std::size_t curDataSet = currentDataSet();
|
||||
poco_check_ptr (_preparations[curDataSet]);
|
||||
|
||||
Extractions& extracts = extractions();
|
||||
Extractions::iterator it = extracts.begin();
|
||||
Extractions::iterator itEnd = extracts.end();
|
||||
|
||||
if (it != itEnd && (*it)->isBulk())
|
||||
{
|
||||
std::size_t limit = getExtractionLimit();
|
||||
if (limit == Limit::LIMIT_UNLIMITED)
|
||||
throw InvalidArgumentException("Bulk operation not allowed without limit.");
|
||||
checkError(Poco::Data::ODBC::SQLSetStmtAttr(_stmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) limit, 0),
|
||||
"SQLSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE)");
|
||||
}
|
||||
|
||||
AbstractPreparation::Ptr pAP = 0;
|
||||
Poco::Data::AbstractPreparator::Ptr pP = _preparations[curDataSet];
|
||||
for (std::size_t pos = 0; it != itEnd; ++it)
|
||||
{
|
||||
pAP = (*it)->createPreparation(pP, pos);
|
||||
pAP->prepare();
|
||||
pos += (*it)->numOfColumnsHandled();
|
||||
}
|
||||
|
||||
_prepared = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ODBCStatementImpl::canBind() const
|
||||
{
|
||||
if (!bindings().empty())
|
||||
return (*bindings().begin())->canBind();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::doBind()
|
||||
{
|
||||
this->clear();
|
||||
Bindings& binds = bindings();
|
||||
if (!binds.empty())
|
||||
{
|
||||
Bindings::iterator it = binds.begin();
|
||||
Bindings::iterator itEnd = binds.end();
|
||||
|
||||
if (it != itEnd && 0 == _affectedRowCount)
|
||||
_affectedRowCount = static_cast<std::size_t>((*it)->numOfRowsHandled());
|
||||
|
||||
for (std::size_t pos = 0; it != itEnd && (*it)->canBind(); ++it)
|
||||
{
|
||||
(*it)->bind(pos);
|
||||
pos += (*it)->numOfColumnsHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::bindImpl()
|
||||
{
|
||||
doBind();
|
||||
|
||||
SQLRETURN rc = SQLExecute(_stmt);
|
||||
|
||||
if (SQL_NEED_DATA == rc) putData();
|
||||
else checkError(rc, "SQLExecute()");
|
||||
|
||||
_pBinder->synchronize();
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::putData()
|
||||
{
|
||||
SQLPOINTER pParam = 0;
|
||||
SQLINTEGER dataSize = 0;
|
||||
SQLRETURN rc;
|
||||
|
||||
while (SQL_NEED_DATA == (rc = SQLParamData(_stmt, &pParam)))
|
||||
{
|
||||
if (pParam)
|
||||
{
|
||||
dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
|
||||
|
||||
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
|
||||
throw StatementException(_stmt, "SQLPutData()");
|
||||
}
|
||||
else // if pParam is null pointer, do a dummy call
|
||||
{
|
||||
char dummy = 0;
|
||||
if (Utility::isError(SQLPutData(_stmt, &dummy, 0)))
|
||||
throw StatementException(_stmt, "SQLPutData()");
|
||||
}
|
||||
}
|
||||
|
||||
checkError(rc, "SQLParamData()");
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::clear()
|
||||
{
|
||||
SQLRETURN rc = SQLCloseCursor(_stmt);
|
||||
_stepCalled = false;
|
||||
_affectedRowCount = 0;
|
||||
|
||||
if (Utility::isError(rc))
|
||||
{
|
||||
StatementError err(_stmt);
|
||||
bool ignoreError = false;
|
||||
|
||||
const StatementDiagnostics& diagnostics = err.diagnostics();
|
||||
//ignore "Invalid cursor state" error
|
||||
//(returned by 3.x drivers when cursor is not opened)
|
||||
for (int i = 0; i < diagnostics.count(); ++i)
|
||||
{
|
||||
if ((ignoreError =
|
||||
(INVALID_CURSOR_STATE == std::string(diagnostics.sqlState(i)))))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreError)
|
||||
throw StatementException(_stmt, "SQLCloseCursor()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ODBCStatementImpl::hasNext()
|
||||
{
|
||||
if (hasData())
|
||||
{
|
||||
if (!extractions().size())
|
||||
makeInternalExtractors();
|
||||
|
||||
if (!_prepared) doPrepare();
|
||||
|
||||
if (_stepCalled)
|
||||
return _stepCalled = nextRowReady();
|
||||
|
||||
makeStep();
|
||||
|
||||
if (!nextRowReady())
|
||||
{
|
||||
if (hasMoreDataSets()) activateNextDataSet();
|
||||
else return false;
|
||||
|
||||
if (SQL_NO_DATA == SQLMoreResults(_stmt))
|
||||
return false;
|
||||
|
||||
addPreparator();
|
||||
doPrepare();
|
||||
fixupExtraction();
|
||||
makeStep();
|
||||
}
|
||||
else if (Utility::isError(_nextResponse))
|
||||
checkError(_nextResponse, "SQLFetch()");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::makeStep()
|
||||
{
|
||||
_extractors[currentDataSet()]->reset();
|
||||
_nextResponse = SQLFetch(_stmt);
|
||||
checkError(_nextResponse);
|
||||
_stepCalled = true;
|
||||
}
|
||||
|
||||
|
||||
std::size_t ODBCStatementImpl::next()
|
||||
{
|
||||
std::size_t count = 0;
|
||||
|
||||
if (nextRowReady())
|
||||
{
|
||||
Extractions& extracts = extractions();
|
||||
Extractions::iterator it = extracts.begin();
|
||||
Extractions::iterator itEnd = extracts.end();
|
||||
std::size_t prevCount = 0;
|
||||
for (std::size_t pos = 0; it != itEnd; ++it)
|
||||
{
|
||||
count = (*it)->extract(pos);
|
||||
if (prevCount && count != prevCount)
|
||||
throw IllegalStateException("Different extraction counts");
|
||||
prevCount = count;
|
||||
pos += (*it)->numOfColumnsHandled();
|
||||
}
|
||||
_stepCalled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw StatementException(_stmt,
|
||||
std::string("Next row not available."));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
std::string ODBCStatementImpl::nativeSQL()
|
||||
{
|
||||
std::string statement = toString();
|
||||
|
||||
SQLINTEGER length = (SQLINTEGER) statement.size() * 2;
|
||||
|
||||
char* pNative = 0;
|
||||
SQLINTEGER retlen = length;
|
||||
do
|
||||
{
|
||||
delete [] pNative;
|
||||
pNative = new char[retlen];
|
||||
std::memset(pNative, 0, retlen);
|
||||
length = retlen;
|
||||
if (Utility::isError(SQLNativeSql(_rConnection,
|
||||
(SQLCHAR*) statement.c_str(),
|
||||
(SQLINTEGER) statement.size(),
|
||||
(SQLCHAR*) pNative,
|
||||
length,
|
||||
&retlen)))
|
||||
{
|
||||
delete [] pNative;
|
||||
throw ConnectionException(_rConnection, "SQLNativeSql()");
|
||||
}
|
||||
++retlen;//accomodate for terminating '\0'
|
||||
}while (retlen > length);
|
||||
|
||||
std::string sql(pNative);
|
||||
delete [] pNative;
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::checkError(SQLRETURN rc, const std::string& msg)
|
||||
{
|
||||
if (SQL_NO_DATA == rc) return;
|
||||
|
||||
if (Utility::isError(rc))
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << std::endl << "Requested SQL statement: " << toString() << std::endl;
|
||||
os << "Native SQL statement: " << nativeSQL() << std::endl;
|
||||
std::string str(msg); str += os.str();
|
||||
|
||||
throw StatementException(_stmt, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::fillColumns()
|
||||
{
|
||||
std::size_t colCount = columnsReturned();
|
||||
std::size_t curDataSet = currentDataSet();
|
||||
if (curDataSet >= _columnPtrs.size())
|
||||
_columnPtrs.resize(curDataSet + 1);
|
||||
|
||||
for (int i = 0; i < colCount; ++i)
|
||||
_columnPtrs[curDataSet].push_back(new ODBCMetaColumn(_stmt, i));
|
||||
}
|
||||
|
||||
|
||||
bool ODBCStatementImpl::isStoredProcedure() const
|
||||
{
|
||||
std::string str = toString();
|
||||
if (trimInPlace(str).size() < 2) return false;
|
||||
|
||||
return ('{' == str[0] && '}' == str[str.size()-1]);
|
||||
}
|
||||
|
||||
|
||||
const MetaColumn& ODBCStatementImpl::metaColumn(std::size_t pos) const
|
||||
{
|
||||
std::size_t curDataSet = currentDataSet();
|
||||
poco_assert_dbg (curDataSet < _columnPtrs.size());
|
||||
|
||||
std::size_t sz = _columnPtrs[curDataSet].size();
|
||||
|
||||
if (0 == sz || pos > sz - 1)
|
||||
throw InvalidAccessException(format("Invalid column number: %u", pos));
|
||||
|
||||
return *_columnPtrs[curDataSet][pos];
|
||||
}
|
||||
|
||||
|
||||
int ODBCStatementImpl::affectedRowCount() const
|
||||
{
|
||||
if (0 == _affectedRowCount)
|
||||
{
|
||||
SQLLEN rows = 0;
|
||||
if (!Utility::isError(SQLRowCount(_stmt, &rows)))
|
||||
_affectedRowCount = static_cast<std::size_t>(rows);
|
||||
}
|
||||
|
||||
return static_cast<int>(_affectedRowCount);
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Parameter.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Parameter
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/Parameter.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/Error.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
Parameter::Parameter(const StatementHandle& rStmt, std::size_t colNum) :
|
||||
_rStmt(rStmt),
|
||||
_number(colNum)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
Parameter::~Parameter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Parameter::init()
|
||||
{
|
||||
if (Utility::isError(SQLDescribeParam(_rStmt,
|
||||
(SQLUSMALLINT) _number + 1,
|
||||
&_dataType,
|
||||
&_columnSize,
|
||||
&_decimalDigits,
|
||||
&_isNullable)))
|
||||
{
|
||||
throw StatementException(_rStmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
//
|
||||
// Preparator.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Preparator
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/Preparator.h"
|
||||
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
using Poco::InvalidArgumentException;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
Preparator::Preparator(const StatementHandle& rStmt,
|
||||
const std::string& statement,
|
||||
std::size_t maxFieldSize,
|
||||
DataExtraction dataExtraction):
|
||||
_rStmt(rStmt),
|
||||
_maxFieldSize(maxFieldSize),
|
||||
_dataExtraction(dataExtraction)
|
||||
{
|
||||
SQLCHAR* pStr = (SQLCHAR*) statement.c_str();
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLPrepare(_rStmt, pStr, (SQLINTEGER) statement.length())))
|
||||
throw StatementException(_rStmt);
|
||||
}
|
||||
|
||||
|
||||
Preparator::Preparator(const Preparator& other):
|
||||
_rStmt(other._rStmt),
|
||||
_maxFieldSize(other._maxFieldSize),
|
||||
_dataExtraction(other._dataExtraction)
|
||||
{
|
||||
resize();
|
||||
}
|
||||
|
||||
|
||||
Preparator::~Preparator()
|
||||
{
|
||||
try
|
||||
{
|
||||
freeMemory();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Preparator::freeMemory() const
|
||||
{
|
||||
IndexMap::iterator it = _varLengthArrays.begin();
|
||||
IndexMap::iterator end = _varLengthArrays.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
switch (it->second)
|
||||
{
|
||||
case DT_BOOL:
|
||||
deleteCachedArray<bool>(it->first);
|
||||
break;
|
||||
|
||||
case DT_CHAR:
|
||||
deleteCachedArray<char>(it->first);
|
||||
break;
|
||||
|
||||
case DT_WCHAR:
|
||||
deleteCachedArray<UTF16String::value_type>(it->first);
|
||||
break;
|
||||
|
||||
case DT_UCHAR:
|
||||
deleteCachedArray<unsigned char>(it->first);
|
||||
break;
|
||||
|
||||
case DT_CHAR_ARRAY:
|
||||
{
|
||||
char** pc = AnyCast<char*>(&_values[it->first]);
|
||||
if (pc) std::free(*pc);
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_WCHAR_ARRAY:
|
||||
{
|
||||
UTF16String::value_type** pc = AnyCast<UTF16String::value_type*>(&_values[it->first]);
|
||||
if (pc) std::free(*pc);
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_UCHAR_ARRAY:
|
||||
{
|
||||
unsigned char** pc = AnyCast<unsigned char*>(&_values[it->first]);
|
||||
if (pc) std::free(*pc);
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_BOOL_ARRAY:
|
||||
{
|
||||
bool** pb = AnyCast<bool*>(&_values[it->first]);
|
||||
if (pb) std::free(*pb);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw InvalidArgumentException("Unknown data type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::size_t Preparator::columns() const
|
||||
{
|
||||
if (_values.empty()) resize();
|
||||
return _values.size();
|
||||
}
|
||||
|
||||
|
||||
void Preparator::resize() const
|
||||
{
|
||||
SQLSMALLINT nCol = 0;
|
||||
if (!Utility::isError(SQLNumResultCols(_rStmt, &nCol)) && 0 != nCol)
|
||||
{
|
||||
_values.resize(nCol, 0);
|
||||
_lengths.resize(nCol, 0);
|
||||
_lenLengths.resize(nCol);
|
||||
if(_varLengthArrays.size())
|
||||
{
|
||||
freeMemory();
|
||||
_varLengthArrays.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::size_t Preparator::maxDataSize(std::size_t pos) const
|
||||
{
|
||||
poco_assert_dbg (pos < _values.size());
|
||||
|
||||
std::size_t sz = 0;
|
||||
std::size_t maxsz = getMaxFieldSize();
|
||||
|
||||
try
|
||||
{
|
||||
ODBCMetaColumn mc(_rStmt, pos);
|
||||
sz = mc.length();
|
||||
|
||||
// accomodate for terminating zero (non-bulk only!)
|
||||
MetaColumn::ColumnDataType type = mc.type();
|
||||
if (!isBulk() && ((ODBCMetaColumn::FDT_WSTRING == type) || (ODBCMetaColumn::FDT_STRING == type))) ++sz;
|
||||
}
|
||||
catch (StatementException&) { }
|
||||
|
||||
if (!sz || sz > maxsz) sz = maxsz;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
std::size_t Preparator::actualDataSize(std::size_t col, std::size_t row) const
|
||||
{
|
||||
SQLLEN size = (POCO_DATA_INVALID_ROW == row) ? _lengths.at(col) :
|
||||
_lenLengths.at(col).at(row);
|
||||
|
||||
// workaround for drivers returning negative length
|
||||
if (size < 0 && SQL_NULL_DATA != size) size *= -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void Preparator::prepareBoolArray(std::size_t pos, SQLSMALLINT valueType, std::size_t length)
|
||||
{
|
||||
poco_assert_dbg (DE_BOUND == _dataExtraction);
|
||||
poco_assert_dbg (pos < _values.size());
|
||||
poco_assert_dbg (pos < _lengths.size());
|
||||
poco_assert_dbg (pos < _lenLengths.size());
|
||||
|
||||
bool* pArray = (bool*) std::calloc(length, sizeof(bool));
|
||||
|
||||
_values[pos] = Any(pArray);
|
||||
_lengths[pos] = 0;
|
||||
_lenLengths[pos].resize(length);
|
||||
_varLengthArrays.insert(IndexMap::value_type(pos, DT_BOOL_ARRAY));
|
||||
|
||||
if (Utility::isError(SQLBindCol(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
valueType,
|
||||
(SQLPOINTER) pArray,
|
||||
(SQLINTEGER) sizeof(bool),
|
||||
&_lenLengths[pos][0])))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindCol()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
//
|
||||
// SessionImpl.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: SessionImpl
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/SessionImpl.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
||||
#include "Poco/Data/ODBC/Error.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/Session.h"
|
||||
#include "Poco/String.h"
|
||||
#include <sqlext.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connect,
|
||||
std::size_t loginTimeout,
|
||||
std::size_t maxFieldSize,
|
||||
bool autoBind,
|
||||
bool autoExtract):
|
||||
Poco::Data::AbstractSessionImpl<SessionImpl>(connect, loginTimeout),
|
||||
_connector(Connector::KEY),
|
||||
_maxFieldSize(maxFieldSize),
|
||||
_autoBind(autoBind),
|
||||
_autoExtract(autoExtract),
|
||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||
_inTransaction(false),
|
||||
_queryTimeout(-1)
|
||||
{
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
setProperty("handle", _db.handle());
|
||||
}
|
||||
|
||||
|
||||
SessionImpl::SessionImpl(const std::string& connect,
|
||||
Poco::Any maxFieldSize,
|
||||
bool enforceCapability,
|
||||
bool autoBind,
|
||||
bool autoExtract): Poco::Data::AbstractSessionImpl<SessionImpl>(connect),
|
||||
_connector(Connector::KEY),
|
||||
_maxFieldSize(maxFieldSize),
|
||||
_autoBind(autoBind),
|
||||
_autoExtract(autoExtract),
|
||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||
_inTransaction(false),
|
||||
_queryTimeout(-1)
|
||||
{
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
setProperty("handle", _db.handle());
|
||||
}
|
||||
|
||||
|
||||
SessionImpl::~SessionImpl()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isTransaction() && !getFeature("autoCommit"))
|
||||
{
|
||||
try { rollback(); }
|
||||
catch (...) { }
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::Data::StatementImpl::Ptr SessionImpl::createStatementImpl()
|
||||
{
|
||||
return new ODBCStatementImpl(*this);
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::open(const std::string& connect)
|
||||
{
|
||||
if (connect != connectionString())
|
||||
{
|
||||
if (isConnected())
|
||||
throw InvalidAccessException("Session already connected");
|
||||
|
||||
if (!connect.empty())
|
||||
setConnectionString(connect);
|
||||
}
|
||||
|
||||
poco_assert_dbg (!connectionString().empty());
|
||||
|
||||
SQLULEN tout = static_cast<SQLULEN>(getLoginTimeout());
|
||||
if (Utility::isError(SQLSetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) tout, 0)))
|
||||
{
|
||||
if (Utility::isError(SQLGetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, &tout, 0, 0)) ||
|
||||
getLoginTimeout() != tout)
|
||||
{
|
||||
ConnectionError e(_db);
|
||||
throw ConnectionFailedException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
SQLCHAR connectOutput[512] = {0};
|
||||
SQLSMALLINT result;
|
||||
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLDriverConnect(_db
|
||||
, NULL
|
||||
,(SQLCHAR*) connectionString().c_str()
|
||||
,(SQLSMALLINT) SQL_NTS
|
||||
, connectOutput
|
||||
, sizeof(connectOutput)
|
||||
, &result
|
||||
, SQL_DRIVER_NOPROMPT)))
|
||||
{
|
||||
ConnectionError err(_db);
|
||||
std::string errStr = err.toString();
|
||||
close();
|
||||
throw ConnectionFailedException(errStr);
|
||||
}
|
||||
|
||||
_dataTypes.fillTypeInfo(_db);
|
||||
addProperty("dataTypeInfo",
|
||||
&SessionImpl::setDataTypeInfo,
|
||||
&SessionImpl::dataTypeInfo);
|
||||
|
||||
addFeature("autoCommit",
|
||||
&SessionImpl::autoCommit,
|
||||
&SessionImpl::isAutoCommit);
|
||||
|
||||
addFeature("autoBind",
|
||||
&SessionImpl::autoBind,
|
||||
&SessionImpl::isAutoBind);
|
||||
|
||||
addFeature("autoExtract",
|
||||
&SessionImpl::autoExtract,
|
||||
&SessionImpl::isAutoExtract);
|
||||
|
||||
addProperty("maxFieldSize",
|
||||
&SessionImpl::setMaxFieldSize,
|
||||
&SessionImpl::getMaxFieldSize);
|
||||
|
||||
addProperty("queryTimeout",
|
||||
&SessionImpl::setQueryTimeout,
|
||||
&SessionImpl::getQueryTimeout);
|
||||
|
||||
Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0);
|
||||
|
||||
if (!canTransact()) autoCommit("", true);
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isConnected() const
|
||||
{
|
||||
SQLULEN value = 0;
|
||||
|
||||
if (Utility::isError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
||||
SQL_ATTR_CONNECTION_DEAD,
|
||||
&value,
|
||||
0,
|
||||
0))) return false;
|
||||
|
||||
return (SQL_CD_FALSE == value);
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::setConnectionTimeout(std::size_t timeout)
|
||||
{
|
||||
SQLUINTEGER value = static_cast<SQLUINTEGER>(timeout);
|
||||
|
||||
checkError(Poco::Data::ODBC::SQLSetConnectAttr(_db,
|
||||
SQL_ATTR_CONNECTION_TIMEOUT,
|
||||
&value,
|
||||
SQL_IS_UINTEGER), "Failed to set connection timeout.");
|
||||
}
|
||||
|
||||
|
||||
std::size_t SessionImpl::getConnectionTimeout() const
|
||||
{
|
||||
SQLULEN value = 0;
|
||||
|
||||
checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
||||
SQL_ATTR_CONNECTION_TIMEOUT,
|
||||
&value,
|
||||
0,
|
||||
0), "Failed to get connection timeout.");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::canTransact() const
|
||||
{
|
||||
if (ODBC_TXN_CAPABILITY_UNKNOWN == _canTransact)
|
||||
{
|
||||
SQLUSMALLINT ret;
|
||||
checkError(Poco::Data::ODBC::SQLGetInfo(_db, SQL_TXN_CAPABLE, &ret, 0, 0),
|
||||
"Failed to obtain transaction capability info.");
|
||||
|
||||
_canTransact = (SQL_TC_NONE != ret) ?
|
||||
ODBC_TXN_CAPABILITY_TRUE :
|
||||
ODBC_TXN_CAPABILITY_FALSE;
|
||||
}
|
||||
|
||||
return ODBC_TXN_CAPABILITY_TRUE == _canTransact;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::setTransactionIsolation(Poco::UInt32 ti)
|
||||
{
|
||||
setTransactionIsolationImpl(ti);
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::setTransactionIsolationImpl(Poco::UInt32 ti) const
|
||||
{
|
||||
#if POCO_PTR_IS_64_BIT
|
||||
Poco::UInt64 isolation = 0;
|
||||
#else
|
||||
Poco::UInt32 isolation = 0;
|
||||
#endif
|
||||
|
||||
if (ti & Session::TRANSACTION_READ_UNCOMMITTED)
|
||||
isolation |= SQL_TXN_READ_UNCOMMITTED;
|
||||
|
||||
if (ti & Session::TRANSACTION_READ_COMMITTED)
|
||||
isolation |= SQL_TXN_READ_COMMITTED;
|
||||
|
||||
if (ti & Session::TRANSACTION_REPEATABLE_READ)
|
||||
isolation |= SQL_TXN_REPEATABLE_READ;
|
||||
|
||||
if (ti & Session::TRANSACTION_SERIALIZABLE)
|
||||
isolation |= SQL_TXN_SERIALIZABLE;
|
||||
|
||||
checkError(SQLSetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER) isolation, 0));
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt32 SessionImpl::getTransactionIsolation() const
|
||||
{
|
||||
SQLULEN isolation = 0;
|
||||
checkError(SQLGetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION,
|
||||
&isolation,
|
||||
0,
|
||||
0));
|
||||
|
||||
return transactionIsolation(isolation);
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti) const
|
||||
{
|
||||
if (isTransaction()) throw InvalidAccessException();
|
||||
|
||||
bool retval = true;
|
||||
Poco::UInt32 old = getTransactionIsolation();
|
||||
try { setTransactionIsolationImpl(ti); }
|
||||
catch (Poco::Exception&) { retval = false; }
|
||||
setTransactionIsolationImpl(old);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt32 SessionImpl::getDefaultTransactionIsolation() const
|
||||
{
|
||||
SQLUINTEGER isolation = 0;
|
||||
checkError(SQLGetInfo(_db, SQL_DEFAULT_TXN_ISOLATION,
|
||||
&isolation,
|
||||
0,
|
||||
0));
|
||||
|
||||
return transactionIsolation(isolation);
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt32 SessionImpl::transactionIsolation(SQLULEN isolation)
|
||||
{
|
||||
if (0 == isolation)
|
||||
throw InvalidArgumentException("transactionIsolation(SQLUINTEGER)");
|
||||
|
||||
Poco::UInt32 ret = 0;
|
||||
|
||||
if (isolation & SQL_TXN_READ_UNCOMMITTED)
|
||||
ret |= Session::TRANSACTION_READ_UNCOMMITTED;
|
||||
|
||||
if (isolation & SQL_TXN_READ_COMMITTED)
|
||||
ret |= Session::TRANSACTION_READ_COMMITTED;
|
||||
|
||||
if (isolation & SQL_TXN_REPEATABLE_READ)
|
||||
ret |= Session::TRANSACTION_REPEATABLE_READ;
|
||||
|
||||
if (isolation & SQL_TXN_SERIALIZABLE)
|
||||
ret |= Session::TRANSACTION_SERIALIZABLE;
|
||||
|
||||
if (0 == ret)
|
||||
throw InvalidArgumentException("transactionIsolation(SQLUINTEGER)");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::autoCommit(const std::string&, bool val)
|
||||
{
|
||||
checkError(Poco::Data::ODBC::SQLSetConnectAttr(_db,
|
||||
SQL_ATTR_AUTOCOMMIT,
|
||||
val ? (SQLPOINTER) SQL_AUTOCOMMIT_ON :
|
||||
(SQLPOINTER) SQL_AUTOCOMMIT_OFF,
|
||||
SQL_IS_UINTEGER), "Failed to set automatic commit.");
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isAutoCommit(const std::string&) const
|
||||
{
|
||||
SQLULEN value = 0;
|
||||
|
||||
checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
||||
SQL_ATTR_AUTOCOMMIT,
|
||||
&value,
|
||||
0,
|
||||
0));
|
||||
|
||||
return (0 != value);
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isTransaction() const
|
||||
{
|
||||
if (!canTransact()) return false;
|
||||
|
||||
SQLULEN value = 0;
|
||||
checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db,
|
||||
SQL_ATTR_AUTOCOMMIT,
|
||||
&value,
|
||||
0,
|
||||
0));
|
||||
|
||||
if (0 == value) return _inTransaction;
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::begin()
|
||||
{
|
||||
if (isAutoCommit())
|
||||
throw InvalidAccessException("Session in auto commit mode.");
|
||||
|
||||
{
|
||||
Poco::FastMutex::ScopedLock l(_mutex);
|
||||
|
||||
if (_inTransaction)
|
||||
throw InvalidAccessException("Transaction in progress.");
|
||||
|
||||
_inTransaction = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::commit()
|
||||
{
|
||||
if (!isAutoCommit())
|
||||
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_COMMIT));
|
||||
|
||||
_inTransaction = false;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::rollback()
|
||||
{
|
||||
if (!isAutoCommit())
|
||||
checkError(SQLEndTran(SQL_HANDLE_DBC, _db, SQL_ROLLBACK));
|
||||
|
||||
_inTransaction = false;
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::close()
|
||||
{
|
||||
if (!isConnected()) return;
|
||||
|
||||
try
|
||||
{
|
||||
commit();
|
||||
}
|
||||
catch (ConnectionException&)
|
||||
{
|
||||
}
|
||||
|
||||
SQLDisconnect(_db);
|
||||
}
|
||||
|
||||
|
||||
int SessionImpl::maxStatementLength() const
|
||||
{
|
||||
SQLUINTEGER info;
|
||||
SQLRETURN rc = 0;
|
||||
if (Utility::isError(rc = Poco::Data::ODBC::SQLGetInfo(_db,
|
||||
SQL_MAXIMUM_STATEMENT_LENGTH,
|
||||
(SQLPOINTER) &info,
|
||||
0,
|
||||
0)))
|
||||
{
|
||||
throw ConnectionException(_db,
|
||||
"SQLGetInfo(SQL_MAXIMUM_STATEMENT_LENGTH)");
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// TypeInfo.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: TypeInfo
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/TypeInfo.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
TypeInfo::TypeInfo(SQLHDBC* pHDBC): _pHDBC(pHDBC)
|
||||
{
|
||||
fillCTypes();
|
||||
fillSQLTypes();
|
||||
if (_pHDBC) fillTypeInfo(*_pHDBC);
|
||||
}
|
||||
|
||||
|
||||
TypeInfo::~TypeInfo()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void TypeInfo::fillCTypes()
|
||||
{
|
||||
_cDataTypes.insert(ValueType(SQL_CHAR, SQL_C_CHAR));
|
||||
_cDataTypes.insert(ValueType(SQL_VARCHAR, SQL_C_CHAR));
|
||||
_cDataTypes.insert(ValueType(SQL_LONGVARCHAR, SQL_C_CHAR));
|
||||
_cDataTypes.insert(ValueType(SQL_DECIMAL, SQL_C_DOUBLE));
|
||||
_cDataTypes.insert(ValueType(SQL_NUMERIC, SQL_C_DOUBLE));
|
||||
_cDataTypes.insert(ValueType(SQL_BIT, SQL_C_BIT));
|
||||
_cDataTypes.insert(ValueType(SQL_TINYINT, SQL_C_STINYINT));
|
||||
_cDataTypes.insert(ValueType(SQL_SMALLINT, SQL_C_SSHORT));
|
||||
_cDataTypes.insert(ValueType(SQL_INTEGER, SQL_C_SLONG));
|
||||
_cDataTypes.insert(ValueType(SQL_BIGINT, SQL_C_SBIGINT));
|
||||
_cDataTypes.insert(ValueType(SQL_REAL, SQL_C_FLOAT));
|
||||
_cDataTypes.insert(ValueType(SQL_FLOAT, SQL_C_DOUBLE));
|
||||
_cDataTypes.insert(ValueType(SQL_DOUBLE, SQL_C_DOUBLE));
|
||||
_cDataTypes.insert(ValueType(SQL_BINARY, SQL_C_BINARY));
|
||||
_cDataTypes.insert(ValueType(SQL_VARBINARY, SQL_C_BINARY));
|
||||
_cDataTypes.insert(ValueType(SQL_LONGVARBINARY, SQL_C_BINARY));
|
||||
_cDataTypes.insert(ValueType(SQL_TYPE_DATE, SQL_C_TYPE_DATE));
|
||||
_cDataTypes.insert(ValueType(SQL_TYPE_TIME, SQL_C_TYPE_TIME));
|
||||
_cDataTypes.insert(ValueType(SQL_TYPE_TIMESTAMP, SQL_C_TYPE_TIMESTAMP));
|
||||
}
|
||||
|
||||
|
||||
void TypeInfo::fillSQLTypes()
|
||||
{
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_CHAR, SQL_LONGVARCHAR));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_BIT, SQL_BIT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_TINYINT, SQL_TINYINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_STINYINT, SQL_TINYINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_UTINYINT, SQL_TINYINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_SHORT, SQL_SMALLINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_SSHORT, SQL_SMALLINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_USHORT, SQL_SMALLINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_LONG, SQL_INTEGER));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_SLONG, SQL_INTEGER));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_ULONG, SQL_INTEGER));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_SBIGINT, SQL_BIGINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_UBIGINT, SQL_BIGINT));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_FLOAT, SQL_REAL));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_DOUBLE, SQL_DOUBLE));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_BINARY, SQL_LONGVARBINARY));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_TYPE_DATE, SQL_TYPE_DATE));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_TYPE_TIME, SQL_TYPE_TIME));
|
||||
_sqlDataTypes.insert(ValueType(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP));
|
||||
}
|
||||
|
||||
|
||||
void TypeInfo::fillTypeInfo(SQLHDBC pHDBC)
|
||||
{
|
||||
_pHDBC = &pHDBC;
|
||||
|
||||
if (_typeInfo.empty() && _pHDBC)
|
||||
{
|
||||
const static int stringSize = 512;
|
||||
TypeInfoVec().swap(_typeInfo);
|
||||
|
||||
SQLRETURN rc;
|
||||
SQLHSTMT hstmt = SQL_NULL_HSTMT;
|
||||
|
||||
rc = SQLAllocHandle(SQL_HANDLE_STMT, *_pHDBC, &hstmt);
|
||||
if (!SQL_SUCCEEDED(rc))
|
||||
throw StatementException(hstmt, "SQLGetData()");
|
||||
|
||||
rc = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES);
|
||||
if (SQL_SUCCEEDED(rc))
|
||||
{
|
||||
while (SQLFetch(hstmt) != SQL_NO_DATA_FOUND)
|
||||
{
|
||||
char typeName[stringSize] = { 0 };
|
||||
char literalPrefix[stringSize] = { 0 };
|
||||
char literalSuffix[stringSize] = { 0 };
|
||||
char createParams[stringSize] = { 0 };
|
||||
char localTypeName[stringSize] = { 0 };
|
||||
|
||||
TypeInfoTup ti("TYPE_NAME", "",
|
||||
"DATA_TYPE", 0,
|
||||
"COLUMN_SIZE", 0,
|
||||
"LITERAL_PREFIX", "",
|
||||
"LITERAL_SUFFIX", "",
|
||||
"CREATE_PARAMS", "",
|
||||
"NULLABLE", 0,
|
||||
"CASE_SENSITIVE", 0,
|
||||
"SEARCHABLE", 0,
|
||||
"UNSIGNED_ATTRIBUTE", 0,
|
||||
"FIXED_PREC_SCALE", 0,
|
||||
"AUTO_UNIQUE_VALUE", 0,
|
||||
"LOCAL_TYPE_NAME", "",
|
||||
"MINIMUM_SCALE", 0,
|
||||
"MAXIMUM_SCALE", 0,
|
||||
"SQL_DATA_TYPE", 0,
|
||||
"SQL_DATETIME_SUB", 0,
|
||||
"NUM_PREC_RADIX", 0,
|
||||
"INTERVAL_PRECISION", 0);
|
||||
|
||||
SQLLEN ind = 0;
|
||||
rc = SQLGetData(hstmt, 1, SQL_C_CHAR, typeName, sizeof(typeName), &ind);
|
||||
ti.set<0>(typeName);
|
||||
rc = SQLGetData(hstmt, 2, SQL_C_SSHORT, &ti.get<1>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &ti.get<2>(), sizeof(SQLINTEGER), &ind);
|
||||
rc = SQLGetData(hstmt, 4, SQL_C_CHAR, literalPrefix, sizeof(literalPrefix), &ind);
|
||||
ti.set<3>(literalPrefix);
|
||||
rc = SQLGetData(hstmt, 5, SQL_C_CHAR, literalSuffix, sizeof(literalSuffix), &ind);
|
||||
ti.set<4>(literalSuffix);
|
||||
rc = SQLGetData(hstmt, 6, SQL_C_CHAR, createParams, sizeof(createParams), &ind);
|
||||
ti.set<5>(createParams);
|
||||
rc = SQLGetData(hstmt, 7, SQL_C_SSHORT, &ti.get<6>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 8, SQL_C_SSHORT, &ti.get<7>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 9, SQL_C_SSHORT, &ti.get<8>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 10, SQL_C_SSHORT, &ti.get<9>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 11, SQL_C_SSHORT, &ti.get<10>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 12, SQL_C_SSHORT, &ti.get<11>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 13, SQL_C_CHAR, localTypeName, sizeof(localTypeName), &ind);
|
||||
ti.set<12>(localTypeName);
|
||||
rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &ti.get<13>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 15, SQL_C_SSHORT, &ti.get<14>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 16, SQL_C_SSHORT, &ti.get<15>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 17, SQL_C_SSHORT, &ti.get<16>(), sizeof(SQLSMALLINT), &ind);
|
||||
rc = SQLGetData(hstmt, 18, SQL_C_SLONG, &ti.get<17>(), sizeof(SQLINTEGER), &ind);
|
||||
rc = SQLGetData(hstmt, 19, SQL_C_SSHORT, &ti.get<18>(), sizeof(SQLSMALLINT), &ind);
|
||||
|
||||
_typeInfo.push_back(ti);
|
||||
}
|
||||
}
|
||||
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DynamicAny TypeInfo::getInfo(SQLSMALLINT type, const std::string& param) const
|
||||
{
|
||||
TypeInfoVec::const_iterator it = _typeInfo.begin();
|
||||
TypeInfoVec::const_iterator end = _typeInfo.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (type == it->get<1>())
|
||||
return (*it)[param];
|
||||
}
|
||||
|
||||
throw NotFoundException(param);
|
||||
}
|
||||
|
||||
|
||||
bool TypeInfo::tryGetInfo(SQLSMALLINT type, const std::string& param, DynamicAny& result) const
|
||||
{
|
||||
TypeInfoVec::const_iterator it = _typeInfo.begin();
|
||||
TypeInfoVec::const_iterator end = _typeInfo.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (type == it->get<1>())
|
||||
{
|
||||
result = (*it)[param];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int TypeInfo::cDataType(int sqlDataType) const
|
||||
{
|
||||
DataTypeMap::const_iterator it = _cDataTypes.find(sqlDataType);
|
||||
|
||||
if (_cDataTypes.end() == it)
|
||||
throw NotFoundException(format("C data type not found for SQL data type: %d", sqlDataType));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
int TypeInfo::sqlDataType(int cDataType) const
|
||||
{
|
||||
DataTypeMap::const_iterator it = _sqlDataTypes.find(cDataType);
|
||||
|
||||
if (_sqlDataTypes.end() == it)
|
||||
throw NotFoundException(format("SQL data type not found for C data type: %d", cDataType));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
void TypeInfo::print(std::ostream& ostr)
|
||||
{
|
||||
if (_typeInfo.empty())
|
||||
{
|
||||
ostr << "No data found.";
|
||||
return;
|
||||
}
|
||||
|
||||
TypeInfoTup::NameVec::const_iterator nIt = (*_typeInfo[0].names()).begin();
|
||||
TypeInfoTup::NameVec::const_iterator nItEnd = (*_typeInfo[0].names()).end();
|
||||
for (; nIt != nItEnd; ++nIt)
|
||||
ostr << *nIt << "\t";
|
||||
|
||||
ostr << std::endl;
|
||||
|
||||
TypeInfoVec::const_iterator it = _typeInfo.begin();
|
||||
TypeInfoVec::const_iterator end = _typeInfo.end();
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
ostr << it->get<0>() << "\t"
|
||||
<< it->get<1>() << "\t"
|
||||
<< it->get<2>() << "\t"
|
||||
<< it->get<3>() << "\t"
|
||||
<< it->get<4>() << "\t"
|
||||
<< it->get<5>() << "\t"
|
||||
<< it->get<6>() << "\t"
|
||||
<< it->get<7>() << "\t"
|
||||
<< it->get<8>() << "\t"
|
||||
<< it->get<9>() << "\t"
|
||||
<< it->get<10>() << "\t"
|
||||
<< it->get<11>() << "\t"
|
||||
<< it->get<12>() << "\t"
|
||||
<< it->get<13>() << "\t"
|
||||
<< it->get<14>() << "\t"
|
||||
<< it->get<15>() << "\t"
|
||||
<< it->get<16>() << "\t"
|
||||
<< it->get<17>() << "\t"
|
||||
<< it->get<18>() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Unicode.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Unicode
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBC.h"
|
||||
|
||||
|
||||
#if defined(POCO_ODBC_UNICODE_WINDOWS)
|
||||
#include "Unicode_WIN32.cpp"
|
||||
#elif defined(POCO_ODBC_UNICODE_UNIXODBC)
|
||||
#include "Unicode_UNIXODBC.cpp"
|
||||
#endif
|
||||
+775
@@ -0,0 +1,775 @@
|
||||
//
|
||||
// Unicode.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Unicode
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBC.h"
|
||||
#include "Poco/Data/ODBC/Unicode_UNIXODBC.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/UTF8Encoding.h"
|
||||
#include "Poco/UTF16Encoding.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using Poco::Buffer;
|
||||
using Poco::UTF8Encoding;
|
||||
using Poco::UTF16Encoding;
|
||||
using Poco::TextConverter;
|
||||
using Poco::InvalidArgumentException;
|
||||
using Poco::NotImplementedException;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
void makeUTF16(SQLCHAR* pSQLChar, SQLINTEGER length, std::string& target)
|
||||
{
|
||||
int len = length;
|
||||
if (SQL_NTS == len)
|
||||
len = (int) std::strlen((const char *) pSQLChar);
|
||||
|
||||
UTF8Encoding utf8Encoding;
|
||||
UTF16Encoding utf16Encoding;
|
||||
TextConverter converter(utf8Encoding, utf16Encoding);
|
||||
|
||||
if (0 != converter.convert(pSQLChar, len, target))
|
||||
throw DataFormatException("Error converting UTF-8 to UTF-16");
|
||||
}
|
||||
|
||||
|
||||
void makeUTF8(Poco::Buffer<SQLWCHAR>& buffer, SQLINTEGER length, SQLPOINTER pTarget, SQLINTEGER targetLength)
|
||||
{
|
||||
UTF8Encoding utf8Encoding;
|
||||
UTF16Encoding utf16Encoding;
|
||||
TextConverter converter(utf16Encoding, utf8Encoding);
|
||||
|
||||
std::string result;
|
||||
if (0 != converter.convert(buffer.begin(), length, result))
|
||||
throw DataFormatException("Error converting UTF-16 to UTF-8");
|
||||
|
||||
std::memset(pTarget, 0, targetLength);
|
||||
std::strncpy((char*) pTarget, result.c_str(), result.size() < targetLength ? result.size() : targetLength);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColAttribute(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT iCol,
|
||||
SQLUSMALLINT iField,
|
||||
SQLPOINTER pCharAttr,
|
||||
SQLSMALLINT cbCharAttrMax,
|
||||
SQLSMALLINT* pcbCharAttr,
|
||||
NumAttrPtrType pNumAttr)
|
||||
{
|
||||
if (isString(pCharAttr, cbCharAttrMax))
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(stringLength(pCharAttr, cbCharAttrMax));
|
||||
|
||||
SQLRETURN rc = SQLColAttributeW(hstmt,
|
||||
iCol,
|
||||
iField,
|
||||
buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbCharAttr,
|
||||
pNumAttr);
|
||||
|
||||
makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLColAttributeW(hstmt,
|
||||
iCol,
|
||||
iField,
|
||||
pCharAttr,
|
||||
cbCharAttrMax,
|
||||
pcbCharAttr,
|
||||
pNumAttr);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColAttributes(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLUSMALLINT fDescType,
|
||||
SQLPOINTER rgbDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT* pcbDesc,
|
||||
SQLLEN* pfDesc)
|
||||
{
|
||||
return SQLColAttribute(hstmt,
|
||||
icol,
|
||||
fDescType,
|
||||
rgbDesc,
|
||||
cbDescMax,
|
||||
pcbDesc,
|
||||
pfDesc);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLConnect(SQLHDBC hdbc,
|
||||
SQLCHAR* szDSN,
|
||||
SQLSMALLINT cbDSN,
|
||||
SQLCHAR* szUID,
|
||||
SQLSMALLINT cbUID,
|
||||
SQLCHAR* szAuthStr,
|
||||
SQLSMALLINT cbAuthStr)
|
||||
{
|
||||
std::string sqlDSN;
|
||||
makeUTF16(szDSN, cbDSN, sqlDSN);
|
||||
|
||||
std::string sqlUID;
|
||||
makeUTF16(szUID, cbUID, sqlUID);
|
||||
|
||||
std::string sqlPWD;
|
||||
makeUTF16(szAuthStr, cbAuthStr, sqlPWD);
|
||||
|
||||
return SQLConnectW(hdbc,
|
||||
(SQLWCHAR*) sqlDSN.c_str(), cbDSN,
|
||||
(SQLWCHAR*) sqlUID.c_str(), cbUID,
|
||||
(SQLWCHAR*) sqlPWD.c_str(), cbAuthStr);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDescribeCol(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLCHAR* szColName,
|
||||
SQLSMALLINT cbColNameMax,
|
||||
SQLSMALLINT* pcbColName,
|
||||
SQLSMALLINT* pfSqlType,
|
||||
SQLULEN* pcbColDef,
|
||||
SQLSMALLINT* pibScale,
|
||||
SQLSMALLINT* pfNullable)
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(cbColNameMax);
|
||||
SQLRETURN rc = SQLDescribeColW(hstmt,
|
||||
icol,
|
||||
(SQLWCHAR*) buffer.begin(),
|
||||
(SQLSMALLINT) buffer.size(),
|
||||
pcbColName,
|
||||
pfSqlType,
|
||||
pcbColDef,
|
||||
pibScale,
|
||||
pfNullable);
|
||||
|
||||
makeUTF8(buffer, *pcbColName * sizeof(SQLWCHAR), szColName, cbColNameMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLError(SQLHENV henv,
|
||||
SQLHDBC hdbc,
|
||||
SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlState,
|
||||
SQLINTEGER* pfNativeError,
|
||||
SQLCHAR* szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT* pcbErrorMsg)
|
||||
{
|
||||
throw NotImplementedException("SQLError is obsolete. "
|
||||
"Use SQLGetDiagRec instead.");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLExecDirect(SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
std::string sqlStr;
|
||||
makeUTF16(szSqlStr, cbSqlStr, sqlStr);
|
||||
|
||||
return SQLExecDirectW(hstmt, (SQLWCHAR*) sqlStr.c_str(), cbSqlStr);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
SQLRETURN rc = SQLGetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
|
||||
makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
return SQLGetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
rgbValue,
|
||||
cbValueMax,
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetCursorName(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCursor,
|
||||
SQLSMALLINT cbCursorMax,
|
||||
SQLSMALLINT* pcbCursor)
|
||||
{
|
||||
throw NotImplementedException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetDescField(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT iField,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
std::string str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValueMax, str);
|
||||
|
||||
return SQLSetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
(SQLPOINTER) str.c_str(),
|
||||
(SQLINTEGER) str.size() * sizeof(SQLWCHAR));
|
||||
}
|
||||
|
||||
return SQLSetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
rgbValue,
|
||||
cbValueMax);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDescField(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT iField,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
SQLRETURN rc = SQLGetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
|
||||
makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
rgbValue,
|
||||
cbValueMax,
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDescRec(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLCHAR* szName,
|
||||
SQLSMALLINT cbNameMax,
|
||||
SQLSMALLINT* pcbName,
|
||||
SQLSMALLINT* pfType,
|
||||
SQLSMALLINT* pfSubType,
|
||||
SQLLEN* pLength,
|
||||
SQLSMALLINT* pPrecision,
|
||||
SQLSMALLINT* pScale,
|
||||
SQLSMALLINT* pNullable)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDiagField(SQLSMALLINT fHandleType,
|
||||
SQLHANDLE handle,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT fDiagField,
|
||||
SQLPOINTER rgbDiagInfo,
|
||||
SQLSMALLINT cbDiagInfoMax,
|
||||
SQLSMALLINT* pcbDiagInfo)
|
||||
{
|
||||
if (isString(rgbDiagInfo, cbDiagInfoMax))
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(stringLength(rgbDiagInfo, cbDiagInfoMax));
|
||||
|
||||
SQLRETURN rc = SQLGetDiagFieldW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
fDiagField,
|
||||
buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbDiagInfo);
|
||||
|
||||
makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetDiagFieldW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
fDiagField,
|
||||
rgbDiagInfo,
|
||||
cbDiagInfoMax,
|
||||
pcbDiagInfo);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType,
|
||||
SQLHANDLE handle,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLCHAR* szSqlState,
|
||||
SQLINTEGER* pfNativeError,
|
||||
SQLCHAR* szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT* pcbErrorMsg)
|
||||
{
|
||||
const SQLINTEGER stateLen = SQL_SQLSTATE_SIZE + 1;
|
||||
Buffer<SQLWCHAR> bufState(stateLen);
|
||||
Buffer<SQLWCHAR> bufErr(cbErrorMsgMax);
|
||||
|
||||
SQLRETURN rc = SQLGetDiagRecW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
bufState.begin(),
|
||||
pfNativeError,
|
||||
bufErr.begin(),
|
||||
(SQLSMALLINT) bufErr.size(),
|
||||
pcbErrorMsg);
|
||||
|
||||
makeUTF8(bufState, stateLen * sizeof(SQLWCHAR), szSqlState, stateLen);
|
||||
makeUTF8(bufErr, *pcbErrorMsg * sizeof(SQLWCHAR), szErrorMsg, cbErrorMsgMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLPrepare(SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
std::string sqlStr;
|
||||
makeUTF16(szSqlStr, cbSqlStr, sqlStr);
|
||||
|
||||
return SQLPrepareW(hstmt, (SQLWCHAR*) sqlStr.c_str(), (SQLINTEGER) sqlStr.size());
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetConnectAttr(SQLHDBC hdbc,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValue))
|
||||
{
|
||||
std::string str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValue, str);
|
||||
|
||||
return SQLSetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLINTEGER) str.size() * sizeof(SQLWCHAR));
|
||||
}
|
||||
|
||||
return SQLSetConnectAttrW(hdbc, fAttribute, rgbValue, cbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetCursorName(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCursor,
|
||||
SQLSMALLINT cbCursor)
|
||||
{
|
||||
throw NotImplementedException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetStmtAttr(SQLHSTMT hstmt,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
std::string str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValueMax, str);
|
||||
|
||||
return SQLSetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLINTEGER) str.size());
|
||||
}
|
||||
|
||||
return SQLSetStmtAttrW(hstmt, fAttribute, rgbValue, cbValueMax);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetStmtAttr(SQLHSTMT hstmt,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
return SQLGetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
(SQLPOINTER) buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
return SQLGetStmtAttrW(hstmt, fAttribute, rgbValue, cbValueMax, pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColumns(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetConnectOption(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fOption,
|
||||
SQLPOINTER pvParam)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetInfo(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fInfoType,
|
||||
SQLPOINTER rgbInfoValue,
|
||||
SQLSMALLINT cbInfoValueMax,
|
||||
SQLSMALLINT* pcbInfoValue)
|
||||
{
|
||||
if (cbInfoValueMax)
|
||||
{
|
||||
Buffer<SQLWCHAR> buffer(cbInfoValueMax);
|
||||
|
||||
SQLRETURN rc = SQLGetInfoW(hdbc,
|
||||
fInfoType,
|
||||
(SQLPOINTER) buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbInfoValue);
|
||||
|
||||
makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetInfoW(hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType)
|
||||
{
|
||||
return SQLGetTypeInfoW(StatementHandle, DataType);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetConnectOption(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fOption,
|
||||
SQLULEN vParam)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSpecialColumns(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT fColType,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLUSMALLINT fScope,
|
||||
SQLUSMALLINT fNullable)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLStatistics(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLUSMALLINT fUnique,
|
||||
SQLUSMALLINT fAccuracy)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLTables(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szTableType,
|
||||
SQLSMALLINT cbTableType)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDataSources(SQLHENV henv,
|
||||
SQLUSMALLINT fDirection,
|
||||
SQLCHAR* szDSN,
|
||||
SQLSMALLINT cbDSNMax,
|
||||
SQLSMALLINT* pcbDSN,
|
||||
SQLCHAR* szDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT* pcbDesc)
|
||||
{
|
||||
Buffer<SQLWCHAR> bufDSN(cbDSNMax);
|
||||
Buffer<SQLWCHAR> bufDesc(cbDescMax);
|
||||
|
||||
SQLRETURN rc = SQLDataSourcesW(henv,
|
||||
fDirection,
|
||||
bufDSN.begin(),
|
||||
(SQLSMALLINT) bufDSN.size(),
|
||||
pcbDSN,
|
||||
bufDesc.begin(),
|
||||
(SQLSMALLINT) bufDesc.size(),
|
||||
pcbDesc);
|
||||
|
||||
makeUTF8(bufDSN, *pcbDSN * sizeof(SQLWCHAR), szDSN, cbDSNMax);
|
||||
makeUTF8(bufDesc, *pcbDesc * sizeof(SQLWCHAR), szDesc, cbDescMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDriverConnect(SQLHDBC hdbc,
|
||||
SQLHWND hwnd,
|
||||
SQLCHAR* szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLCHAR* szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT* pcbConnStrOut,
|
||||
SQLUSMALLINT fDriverCompletion)
|
||||
{
|
||||
SQLSMALLINT len = cbConnStrIn;
|
||||
if (SQL_NTS == len)
|
||||
len = (SQLSMALLINT) std::strlen((const char*) szConnStrIn) + 1;
|
||||
|
||||
std::string connStrIn;
|
||||
makeUTF16(szConnStrIn, len, connStrIn);
|
||||
|
||||
Buffer<SQLWCHAR> out(cbConnStrOutMax);
|
||||
SQLRETURN rc = SQLDriverConnectW(hdbc,
|
||||
hwnd,
|
||||
(SQLWCHAR*) connStrIn.c_str(),
|
||||
(SQLSMALLINT) connStrIn.size(),
|
||||
out.begin(),
|
||||
cbConnStrOutMax,
|
||||
pcbConnStrOut,
|
||||
fDriverCompletion);
|
||||
|
||||
makeUTF8(out, *pcbConnStrOut * sizeof(SQLWCHAR), pcbConnStrOut, cbConnStrOutMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLBrowseConnect(SQLHDBC hdbc,
|
||||
SQLCHAR* szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLCHAR* szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT* pcbConnStrOut)
|
||||
{
|
||||
std::string str;
|
||||
makeUTF16(szConnStrIn, cbConnStrIn, str);
|
||||
|
||||
Buffer<SQLWCHAR> bufConnStrOut(cbConnStrOutMax);
|
||||
|
||||
SQLRETURN rc = SQLBrowseConnectW(hdbc,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLSMALLINT) str.size(),
|
||||
bufConnStrOut.begin(),
|
||||
(SQLSMALLINT) bufConnStrOut.size(),
|
||||
pcbConnStrOut);
|
||||
|
||||
makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(SQLWCHAR), szConnStrOut, cbConnStrOutMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColumnPrivileges(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLForeignKeys(SQLHSTMT hstmt,
|
||||
SQLCHAR* szPkCatalogName,
|
||||
SQLSMALLINT cbPkCatalogName,
|
||||
SQLCHAR* szPkSchemaName,
|
||||
SQLSMALLINT cbPkSchemaName,
|
||||
SQLCHAR* szPkTableName,
|
||||
SQLSMALLINT cbPkTableName,
|
||||
SQLCHAR* szFkCatalogName,
|
||||
SQLSMALLINT cbFkCatalogName,
|
||||
SQLCHAR* szFkSchemaName,
|
||||
SQLSMALLINT cbFkSchemaName,
|
||||
SQLCHAR* szFkTableName,
|
||||
SQLSMALLINT cbFkTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLNativeSql(SQLHDBC hdbc,
|
||||
SQLCHAR* szSqlStrIn,
|
||||
SQLINTEGER cbSqlStrIn,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStrMax,
|
||||
SQLINTEGER* pcbSqlStr)
|
||||
{
|
||||
std::string str;
|
||||
makeUTF16(szSqlStrIn, cbSqlStrIn, str);
|
||||
|
||||
Buffer<SQLWCHAR> bufSQLOut(cbSqlStrMax);
|
||||
|
||||
SQLRETURN rc = SQLNativeSqlW(hdbc,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLINTEGER) str.size(),
|
||||
bufSQLOut.begin(),
|
||||
(SQLINTEGER) bufSQLOut.size(),
|
||||
pcbSqlStr);
|
||||
|
||||
makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(SQLWCHAR), szSqlStr, cbSqlStrMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLPrimaryKeys(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLProcedureColumns(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szProcName,
|
||||
SQLSMALLINT cbProcName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLProcedures(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szProcName,
|
||||
SQLSMALLINT cbProcName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLTablePrivileges(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDrivers(SQLHENV henv,
|
||||
SQLUSMALLINT fDirection,
|
||||
SQLCHAR* szDriverDesc,
|
||||
SQLSMALLINT cbDriverDescMax,
|
||||
SQLSMALLINT* pcbDriverDesc,
|
||||
SQLCHAR* szDriverAttributes,
|
||||
SQLSMALLINT cbDrvrAttrMax,
|
||||
SQLSMALLINT* pcbDrvrAttr)
|
||||
{
|
||||
Buffer<SQLWCHAR> bufDriverDesc(cbDriverDescMax);
|
||||
Buffer<SQLWCHAR> bufDriverAttr(cbDrvrAttrMax);
|
||||
|
||||
SQLRETURN rc = SQLDriversW(henv,
|
||||
fDirection,
|
||||
bufDriverDesc.begin(),
|
||||
(SQLSMALLINT) bufDriverDesc.size(),
|
||||
pcbDriverDesc,
|
||||
bufDriverAttr.begin(),
|
||||
(SQLSMALLINT) bufDriverAttr.size(),
|
||||
pcbDrvrAttr);
|
||||
|
||||
makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(SQLWCHAR), szDriverDesc, cbDriverDescMax);
|
||||
makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(SQLWCHAR), szDriverAttributes, cbDrvrAttrMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+761
@@ -0,0 +1,761 @@
|
||||
//
|
||||
// Unicode.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Unicode
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/ODBC.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/Unicode_WIN32.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
using Poco::Buffer;
|
||||
using Poco::InvalidArgumentException;
|
||||
using Poco::NotImplementedException;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
SQLRETURN SQLColAttribute(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT iCol,
|
||||
SQLUSMALLINT iField,
|
||||
SQLPOINTER pCharAttr,
|
||||
SQLSMALLINT cbCharAttrMax,
|
||||
SQLSMALLINT* pcbCharAttr,
|
||||
NumAttrPtrType pNumAttr)
|
||||
{
|
||||
if (isString(pCharAttr, cbCharAttrMax))
|
||||
{
|
||||
Buffer<wchar_t> buffer(stringLength(pCharAttr, cbCharAttrMax));
|
||||
|
||||
SQLRETURN rc = SQLColAttributeW(hstmt,
|
||||
iCol,
|
||||
iField,
|
||||
buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbCharAttr,
|
||||
pNumAttr);
|
||||
|
||||
makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLColAttributeW(hstmt,
|
||||
iCol,
|
||||
iField,
|
||||
pCharAttr,
|
||||
cbCharAttrMax,
|
||||
pcbCharAttr,
|
||||
pNumAttr);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColAttributes(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLUSMALLINT fDescType,
|
||||
SQLPOINTER rgbDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT* pcbDesc,
|
||||
SQLLEN* pfDesc)
|
||||
{
|
||||
return SQLColAttribute(hstmt,
|
||||
icol,
|
||||
fDescType,
|
||||
rgbDesc,
|
||||
cbDescMax,
|
||||
pcbDesc,
|
||||
pfDesc);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLConnect(SQLHDBC hdbc,
|
||||
SQLCHAR* szDSN,
|
||||
SQLSMALLINT cbDSN,
|
||||
SQLCHAR* szUID,
|
||||
SQLSMALLINT cbUID,
|
||||
SQLCHAR* szAuthStr,
|
||||
SQLSMALLINT cbAuthStr)
|
||||
{
|
||||
std::wstring sqlDSN;
|
||||
makeUTF16(szDSN, cbDSN, sqlDSN);
|
||||
|
||||
std::wstring sqlUID;
|
||||
makeUTF16(szUID, cbUID, sqlUID);
|
||||
|
||||
std::wstring sqlPWD;
|
||||
makeUTF16(szAuthStr, cbAuthStr, sqlPWD);
|
||||
|
||||
return SQLConnectW(hdbc,
|
||||
(SQLWCHAR*) sqlDSN.c_str(),
|
||||
(SQLSMALLINT) sqlDSN.size(),
|
||||
(SQLWCHAR*) sqlUID.c_str(),
|
||||
(SQLSMALLINT) sqlUID.size(),
|
||||
(SQLWCHAR*) sqlPWD.c_str(),
|
||||
(SQLSMALLINT) sqlPWD.size());
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDescribeCol(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLCHAR* szColName,
|
||||
SQLSMALLINT cbColNameMax,
|
||||
SQLSMALLINT* pcbColName,
|
||||
SQLSMALLINT* pfSqlType,
|
||||
SQLULEN* pcbColDef,
|
||||
SQLSMALLINT* pibScale,
|
||||
SQLSMALLINT* pfNullable)
|
||||
{
|
||||
Buffer<wchar_t> buffer(cbColNameMax);
|
||||
SQLRETURN rc = SQLDescribeColW(hstmt,
|
||||
icol,
|
||||
(SQLWCHAR*) buffer.begin(),
|
||||
(SQLSMALLINT) buffer.size(),
|
||||
pcbColName,
|
||||
pfSqlType,
|
||||
pcbColDef,
|
||||
pibScale,
|
||||
pfNullable);
|
||||
|
||||
makeUTF8(buffer, *pcbColName * sizeof(wchar_t), szColName, cbColNameMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLError(SQLHENV henv,
|
||||
SQLHDBC hdbc,
|
||||
SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlState,
|
||||
SQLINTEGER* pfNativeError,
|
||||
SQLCHAR* szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT* pcbErrorMsg)
|
||||
{
|
||||
throw NotImplementedException("SQLError is obsolete. "
|
||||
"Use SQLGetDiagRec instead.");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLExecDirect(SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
std::wstring sqlStr;
|
||||
makeUTF16(szSqlStr, cbSqlStr, sqlStr);
|
||||
|
||||
return SQLExecDirectW(hstmt,
|
||||
(SQLWCHAR*) sqlStr.c_str(),
|
||||
(SQLINTEGER) sqlStr.size());
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<wchar_t> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
SQLRETURN rc = SQLGetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
|
||||
makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
return SQLGetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
rgbValue,
|
||||
cbValueMax,
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetCursorName(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCursor,
|
||||
SQLSMALLINT cbCursorMax,
|
||||
SQLSMALLINT* pcbCursor)
|
||||
{
|
||||
throw NotImplementedException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetDescField(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT iField,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
std::wstring str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValueMax, str);
|
||||
|
||||
SQLRETURN rc = SQLSetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
(SQLPOINTER) str.c_str(),
|
||||
(SQLINTEGER) str.size() * sizeof(std::wstring::value_type));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLSetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
rgbValue,
|
||||
cbValueMax);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDescField(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT iField,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<wchar_t> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
SQLRETURN rc = SQLGetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
|
||||
makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetDescFieldW(hdesc,
|
||||
iRecord,
|
||||
iField,
|
||||
rgbValue,
|
||||
cbValueMax,
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDescRec(SQLHDESC hdesc,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLCHAR* szName,
|
||||
SQLSMALLINT cbNameMax,
|
||||
SQLSMALLINT* pcbName,
|
||||
SQLSMALLINT* pfType,
|
||||
SQLSMALLINT* pfSubType,
|
||||
SQLLEN* pLength,
|
||||
SQLSMALLINT* pPrecision,
|
||||
SQLSMALLINT* pScale,
|
||||
SQLSMALLINT* pNullable)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDiagField(SQLSMALLINT fHandleType,
|
||||
SQLHANDLE handle,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLSMALLINT fDiagField,
|
||||
SQLPOINTER rgbDiagInfo,
|
||||
SQLSMALLINT cbDiagInfoMax,
|
||||
SQLSMALLINT* pcbDiagInfo)
|
||||
{
|
||||
if (isString(rgbDiagInfo, cbDiagInfoMax))
|
||||
{
|
||||
Buffer<wchar_t> buffer(stringLength(rgbDiagInfo, cbDiagInfoMax));
|
||||
|
||||
SQLRETURN rc = SQLGetDiagFieldW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
fDiagField,
|
||||
buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbDiagInfo);
|
||||
|
||||
makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetDiagFieldW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
fDiagField,
|
||||
rgbDiagInfo,
|
||||
cbDiagInfoMax,
|
||||
pcbDiagInfo);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType,
|
||||
SQLHANDLE handle,
|
||||
SQLSMALLINT iRecord,
|
||||
SQLCHAR* szSqlState,
|
||||
SQLINTEGER* pfNativeError,
|
||||
SQLCHAR* szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT* pcbErrorMsg)
|
||||
{
|
||||
const SQLINTEGER stateLen = SQL_SQLSTATE_SIZE + 1;
|
||||
Buffer<wchar_t> bufState(stateLen);
|
||||
Buffer<wchar_t> bufErr(cbErrorMsgMax);
|
||||
|
||||
SQLRETURN rc = SQLGetDiagRecW(fHandleType,
|
||||
handle,
|
||||
iRecord,
|
||||
bufState.begin(),
|
||||
pfNativeError,
|
||||
bufErr.begin(),
|
||||
(SQLSMALLINT) bufErr.size(),
|
||||
pcbErrorMsg);
|
||||
|
||||
makeUTF8(bufState, stateLen * sizeof(wchar_t), szSqlState, stateLen);
|
||||
makeUTF8(bufErr, *pcbErrorMsg * sizeof(wchar_t), szErrorMsg, cbErrorMsgMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLPrepare(SQLHSTMT hstmt,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
std::wstring sqlStr;
|
||||
makeUTF16(szSqlStr, cbSqlStr, sqlStr);
|
||||
|
||||
return SQLPrepareW(hstmt,
|
||||
(SQLWCHAR*) sqlStr.c_str(),
|
||||
(SQLINTEGER) sqlStr.size());
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetConnectAttr(SQLHDBC hdbc,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValue))
|
||||
{
|
||||
std::wstring str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValue, str);
|
||||
|
||||
return SQLSetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLINTEGER) str.size() * sizeof(std::wstring::value_type));
|
||||
}
|
||||
|
||||
return SQLSetConnectAttrW(hdbc,
|
||||
fAttribute,
|
||||
rgbValue,
|
||||
cbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetCursorName(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCursor,
|
||||
SQLSMALLINT cbCursor)
|
||||
{
|
||||
throw NotImplementedException("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetStmtAttr(SQLHSTMT hstmt,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
std::wstring str;
|
||||
makeUTF16((SQLCHAR*) rgbValue, cbValueMax, str);
|
||||
|
||||
return SQLSetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
(SQLPOINTER) str.c_str(),
|
||||
(SQLINTEGER) str.size());
|
||||
}
|
||||
|
||||
return SQLSetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
rgbValue,
|
||||
cbValueMax);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetStmtAttr(SQLHSTMT hstmt,
|
||||
SQLINTEGER fAttribute,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLINTEGER cbValueMax,
|
||||
SQLINTEGER* pcbValue)
|
||||
{
|
||||
if (isString(rgbValue, cbValueMax))
|
||||
{
|
||||
Buffer<wchar_t> buffer(stringLength(rgbValue, cbValueMax));
|
||||
|
||||
return SQLGetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
(SQLPOINTER) buffer.begin(),
|
||||
(SQLINTEGER) buffer.sizeBytes(),
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
return SQLGetStmtAttrW(hstmt,
|
||||
fAttribute,
|
||||
rgbValue,
|
||||
cbValueMax,
|
||||
pcbValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColumns(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetConnectOption(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fOption,
|
||||
SQLPOINTER pvParam)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetInfo(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fInfoType,
|
||||
SQLPOINTER rgbInfoValue,
|
||||
SQLSMALLINT cbInfoValueMax,
|
||||
SQLSMALLINT* pcbInfoValue)
|
||||
{
|
||||
if (cbInfoValueMax)
|
||||
{
|
||||
Buffer<wchar_t> buffer(cbInfoValueMax);
|
||||
|
||||
SQLRETURN rc = SQLGetInfoW(hdbc,
|
||||
fInfoType,
|
||||
(SQLPOINTER) buffer.begin(),
|
||||
(SQLSMALLINT) buffer.sizeBytes(),
|
||||
pcbInfoValue);
|
||||
|
||||
makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SQLGetInfoW(hdbc,
|
||||
fInfoType,
|
||||
rgbInfoValue,
|
||||
cbInfoValueMax,
|
||||
pcbInfoValue);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType)
|
||||
{
|
||||
return SQLGetTypeInfoW(StatementHandle, DataType);
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSetConnectOption(SQLHDBC hdbc,
|
||||
SQLUSMALLINT fOption,
|
||||
SQLULEN vParam)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLSpecialColumns(SQLHSTMT hstmt,
|
||||
SQLUSMALLINT fColType,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLUSMALLINT fScope,
|
||||
SQLUSMALLINT fNullable)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLStatistics(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLUSMALLINT fUnique,
|
||||
SQLUSMALLINT fAccuracy)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLTables(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szTableType,
|
||||
SQLSMALLINT cbTableType)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDataSources(SQLHENV henv,
|
||||
SQLUSMALLINT fDirection,
|
||||
SQLCHAR* szDSN,
|
||||
SQLSMALLINT cbDSNMax,
|
||||
SQLSMALLINT* pcbDSN,
|
||||
SQLCHAR* szDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT* pcbDesc)
|
||||
{
|
||||
Buffer<wchar_t> bufDSN(cbDSNMax);
|
||||
Buffer<wchar_t> bufDesc(cbDescMax);
|
||||
|
||||
SQLRETURN rc = SQLDataSourcesW(henv,
|
||||
fDirection,
|
||||
bufDSN.begin(),
|
||||
(SQLSMALLINT) bufDSN.size(),
|
||||
pcbDSN,
|
||||
bufDesc.begin(),
|
||||
(SQLSMALLINT) bufDesc.size(),
|
||||
pcbDesc);
|
||||
|
||||
makeUTF8(bufDSN, *pcbDSN * sizeof(wchar_t), szDSN, cbDSNMax);
|
||||
makeUTF8(bufDesc, *pcbDesc * sizeof(wchar_t), szDesc, cbDescMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDriverConnect(SQLHDBC hdbc,
|
||||
SQLHWND hwnd,
|
||||
SQLCHAR* szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLCHAR* szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT* pcbConnStrOut,
|
||||
SQLUSMALLINT fDriverCompletion)
|
||||
{
|
||||
std::wstring connStrIn;
|
||||
int len = cbConnStrIn;
|
||||
if (SQL_NTS == len)
|
||||
len = (int) std::strlen((const char*) szConnStrIn);
|
||||
|
||||
Poco::UnicodeConverter::toUTF16((const char *) szConnStrIn, len, connStrIn);
|
||||
|
||||
Buffer<wchar_t> bufOut(cbConnStrOutMax);
|
||||
SQLRETURN rc = SQLDriverConnectW(hdbc,
|
||||
hwnd,
|
||||
(SQLWCHAR*) connStrIn.c_str(),
|
||||
(SQLSMALLINT) connStrIn.size(),
|
||||
bufOut.begin(),
|
||||
(SQLSMALLINT) bufOut.size(),
|
||||
pcbConnStrOut,
|
||||
fDriverCompletion);
|
||||
|
||||
if (!Utility::isError(rc))
|
||||
makeUTF8(bufOut, *pcbConnStrOut * sizeof(wchar_t), szConnStrOut, cbConnStrOutMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLBrowseConnect(SQLHDBC hdbc,
|
||||
SQLCHAR* szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLCHAR* szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT* pcbConnStrOut)
|
||||
{
|
||||
std::wstring str;
|
||||
makeUTF16(szConnStrIn, cbConnStrIn, str);
|
||||
|
||||
Buffer<wchar_t> bufConnStrOut(cbConnStrOutMax);
|
||||
|
||||
SQLRETURN rc = SQLBrowseConnectW(hdbc,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLSMALLINT) str.size(),
|
||||
bufConnStrOut.begin(),
|
||||
(SQLSMALLINT) bufConnStrOut.size(),
|
||||
pcbConnStrOut);
|
||||
|
||||
makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(wchar_t), szConnStrOut, cbConnStrOutMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLColumnPrivileges(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLForeignKeys(SQLHSTMT hstmt,
|
||||
SQLCHAR* szPkCatalogName,
|
||||
SQLSMALLINT cbPkCatalogName,
|
||||
SQLCHAR* szPkSchemaName,
|
||||
SQLSMALLINT cbPkSchemaName,
|
||||
SQLCHAR* szPkTableName,
|
||||
SQLSMALLINT cbPkTableName,
|
||||
SQLCHAR* szFkCatalogName,
|
||||
SQLSMALLINT cbFkCatalogName,
|
||||
SQLCHAR* szFkSchemaName,
|
||||
SQLSMALLINT cbFkSchemaName,
|
||||
SQLCHAR* szFkTableName,
|
||||
SQLSMALLINT cbFkTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLNativeSql(SQLHDBC hdbc,
|
||||
SQLCHAR* szSqlStrIn,
|
||||
SQLINTEGER cbSqlStrIn,
|
||||
SQLCHAR* szSqlStr,
|
||||
SQLINTEGER cbSqlStrMax,
|
||||
SQLINTEGER* pcbSqlStr)
|
||||
{
|
||||
std::wstring str;
|
||||
makeUTF16(szSqlStrIn, cbSqlStrIn, str);
|
||||
|
||||
Buffer<wchar_t> bufSQLOut(cbSqlStrMax);
|
||||
|
||||
SQLRETURN rc = SQLNativeSqlW(hdbc,
|
||||
(SQLWCHAR*) str.c_str(),
|
||||
(SQLINTEGER) str.size(),
|
||||
bufSQLOut.begin(),
|
||||
(SQLINTEGER) bufSQLOut.size(),
|
||||
pcbSqlStr);
|
||||
|
||||
makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(wchar_t), szSqlStr, cbSqlStrMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLPrimaryKeys(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLProcedureColumns(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szProcName,
|
||||
SQLSMALLINT cbProcName,
|
||||
SQLCHAR* szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLProcedures(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szProcName,
|
||||
SQLSMALLINT cbProcName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLTablePrivileges(SQLHSTMT hstmt,
|
||||
SQLCHAR* szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLCHAR* szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLCHAR* szTableName,
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
throw NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
SQLRETURN SQLDrivers(SQLHENV henv,
|
||||
SQLUSMALLINT fDirection,
|
||||
SQLCHAR* szDriverDesc,
|
||||
SQLSMALLINT cbDriverDescMax,
|
||||
SQLSMALLINT* pcbDriverDesc,
|
||||
SQLCHAR* szDriverAttributes,
|
||||
SQLSMALLINT cbDrvrAttrMax,
|
||||
SQLSMALLINT* pcbDrvrAttr)
|
||||
{
|
||||
Buffer<wchar_t> bufDriverDesc(cbDriverDescMax);
|
||||
Buffer<wchar_t> bufDriverAttr(cbDrvrAttrMax);
|
||||
|
||||
SQLRETURN rc = SQLDriversW(henv,
|
||||
fDirection,
|
||||
bufDriverDesc.begin(),
|
||||
(SQLSMALLINT) bufDriverDesc.size(),
|
||||
pcbDriverDesc,
|
||||
bufDriverAttr.begin(),
|
||||
(SQLSMALLINT) bufDriverAttr.size(),
|
||||
pcbDrvrAttr);
|
||||
|
||||
makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(wchar_t), szDriverDesc, cbDriverDescMax);
|
||||
makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(wchar_t), szDriverAttributes, cbDrvrAttrMax);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// Utility.cpp
|
||||
//
|
||||
// Library: Data/ODBC
|
||||
// Package: ODBC
|
||||
// Module: Utility
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/Handle.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
const TypeInfo Utility::_dataTypes;
|
||||
|
||||
|
||||
Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap)
|
||||
{
|
||||
static const EnvironmentHandle henv;
|
||||
const int length = sizeof(SQLCHAR) * 512;
|
||||
|
||||
SQLCHAR desc[length];
|
||||
std::memset(desc, 0, length);
|
||||
SQLSMALLINT len1 = length;
|
||||
SQLCHAR attr[length];
|
||||
std::memset(attr, 0, length);
|
||||
SQLSMALLINT len2 = length;
|
||||
RETCODE rc = 0;
|
||||
|
||||
if (!Utility::isError(rc = SQLDrivers(henv,
|
||||
SQL_FETCH_FIRST,
|
||||
desc,
|
||||
length,
|
||||
&len1,
|
||||
attr,
|
||||
len2,
|
||||
&len2)))
|
||||
{
|
||||
do
|
||||
{
|
||||
driverMap.insert(DSNMap::value_type(std::string((char *) desc),
|
||||
std::string((char *) attr)));
|
||||
std::memset(desc, 0, length);
|
||||
std::memset(attr, 0, length);
|
||||
len2 = length;
|
||||
}while (!Utility::isError(rc = SQLDrivers(henv,
|
||||
SQL_FETCH_NEXT,
|
||||
desc,
|
||||
length,
|
||||
&len1,
|
||||
attr,
|
||||
len2,
|
||||
&len2)));
|
||||
}
|
||||
|
||||
if (SQL_NO_DATA != rc)
|
||||
throw EnvironmentException(henv);
|
||||
|
||||
return driverMap;
|
||||
}
|
||||
|
||||
|
||||
Utility::DSNMap& Utility::dataSources(Utility::DSNMap& dsnMap)
|
||||
{
|
||||
static const EnvironmentHandle henv;
|
||||
const int length = sizeof(SQLCHAR) * 512;
|
||||
const int dsnLength = sizeof(SQLCHAR) * (SQL_MAX_DSN_LENGTH + 1);
|
||||
|
||||
SQLCHAR dsn[dsnLength];
|
||||
std::memset(dsn, 0, dsnLength);
|
||||
SQLSMALLINT len1 = sizeof(SQLCHAR) * SQL_MAX_DSN_LENGTH;
|
||||
SQLCHAR desc[length];
|
||||
std::memset(desc, 0, length);
|
||||
SQLSMALLINT len2 = length;
|
||||
RETCODE rc = 0;
|
||||
|
||||
while (!Utility::isError(rc = Poco::Data::ODBC::SQLDataSources(henv,
|
||||
SQL_FETCH_NEXT,
|
||||
dsn,
|
||||
SQL_MAX_DSN_LENGTH,
|
||||
&len1,
|
||||
desc,
|
||||
len2,
|
||||
&len2)))
|
||||
{
|
||||
dsnMap.insert(DSNMap::value_type(std::string((char *) dsn), std::string((char *) desc)));
|
||||
std::memset(dsn, 0, dsnLength);
|
||||
std::memset(desc, 0, length);
|
||||
len2 = length;
|
||||
}
|
||||
|
||||
if (SQL_NO_DATA != rc)
|
||||
throw EnvironmentException(henv);
|
||||
|
||||
return dsnMap;
|
||||
}
|
||||
|
||||
|
||||
void Utility::dateTimeSync(Poco::DateTime& dt, const SQL_TIMESTAMP_STRUCT& ts)
|
||||
{
|
||||
double msec = ts.fraction/1000000;
|
||||
double usec = 1000 * (msec - std::floor(msec));
|
||||
|
||||
dt.assign(ts.year,
|
||||
ts.month,
|
||||
ts.day,
|
||||
ts.hour,
|
||||
ts.minute,
|
||||
ts.second,
|
||||
(int) std::floor(msec),
|
||||
(int) std::floor(usec));
|
||||
}
|
||||
|
||||
|
||||
void Utility::dateSync(SQL_DATE_STRUCT& ds, const Date& d)
|
||||
{
|
||||
ds.year = d.year();
|
||||
ds.month = d.month();
|
||||
ds.day = d.day();
|
||||
}
|
||||
|
||||
|
||||
void Utility::timeSync(SQL_TIME_STRUCT& ts, const Time& t)
|
||||
{
|
||||
ts.hour = t.hour();
|
||||
ts.minute = t.minute();
|
||||
ts.second = t.second();
|
||||
}
|
||||
|
||||
|
||||
void Utility::dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt)
|
||||
{
|
||||
ts.year = dt.year();
|
||||
ts.month = dt.month();
|
||||
ts.day = dt.day();
|
||||
ts.hour = dt.hour();
|
||||
ts.minute = dt.minute();
|
||||
ts.second = dt.second();
|
||||
// Fraction support is limited to milliseconds due to MS SQL Server limitation
|
||||
// see http://support.microsoft.com/kb/263872
|
||||
ts.fraction = (dt.millisecond() * 1000000);// + (dt.microsecond() * 1000);
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
Reference in New Issue
Block a user