DateTime binding (work in progress)

This commit is contained in:
Aleksandar Fabijanic 2007-06-02 01:51:38 +00:00
parent b55004813d
commit 0bde32efac
21 changed files with 505 additions and 164 deletions

View File

@ -16,7 +16,7 @@ else
$(error No ODBC library found. Please install unixODBC or iODBC and try again)
endif
objects = Binder ConnectionHandle DataTypes EnvironmentHandle \
objects = Binder ConnectionHandle TypeInfo EnvironmentHandle \
Extractor ODBCColumn ODBCException ODBCStatementImpl Parameter Preparation \
SessionImpl Connector Utility

View File

@ -158,7 +158,7 @@
RelativePath=".\include\Poco\Data\Odbc\Connector.h">
</File>
<File
RelativePath=".\include\Poco\Data\Odbc\DataTypes.h">
RelativePath=".\include\Poco\Data\Odbc\TypeInfo.h">
</File>
<File
RelativePath=".\include\Poco\Data\Odbc\Diagnostics.h">
@ -213,7 +213,7 @@
RelativePath=".\src\Connector.cpp">
</File>
<File
RelativePath=".\src\DataTypes.cpp">
RelativePath=".\src\TypeInfo.cpp">
</File>
<File
RelativePath=".\src\EnvironmentHandle.cpp">

View File

@ -221,10 +221,6 @@
RelativePath=".\include\Poco\Data\ODBC\Connector.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\DataTypes.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\Diagnostics.h"
>
@ -273,6 +269,10 @@
RelativePath=".\include\Poco\Data\ODBC\SessionImpl.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\TypeInfo.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\Utility.h"
>
@ -293,10 +293,6 @@
RelativePath=".\src\Connector.cpp"
>
</File>
<File
RelativePath=".\src\DataTypes.cpp"
>
</File>
<File
RelativePath=".\src\EnvironmentHandle.cpp"
>
@ -329,6 +325,10 @@
RelativePath=".\src\SessionImpl.cpp"
>
</File>
<File
RelativePath=".\src\TypeInfo.cpp"
>
</File>
<File
RelativePath=".\src\Utility.cpp"
>

View File

@ -47,6 +47,7 @@
#include "Poco/Data/ODBC/Parameter.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h"
#include <vector>
@ -79,7 +80,8 @@ public:
};
Binder(const StatementHandle& rStmt,
ParameterBinding dataBinding = PB_IMMEDIATE);
ParameterBinding dataBinding = PB_IMMEDIATE,
TypeInfo* pDataTypes = 0);
/// Creates the Binder.
~Binder();
@ -204,6 +206,7 @@ private:
SizeMap _dataSize;
ParameterBinding _paramBinding;
TimestampMap _timestamps;
const TypeInfo* _pTypeInfo;
};

View File

@ -41,6 +41,7 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/Data/ODBC/Binder.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCException.h"
@ -133,14 +134,21 @@ public:
const ConnectionHandle& dbc() const;
/// Returns the connection handle.
Poco::Any dataTypeInfo(const std::string& rName="");
/// Returns the data types information.
private:
void setDataTypeInfo(const std::string& rName, const Poco::Any& rValue);
/// No-op. Throws InvalidAccessException.
static const int FUNCTIONS = SQL_API_ODBC3_ALL_FUNCTIONS_SIZE;
void open();
/// Opens a connection to the Database
bool isCapable();
/// Returns true if driver supports all required functions.
bool isCapable(int function = 0);
/// Returns true if driver supports specified function, or if
/// specified function is zero, all required functions.
/// Called upon succesful connection if _enforceCapability is true.
/// This function code should be updated whenever a new
/// ODBC API call is introduced anywhere in ODBC data connector.
@ -153,6 +161,7 @@ private:
bool _enforceCapability;
bool _autoBind;
bool _autoExtract;
TypeInfo _dataTypes;
};
@ -198,6 +207,18 @@ inline Poco::Any SessionImpl::getMaxFieldSize(const std::string& rName)
}
inline void SessionImpl::setDataTypeInfo(const std::string& rName, const Poco::Any& rValue)
{
throw InvalidAccessException();
}
inline Poco::Any SessionImpl::dataTypeInfo(const std::string& rName)
{
return &_dataTypes;
}
} } } // namespace Poco::Data::ODBC

View File

@ -1,13 +1,13 @@
//
// DataTypes.h
// TypeInfo.h
//
// $Id: //poco/Main/Data/ODBC/include/Poco/Data/ODBC/DataTypes.h#3 $
// $Id: //poco/Main/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h#3 $
//
// Library: ODBC
// Package: ODBC
// Module: DataTypes
// Module: TypeInfo
//
// Definition of DataTypes.
// Definition of TypeInfo.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
@ -41,6 +41,9 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/NamedTuple.h"
#include "Poco/DynamicAny.h"
#include <vector>
#include <map>
#ifdef POCO_OS_FAMILY_WINDOWS
#include <windows.h>
@ -53,18 +56,38 @@ namespace Data {
namespace ODBC {
class ODBC_API DataTypes
class ODBC_API TypeInfo
/// C <==> SQL datatypes mapping utility class.
{
public:
typedef std::map<int, int> DataTypeMap;
typedef DataTypeMap::value_type ValueType;
typedef Poco::NamedTuple<std::string,
SQLSMALLINT,
SQLINTEGER,
std::string,
std::string,
std::string,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
std::string,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLINTEGER,
SQLSMALLINT> TypeInfoTup;
typedef std::vector<TypeInfoTup> TypeInfoVec;
DataTypes();
/// Creates the DataTypes.
explicit TypeInfo(SQLHDBC* pHDBC=0);
/// Creates the TypeInfo.
~DataTypes();
/// Destroys the DataTypes.
~TypeInfo();
/// Destroys the TypeInfo.
int cDataType(int sqlDataType) const;
/// Returns C data type corresponding to supplied SQL data type.
@ -72,12 +95,37 @@ public:
int sqlDataType(int cDataType) const;
/// Returns SQL data type corresponding to supplied C data type.
void fillTypeInfo(SQLHDBC pHDBC);
/// Fills the data type info structure for the database.
DynamicAny getInfo(SQLSMALLINT type, const std::string& param) const;
/// Returns information about specified data type.
private:
void fillCTypes();
void fillSQLTypes();
DataTypeMap _cDataTypes;
DataTypeMap _sqlDataTypes;
TypeInfoVec _typeInfo;
SQLHDBC* _pHDBC;
};
inline 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);
}
} } } // namespace Poco::Data::ODBC

View File

@ -41,9 +41,10 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/DataTypes.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/DateTime.h"
#include <sstream>
#include <map>
#ifdef POCO_OS_FAMILY_WINDOWS
#include <windows.h>
#endif
@ -104,7 +105,7 @@ public:
/// ODBC size for bool data type.
private:
static const DataTypes _dataTypes;
static const TypeInfo _dataTypes;
/// C <==> SQL data type mapping
};

View File

@ -48,9 +48,12 @@ namespace Data {
namespace ODBC {
Binder::Binder(const StatementHandle& rStmt, Binder::ParameterBinding dataBinding):
Binder::Binder(const StatementHandle& rStmt,
Binder::ParameterBinding dataBinding,
TypeInfo* pDataTypes):
_rStmt(rStmt),
_paramBinding(dataBinding)
_paramBinding(dataBinding),
_pTypeInfo(pDataTypes)
{
}
@ -146,15 +149,27 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val)
_timestamps.insert(TimestampMap::value_type(pTS, const_cast<DateTime*>(&val)));
_dataSize.insert(SizeMap::value_type((SQLPOINTER) pTS, size));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
if (_pTypeInfo)
{
try
{
colSize = _pTypeInfo->getInfo(SQL_TIMESTAMP, "COLUMN_SIZE");
decDigits = _pTypeInfo->getInfo(SQL_TIMESTAMP, "MINIMUM_SCALE");
}catch (NotFoundException&) { }
}
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
getParamType(),
SQL_C_TIMESTAMP,
SQL_TIMESTAMP,
(SQLUINTEGER) size,
0,
colSize,
decDigits,
(SQLPOINTER) pTS,
(SQLINTEGER) size,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(BLOB)");

View File

@ -1,118 +0,0 @@
//
// DataTypes.cpp
//
// $Id: //poco/Main/Data/ODBC/src/DataTypes.cpp#3 $
//
// Library: ODBC
// Package: ODBC
// Module: DataTypes
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Data/ODBC/DataTypes.h"
#include "Poco/Format.h"
#include "Poco/Exception.h"
namespace Poco {
namespace Data {
namespace ODBC {
DataTypes::DataTypes()
{
_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_SLONG));
_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));
_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));
}
DataTypes::~DataTypes()
{
}
int DataTypes::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 DataTypes::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;
}
} } } // namespace Poco::Data::ODBC

View File

@ -109,7 +109,14 @@ void ODBCStatementImpl::compileImpl()
Binder::ParameterBinding bind = session().getFeature("autoBind") ?
Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
_pBinder = new Binder(_stmt, bind);
TypeInfo* pDT = 0;
try
{
Poco::Any dti = session().getProperty("dataTypeInfo");
pDT = AnyCast<TypeInfo*>(dti);
}catch (NotSupportedException&) { }
_pBinder = new Binder(_stmt, bind, pDT);
_pExtractor = new Extractor(_stmt, *_pPreparation);
bool dataAvailable = hasData();

View File

@ -98,6 +98,11 @@ void SessionImpl::open()
throw exc;
}
_dataTypes.fillTypeInfo(_db);
addProperty("dataTypeInfo",
&SessionImpl::setDataTypeInfo,
&SessionImpl::dataTypeInfo);
addFeature("enforceCapability",
&SessionImpl::setEnforceCapability,
&SessionImpl::getEnforceCapability);
@ -189,7 +194,7 @@ void SessionImpl::close()
}
bool SessionImpl::isCapable()
bool SessionImpl::isCapable(int function)
{
SQLUSMALLINT exists[FUNCTIONS] = {0};
@ -199,7 +204,8 @@ bool SessionImpl::isCapable()
"SQLGetFunctions(SQL_API_ODBC3_ALL_FUNCTIONS)");
}
return
if (0 != function) return 0 != exists[function];
else return
exists[SQL_API_SQLBINDPARAMETER] &&
exists[SQL_API_SQLBINDCOL] &&
exists[SQL_API_SQLGETDATA] &&
@ -208,6 +214,7 @@ bool SessionImpl::isCapable()
exists[SQL_API_SQLDESCRIBECOL] &&
exists[SQL_API_SQLDESCRIBEPARAM] &&
exists[SQL_API_SQLGETINFO] &&
exists[SQL_API_SQLGETTYPEINFO] &&
exists[SQL_API_SQLGETDIAGREC] &&
exists[SQL_API_SQLGETDIAGFIELD] &&
exists[SQL_API_SQLPREPARE] &&

216
Data/ODBC/src/TypeInfo.cpp Normal file
View File

@ -0,0 +1,216 @@
//
// TypeInfo.cpp
//
// $Id: //poco/Main/Data/ODBC/src/TypeInfo.cpp#3 $
//
// Library: ODBC
// Package: ODBC
// Module: TypeInfo
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#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_SLONG));
_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_DATE, SQL_C_DATE));
_cDataTypes.insert(ValueType(SQL_TIME, SQL_C_TIME));
_cDataTypes.insert(ValueType(SQL_TIMESTAMP, SQL_C_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_DATE, SQL_DATE));
_sqlDataTypes.insert(ValueType(SQL_C_TIME, SQL_TIME));
_sqlDataTypes.insert(ValueType(SQL_C_TIMESTAMP, SQL_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()");
DataTypeMap::const_iterator it = _cDataTypes.begin();
DataTypeMap::const_iterator end = _cDataTypes.end();
for(; it != end; ++it)
{
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);
rc = SQLGetTypeInfo(hstmt, it->first);
rc = SQLFetch(hstmt);
if (SQL_SUCCEEDED(rc))
{
rc = SQLGetData(hstmt, 1, SQL_C_CHAR, typeName, sizeof(typeName), 0);
ti.set<0>(typeName);
rc = SQLGetData(hstmt, 2, SQL_C_SSHORT, &ti.get<1>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &ti.get<2>(), sizeof(SQLINTEGER), 0);
rc = SQLGetData(hstmt, 4, SQL_C_CHAR, literalPrefix, sizeof(literalPrefix), 0);
ti.set<3>(literalPrefix);
rc = SQLGetData(hstmt, 5, SQL_C_CHAR, literalSuffix, sizeof(literalSuffix), 0);
ti.set<4>(literalSuffix);
rc = SQLGetData(hstmt, 6, SQL_C_CHAR, createParams, sizeof(createParams), 0);
ti.set<5>(createParams);
rc = SQLGetData(hstmt, 7, SQL_C_SSHORT, &ti.get<6>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 8, SQL_C_SSHORT, &ti.get<7>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 9, SQL_C_SSHORT, &ti.get<8>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 10, SQL_C_SSHORT, &ti.get<9>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 11, SQL_C_SSHORT, &ti.get<10>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 12, SQL_C_SSHORT, &ti.get<11>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 13, SQL_C_CHAR, localTypeName, sizeof(localTypeName), 0);
ti.set<12>(localTypeName);
rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &ti.get<13>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 15, SQL_C_SSHORT, &ti.get<14>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 16, SQL_C_SSHORT, &ti.get<15>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 17, SQL_C_SSHORT, &ti.get<16>(), sizeof(SQLSMALLINT), 0);
rc = SQLGetData(hstmt, 18, SQL_C_SLONG, &ti.get<17>(), sizeof(SQLINTEGER), 0);
rc = SQLGetData(hstmt, 19, SQL_C_SSHORT, &ti.get<18>(), sizeof(SQLSMALLINT), 0);
_typeInfo.push_back(ti);
}
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
}
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;
}
} } } // namespace Poco::Data::ODBC

View File

@ -47,7 +47,7 @@ namespace Data {
namespace ODBC {
const DataTypes Utility::_dataTypes;
const TypeInfo Utility::_dataTypes;
const SQLSMALLINT Utility::boolDataType = (sizeof(bool) <= sizeof(char)) ? SQL_C_TINYINT :
(sizeof(bool) == sizeof(short)) ? SQL_C_SHORT : SQL_C_LONG;

View File

@ -84,7 +84,8 @@ void ODBCDB2Test::testBareboneODBC()
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth FLOAT)";
"Fifth FLOAT,"
"Sixth TIMESTAMP)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);

View File

@ -86,12 +86,26 @@ void ODBCMySQLTest::testBareboneODBC()
"Second VARCHAR(30),"
"Third VARBINARY(30),"
"Fourth INTEGER,"
"Fifth FLOAT)";
"Fifth FLOAT,"
"Sixth DATETIME)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second VARCHAR(30),"
"Third VARBINARY(30),"
"Fourth INTEGER,"
"Fifth FLOAT,"
"Sixth DATE)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
}

View File

@ -88,7 +88,21 @@ void ODBCOracleTest::testBareboneODBC()
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth NUMBER)";
"Fifth NUMBER,"
"Sixth TIMESTAMP)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth NUMBER,"
"Sixth DATE)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);

View File

@ -86,12 +86,26 @@ void ODBCPostgreSQLTest::testBareboneODBC()
"Second VARCHAR(30),"
"Third BYTEA,"
"Fourth INTEGER,"
"Fifth FLOAT)";
"Fifth FLOAT,"
"Sixth TIMESTAMP)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second VARCHAR(30),"
"Third BYTEA,"
"Fourth INTEGER,"
"Fifth FLOAT,"
"Sixth DATE)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
}

View File

@ -87,7 +87,8 @@ void ODBCSQLServerTest::testBareboneODBC()
"Second VARCHAR(30),"
"Third VARBINARY(30),"
"Fourth INTEGER,"
"Fifth FLOAT)";
"Fifth FLOAT,"
"Sixth DATETIME)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);

View File

@ -84,7 +84,34 @@ void ODBCSQLiteTest::testBareboneODBC()
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth REAL)";
"Fifth REAL,"
"Sixth TIMESTAMP)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth REAL,"
"Sixth DATETIME)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second VARCHAR(30),"
"Third BLOB,"
"Fourth INTEGER,"
"Fifth REAL,"
"Sixth DATE)";
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);

View File

@ -177,7 +177,8 @@ SQLExecutor::~SQLExecutor()
void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
const std::string& tableCreateString,
SQLExecutor::DataBinding bindMode,
SQLExecutor::DataExtraction extractMode)
SQLExecutor::DataExtraction extractMode,
bool doTime)
{
SQLRETURN rc;
SQLHENV henv = SQL_NULL_HENV;
@ -206,6 +207,25 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
, SQL_DRIVER_NOPROMPT);
assert (SQL_SUCCEEDED(rc));
// retrieve datetime type information for this DBMS
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetTypeInfo(hstmt, SQL_TIMESTAMP);
assert (SQL_SUCCEEDED(rc));
SQLINTEGER dateTimeColSize = 0;
SQLSMALLINT dateTimeDecDigits = 0;
rc = SQLFetch(hstmt);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &dateTimeColSize, sizeof(SQLINTEGER), 0);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &dateTimeDecDigits, sizeof(SQLSMALLINT), 0);
assert (SQL_SUCCEEDED(rc));
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
assert (SQL_SUCCEEDED(rc));
// Statement begin
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
@ -215,6 +235,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length());
//no return code check - ignore drop errors
// create table and go
sql = tableCreateString;
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
@ -223,7 +244,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
sql = "INSERT INTO Test VALUES (?,?,?,?,?)";
sql = "INSERT INTO Test VALUES (?,?,?,?,?,?)";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
@ -231,6 +252,16 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
std::string str[3] = { "111", "222", "333" };
int fourth = 4;
float fifth = 1.5;
SQL_TIMESTAMP_STRUCT sixth;
sixth.year = 1965;
sixth.month = 6;
sixth.day = 18;
sixth.hour = 5;
sixth.minute = 34;
sixth.second = 59;
//some DBMS do not support this (e.g. MS SQL Server), hence 0
sixth.fraction = 0;
SQLLEN li = SQL_NTS;
SQLINTEGER size = (SQLINTEGER) str[0].size();
@ -306,6 +337,18 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
0);
assert (SQL_SUCCEEDED(rc));
rc = SQLBindParameter(hstmt,
(SQLUSMALLINT) 6,
SQL_PARAM_INPUT,
SQL_C_TIMESTAMP,
SQL_TIMESTAMP,
dateTimeColSize,
dateTimeDecDigits,
(SQLPOINTER) &sixth,
0,
0);
assert (SQL_SUCCEEDED(rc));
size = 0;
if (SQLExecutor::PB_AT_EXEC == bindMode)
li = SQL_LEN_DATA_AT_EXEC((int) sizeof(int));
@ -341,9 +384,10 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
assert (SQL_SUCCEEDED(rc));
char chr[3][5] = {{ 0 }};
SQLLEN lengths[5] = { 0 };
SQLLEN lengths[6] = { 0 };
fourth = 0;
fifth = 0.0f;
memset(&sixth, 0, sizeof(sixth));
if (SQLExecutor::DE_BOUND == extractMode)
{
@ -386,6 +430,14 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLINTEGER) 0,
&lengths[4]);
assert (SQL_SUCCEEDED(rc));
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 6,
SQL_C_TIMESTAMP,
(SQLPOINTER) &sixth,
(SQLINTEGER) 0,
&lengths[5]);
assert (SQL_SUCCEEDED(rc));
}
rc = SQLExecute(hstmt);
@ -423,7 +475,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLUSMALLINT) 4,
SQL_C_SLONG,
&fourth,
4,
0,
&lengths[3]);
assert (SQL_SUCCEEDED(rc));
@ -431,9 +483,17 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLUSMALLINT) 5,
SQL_C_FLOAT,
&fifth,
5,
0,
&lengths[4]);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 6,
SQL_C_TIMESTAMP,
&sixth,
0,
&lengths[5]);
assert (SQL_SUCCEEDED(rc));
}
assert (0 == strncmp("111", chr[0], 3));
@ -441,6 +501,15 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
assert (0 == strncmp("333", chr[2], 3));
assert (4 == fourth);
assert (1.5 == fifth);
assert (1965 == sixth.year);
assert (6 == sixth.month);
assert (18 == sixth.day);
if (doTime)
{
assert (5 == sixth.hour);
assert (34 == sixth.minute);
assert (59 == sixth.second);
}
rc = SQLCloseCursor(hstmt);
assert (SQL_SUCCEEDED(rc));

View File

@ -62,7 +62,8 @@ public:
void bareboneODBCTest(const std::string& dbConnString,
const std::string& tableCreateString,
DataBinding bindMode,
DataExtraction extractMode);
DataExtraction extractMode,
bool doTime=true);
/// This function uses "bare bone" ODBC API calls (i.e. calls are not
/// "wrapped" in PocoData framework structures).
/// The purpose of the function is to verify that driver behaves