DateTime binding (only Oracle tested)

This commit is contained in:
Aleksandar Fabijanic
2007-05-31 22:40:27 +00:00
parent c1ecb3ee05
commit b55004813d
22 changed files with 410 additions and 83 deletions

View File

@@ -47,7 +47,10 @@
#include "Poco/Data/ODBC/Parameter.h" #include "Poco/Data/ODBC/Parameter.h"
#include "Poco/Data/ODBC/ODBCColumn.h" #include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Utility.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <vector>
#include <map>
#ifdef POCO_OS_FAMILY_WINDOWS #ifdef POCO_OS_FAMILY_WINDOWS
#include <windows.h> #include <windows.h>
#endif #endif
@@ -69,6 +72,12 @@ public:
PB_AT_EXEC PB_AT_EXEC
}; };
enum Direction
{
PD_IN,
PD_OUT
};
Binder(const StatementHandle& rStmt, Binder(const StatementHandle& rStmt,
ParameterBinding dataBinding = PB_IMMEDIATE); ParameterBinding dataBinding = PB_IMMEDIATE);
/// Creates the Binder. /// Creates the Binder.
@@ -118,6 +127,9 @@ public:
void bind(std::size_t pos, const Poco::Data::BLOB& val); void bind(std::size_t pos, const Poco::Data::BLOB& val);
/// Binds a BLOB. /// Binds a BLOB.
void bind(std::size_t pos, const Poco::DateTime& val);
/// Binds a DateTime.
void setDataBinding(ParameterBinding binding); void setDataBinding(ParameterBinding binding);
/// Set data binding type. /// Set data binding type.
@@ -127,7 +139,12 @@ public:
std::size_t dataSize(SQLPOINTER pAddr) const; std::size_t dataSize(SQLPOINTER pAddr) const;
/// Returns bound data size for parameter at specified position. /// Returns bound data size for parameter at specified position.
void sync(Direction direction);
/// Synchronizes non-POD parameters.
private: private:
typedef std::vector<SQLLEN*> LengthVec;
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
typedef std::map<SQLPOINTER, SQLLEN> SizeMap; typedef std::map<SQLPOINTER, SQLLEN> SizeMap;
void bind(std::size_t pos, const char* const &pVal); void bind(std::size_t pos, const char* const &pVal);
@@ -135,6 +152,8 @@ private:
/// This is a private no-op in this implementation /// This is a private no-op in this implementation
/// due to security risk. /// due to security risk.
SQLSMALLINT getParamType() const;
template <typename T> template <typename T>
void bindImpl(std::size_t pos, T& val, SQLSMALLINT cDataType) void bindImpl(std::size_t pos, T& val, SQLSMALLINT cDataType)
{ {
@@ -165,17 +184,9 @@ private:
catch (StatementException&) { } catch (StatementException&) { }
} }
bool in = isInBound();
bool out = isOutBound();
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]).");
if (Utility::isError(SQLBindParameter(_rStmt, if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1, (SQLUSMALLINT) pos + 1,
ioType, getParamType(),
cDataType, cDataType,
sqlDataType, sqlDataType,
columnSize, columnSize,
@@ -189,9 +200,10 @@ private:
} }
const StatementHandle& _rStmt; const StatementHandle& _rStmt;
std::vector<SQLLEN*> _lengthIndicator; LengthVec _lengthIndicator;
SizeMap _dataSize; SizeMap _dataSize;
ParameterBinding _paramBinding; ParameterBinding _paramBinding;
TimestampMap _timestamps;
}; };

View File

@@ -46,6 +46,8 @@
#include "Poco/Data/ODBC/ODBCColumn.h" #include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/Error.h" #include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Utility.h"
#include "Poco/DateTime.h"
#include "Poco/Any.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <map> #include <map>
#ifdef POCO_OS_FAMILY_WINDOWS #ifdef POCO_OS_FAMILY_WINDOWS
@@ -113,6 +115,9 @@ public:
bool extract(std::size_t pos, Poco::Data::BLOB& val); bool extract(std::size_t pos, Poco::Data::BLOB& val);
/// Extracts a BLOB. /// Extracts a BLOB.
bool extract(std::size_t pos, Poco::DateTime& val);
/// Extracts a DateTime.
bool extract(std::size_t pos, Poco::Any& val); bool extract(std::size_t pos, Poco::Any& val);
/// Extracts an Any. /// Extracts an Any.
@@ -124,10 +129,10 @@ public:
private: private:
static const int CHUNK_SIZE = 1024; static const int CHUNK_SIZE = 1024;
/// Amount of data retrieved in one SQLGetData() request when doing manual extract. /// Amount of data retrieved in one SQLGetData() request when doing manual extract.
static const std::string FLD_SIZE_EXCEEDED_FMT; static const std::string FLD_SIZE_EXCEEDED_FMT;
/// String format for the exception message when the field size is exceeded. /// String format for the exception message when the field size is exceeded.
void checkDataSize(std::size_t size); void checkDataSize(std::size_t size);
/// This check is only performed for bound data /// This check is only performed for bound data

View File

@@ -47,6 +47,7 @@
#include "Poco/Data/AbstractPreparation.h" #include "Poco/Data/AbstractPreparation.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
#include "Poco/Any.h" #include "Poco/Any.h"
#include "Poco/DateTime.h"
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
#include <vector> #include <vector>
#ifdef POCO_OS_FAMILY_WINDOWS #ifdef POCO_OS_FAMILY_WINDOWS
@@ -143,6 +144,9 @@ public:
void prepare(std::size_t pos, const Poco::Data::BLOB&); void prepare(std::size_t pos, const Poco::Data::BLOB&);
/// Prepares a BLOB. /// Prepares a BLOB.
void prepare(std::size_t pos, const Poco::DateTime&);
/// Prepares a DateTime.
void prepare(std::size_t pos, const Poco::Any&); void prepare(std::size_t pos, const Poco::Any&);
/// Prepares an Any. /// Prepares an Any.
@@ -202,7 +206,31 @@ private:
} }
} }
void prepareRaw(std::size_t pos, SQLSMALLINT valueType, std::size_t size); template <typename T>
void prepareRaw(std::size_t pos, SQLSMALLINT valueType, std::size_t size)
{
poco_assert (DE_BOUND == _dataExtraction);
poco_assert (pos >= 0 && pos < _pValues.size());
T* pChr = new T[size];
poco_assert_dbg (pChr);
memset(pChr, 0, size);
SharedPtr<T> sp = pChr;
_pValues[pos] = new Any(sp);
_pLengths[pos] = new SQLLEN;
*_pLengths[pos] = (SQLLEN) size;
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pChr,
(SQLINTEGER) size,
_pLengths[pos])))
{
throw StatementException(_rStmt, "SQLBindCol()");
}
}
const StatementHandle& _rStmt; const StatementHandle& _rStmt;
std::vector<Poco::Any*> _pValues; std::vector<Poco::Any*> _pValues;
@@ -289,13 +317,21 @@ inline void Preparation::prepare(std::size_t pos, char)
inline void Preparation::prepare(std::size_t pos, const std::string&) inline void Preparation::prepare(std::size_t pos, const std::string&)
{ {
prepareRaw(pos, SQL_C_CHAR, maxDataSize(pos)); prepareRaw<char>(pos, SQL_C_CHAR, maxDataSize(pos));
} }
inline void Preparation::prepare(std::size_t pos, const Poco::Data::BLOB&) inline void Preparation::prepare(std::size_t pos, const Poco::Data::BLOB&)
{ {
prepareRaw(pos, SQL_C_BINARY, maxDataSize(pos)); prepareRaw<char>(pos, SQL_C_BINARY, maxDataSize(pos));
}
inline void Preparation::prepare(std::size_t pos, const Poco::DateTime&)
{
prepareRaw<SQL_TIMESTAMP_STRUCT>(pos,
SQL_C_TYPE_TIMESTAMP,
sizeof(SQL_TIMESTAMP_STRUCT));
} }

View File

@@ -42,6 +42,7 @@
#include "Poco/Data/ODBC/ODBC.h" #include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/DataTypes.h" #include "Poco/Data/ODBC/DataTypes.h"
#include "Poco/DateTime.h"
#include <sstream> #include <sstream>
#ifdef POCO_OS_FAMILY_WINDOWS #ifdef POCO_OS_FAMILY_WINDOWS
#include <windows.h> #include <windows.h>
@@ -93,6 +94,12 @@ public:
static int sqlDataType(int cDataType); static int sqlDataType(int cDataType);
/// Returns SQL data type corresponding to supplied C data type. /// Returns SQL data type corresponding to supplied C data type.
static void dateTimeSync(Poco::DateTime& dt, const SQL_TIMESTAMP_STRUCT& ts);
/// Transfers data from ODBC SQL_TIMESTAMP_STRUCT to Poco::DateTime.
static void dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt);
/// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT.
static const SQLSMALLINT boolDataType; static const SQLSMALLINT boolDataType;
/// ODBC size for bool data type. /// ODBC size for bool data type.

View File

@@ -38,6 +38,7 @@
#include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
#include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <sql.h> #include <sql.h>
@@ -56,14 +57,21 @@ Binder::Binder(const StatementHandle& rStmt, Binder::ParameterBinding dataBindin
Binder::~Binder() Binder::~Binder()
{ {
std::vector<SQLLEN*>::iterator it = _lengthIndicator.begin(); LengthVec::iterator itLen = _lengthIndicator.begin();
std::vector<SQLLEN*>::iterator itEnd = _lengthIndicator.end(); LengthVec::iterator itLenEnd = _lengthIndicator.end();
for(; it != itEnd; ++it) delete *it; for(; itLen != itLenEnd; ++itLen) delete *itLen;
TimestampMap::iterator itTS = _timestamps.begin();
TimestampMap::iterator itTSEnd = _timestamps.end();
for(; itTS != itTSEnd; ++itTS) delete itTS->first;
} }
void Binder::bind(std::size_t pos, const std::string& val) void Binder::bind(std::size_t pos, const std::string& val)
{ {
if (isOutBound())
throw InvalidAccessException("std::string can only be in-bound");
SQLINTEGER size = (SQLINTEGER) val.size(); SQLINTEGER size = (SQLINTEGER) val.size();
SQLLEN* pLenIn = new SQLLEN; SQLLEN* pLenIn = new SQLLEN;
*pLenIn = SQL_NTS; *pLenIn = SQL_NTS;
@@ -85,38 +93,72 @@ void Binder::bind(std::size_t pos, const std::string& val)
(SQLINTEGER) size, (SQLINTEGER) size,
_lengthIndicator.back()))) _lengthIndicator.back())))
{ {
throw StatementException(_rStmt, throw StatementException(_rStmt, "SQLBindParameter(std::string)");
"SQLBindParameter()");
} }
} }
void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val) void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val)
{ {
SQLINTEGER size = (SQLINTEGER) val.size(); if (isOutBound())
SQLLEN* pLenIn = new SQLLEN; throw InvalidAccessException("BLOB can only be in-bound");
*pLenIn = size;
if (PB_AT_EXEC == _paramBinding) SQLINTEGER size = (SQLINTEGER) val.size();
*pLenIn = SQL_LEN_DATA_AT_EXEC(size); SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
_lengthIndicator.push_back(pLenIn); if (PB_AT_EXEC == _paramBinding)
_dataSize.insert(SizeMap::value_type((SQLPOINTER) val.rawContent(), size)); *pLenIn = SQL_LEN_DATA_AT_EXEC(size);
if (Utility::isError(SQLBindParameter(_rStmt, _lengthIndicator.push_back(pLenIn);
(SQLUSMALLINT) pos + 1, _dataSize.insert(SizeMap::value_type((SQLPOINTER) val.rawContent(), size));
SQL_PARAM_INPUT,
SQL_C_BINARY, if (Utility::isError(SQLBindParameter(_rStmt,
SQL_LONGVARBINARY, (SQLUSMALLINT) pos + 1,
(SQLUINTEGER) size, SQL_PARAM_INPUT,
0, SQL_C_BINARY,
(SQLPOINTER) val.rawContent(), SQL_LONGVARBINARY,
(SQLINTEGER) size, (SQLUINTEGER) size,
_lengthIndicator.back()))) 0,
{ (SQLPOINTER) val.rawContent(),
throw StatementException(_rStmt, (SQLINTEGER) size,
"SQLBindParameter()"); _lengthIndicator.back())))
} {
throw StatementException(_rStmt, "SQLBindParameter(BLOB)");
}
}
void Binder::bind(std::size_t pos, const Poco::DateTime& val)
{
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT);
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
if (PB_AT_EXEC == _paramBinding)
*pLenIn = SQL_LEN_DATA_AT_EXEC(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)));
_dataSize.insert(SizeMap::value_type((SQLPOINTER) pTS, size));
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
getParamType(),
SQL_C_TIMESTAMP,
SQL_TIMESTAMP,
(SQLUINTEGER) size,
0,
(SQLPOINTER) pTS,
(SQLINTEGER) size,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(BLOB)");
}
} }
@@ -135,4 +177,32 @@ void Binder::bind(std::size_t pos, const char* const &pVal)
} }
SQLSMALLINT Binder::getParamType() const
{
bool in = isInBound();
bool out = isOutBound();
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::sync(Binder::Direction direction)
{
TimestampMap::iterator itTS = _timestamps.begin();
TimestampMap::iterator itTSEnd = _timestamps.end();
for(; itTS != itTSEnd; ++itTS)
{
if (PD_OUT == direction) // SQL_TIMESTAMP_STRUCT => DateTime
Utility::dateTimeSync(*itTS->second, *itTS->first);
else // DateTime => SQL_TIMESTAMP_STRUCT
Utility::dateTimeSync(*itTS->first, *itTS->second);
}
}
} } } // namespace Poco::Data::ODBC } } } // namespace Poco::Data::ODBC

View File

@@ -40,7 +40,6 @@
#include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <memory>
namespace Poco { namespace Poco {
@@ -92,6 +91,18 @@ bool Extractor::extractBoundImpl<Poco::Data::BLOB>(std::size_t pos, Poco::Data::
} }
template<>
bool Extractor::extractBoundImpl<Poco::DateTime>(std::size_t pos, Poco::DateTime& val)
{
std::size_t dataSize = _rPreparation.actualDataSize(pos);
checkDataSize(dataSize);
SharedPtr<SQL_TIMESTAMP_STRUCT>& sp = RefAnyCast<SharedPtr<SQL_TIMESTAMP_STRUCT> >(_rPreparation[pos]);
Utility::dateTimeSync(val, *sp);
return true;
}
template<> template<>
bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val, SQLSMALLINT cType) bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val, SQLSMALLINT cType)
{ {
@@ -186,6 +197,33 @@ bool Extractor::extractManualImpl<Poco::Data::BLOB>(std::size_t pos,
} }
template<>
bool Extractor::extractManualImpl<Poco::DateTime>(std::size_t pos,
Poco::DateTime& val,
SQLSMALLINT cType)
{
SQLLEN len = 0;
SQL_TIMESTAMP_STRUCT ts;
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
&ts, //returned value
sizeof(ts), //buffer length
&len); //length indicator
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (SQL_NULL_DATA == len)
val.assign(0,0,0,0,0,0);
else
Utility::dateTimeSync(val, ts);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Int32& val) bool Extractor::extract(std::size_t pos, Poco::Int32& val)
{ {
if (Preparation::DE_MANUAL == _dataExtraction) if (Preparation::DE_MANUAL == _dataExtraction)
@@ -232,6 +270,15 @@ bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
} }
bool Extractor::extract(std::size_t pos, Poco::DateTime& val)
{
if (Preparation::DE_MANUAL == _dataExtraction)
return extractManualImpl(pos, val, SQL_C_TIMESTAMP);
else
return extractBoundImpl(pos, val);
}
bool Extractor::extract(std::size_t pos, Poco::Int8& val) bool Extractor::extract(std::size_t pos, Poco::Int8& val)
{ {
if (Preparation::DE_MANUAL == _dataExtraction) if (Preparation::DE_MANUAL == _dataExtraction)
@@ -358,6 +405,9 @@ bool Extractor::extract(std::size_t pos, Poco::Any& val)
case MetaColumn::FDT_BLOB: case MetaColumn::FDT_BLOB:
{ Poco::Data::BLOB b; extract(pos, b); val = b; return true; } { Poco::Data::BLOB b; extract(pos, b); val = b; return true; }
case MetaColumn::FDT_TIMESTAMP:
{ Poco::DateTime b; extract(pos, b); val = b; return true; }
default: default:
throw DataFormatException("Unsupported data type."); throw DataFormatException("Unsupported data type.");
} }

View File

@@ -125,6 +125,8 @@ void ODBCColumn::init()
case SQL_LONGVARBINARY: case SQL_LONGVARBINARY:
case -98:// IBM DB2 non-standard type case -98:// IBM DB2 non-standard type
setType(MetaColumn::FDT_BLOB); break; setType(MetaColumn::FDT_BLOB); break;
case SQL_TIMESTAMP:
setType(MetaColumn::FDT_TIMESTAMP); break;
default: default:
throw DataFormatException("Unsupported data type."); throw DataFormatException("Unsupported data type.");
} }

View File

@@ -163,6 +163,8 @@ void ODBCStatementImpl::bindImpl()
if (SQL_NEED_DATA == rc) putData(); if (SQL_NEED_DATA == rc) putData();
else checkError(rc, "SQLExecute()"); else checkError(rc, "SQLExecute()");
_pBinder->sync(Binder::PD_OUT);
} }

View File

@@ -87,32 +87,6 @@ Poco::Any& Preparation::operator [] (std::size_t pos)
} }
void Preparation::prepareRaw(std::size_t pos, SQLSMALLINT valueType, std::size_t size)
{
poco_assert (DE_BOUND == _dataExtraction);
poco_assert (pos >= 0 && pos < _pValues.size());
char* pChr = new char[size];
poco_assert_dbg (pChr);
memset(pChr, 0, size);
SharedPtr<char> sp = pChr;
_pValues[pos] = new Any(sp);
_pLengths[pos] = new SQLLEN;
*_pLengths[pos] = (SQLLEN) size;
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pChr,
(SQLINTEGER) size,
_pLengths[pos])))
{
throw StatementException(_rStmt, "SQLBindCol()");
}
}
void Preparation::prepare(std::size_t pos, const Poco::Any&) void Preparation::prepare(std::size_t pos, const Poco::Any&)
{ {
ODBCColumn col(_rStmt, pos); ODBCColumn col(_rStmt, pos);
@@ -153,16 +127,14 @@ void Preparation::prepare(std::size_t pos, const Poco::Any&)
return preparePOD<float>(pos, SQL_C_DOUBLE); return preparePOD<float>(pos, SQL_C_DOUBLE);
case MetaColumn::FDT_STRING: case MetaColumn::FDT_STRING:
return prepareRaw(pos, SQL_C_CHAR, maxDataSize(pos)); return prepareRaw<char>(pos, SQL_C_CHAR, maxDataSize(pos));
case MetaColumn::FDT_BLOB: case MetaColumn::FDT_BLOB:
return prepareRaw(pos, SQL_C_BINARY, maxDataSize(pos)); return prepareRaw<char>(pos, SQL_C_BINARY, maxDataSize(pos));
default: default:
throw DataFormatException("Unsupported data type."); throw DataFormatException("Unsupported data type.");
} }
prepareRaw(pos, SQL_C_BINARY, maxDataSize(pos));
} }

View File

@@ -38,6 +38,8 @@
#include "Poco/Data/ODBC/Handle.h" #include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
#include "Poco/DateTime.h"
#include <cmath>
namespace Poco { namespace Poco {
@@ -122,4 +124,32 @@ Utility::DSNMap& Utility::dataSources(Utility::DSNMap& dsnMap)
} }
void Utility::dateTimeSync(Poco::DateTime& dt, const SQL_TIMESTAMP_STRUCT& ts)
{
double msec = ts.fraction/1000000;
double usec = 1000 * (msec - floor(msec));
dt.assign(ts.year,
ts.month,
ts.day,
ts.hour,
ts.minute,
ts.second,
(int) floor(msec),
(int) floor(usec));
}
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();
ts.fraction = (dt.millisecond() * 1000000) + (dt.microsecond() * 1000);
}
} } } // namespace Poco::Data::ODBC } } } // namespace Poco::Data::ODBC

View File

@@ -36,6 +36,7 @@
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/Tuple.h" #include "Poco/Tuple.h"
#include "Poco/Format.h" #include "Poco/Format.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include "Poco/Data/Common.h" #include "Poco/Data/Common.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
@@ -56,6 +57,7 @@ using Poco::Data::ODBC::StatementException;
using Poco::Data::ODBC::StatementDiagnostics; using Poco::Data::ODBC::StatementDiagnostics;
using Poco::format; using Poco::format;
using Poco::Tuple; using Poco::Tuple;
using Poco::DateTime;
using Poco::NotFoundException; using Poco::NotFoundException;
@@ -752,6 +754,21 @@ void ODBCOracleTest::testBLOBStmt()
} }
void ODBCOracleTest::testDateTime()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonDateTimeTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->dateTime();
i += 2;
}
}
void ODBCOracleTest::testFloat() void ODBCOracleTest::testFloat()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@@ -884,6 +901,19 @@ void ODBCOracleTest::testStoredProcedure()
k += 2; k += 2;
} }
//DateTime io params only for autoBind for now
_pSession->setFeature("autoBind", true);
*_pSession << "CREATE OR REPLACE "
"PROCEDURE storedProcedure(ioParam IN OUT DATE) IS "
" BEGIN ioParam := ioParam + 1; "
" END storedProcedure;" , now;
DateTime dt(1965, 6, 18, 5, 35, 1);
*_pSession << "{call storedProcedure(?)}", io(dt), now;
assert(19 == dt.day());
*_pSession << "DROP PROCEDURE storedProcedure;", now;
} }
@@ -951,7 +981,7 @@ void ODBCOracleTest::testStoredFunction()
assert(3 == result); assert(3 == result);
*_pSession << "DROP FUNCTION storedFunction;", now; *_pSession << "DROP FUNCTION storedFunction;", now;
k = k + 2; k += 2;
} }
} }
@@ -999,6 +1029,15 @@ void ODBCOracleTest::recreatePersonBLOBTable()
} }
void ODBCOracleTest::recreatePersonDateTimeTable()
{
dropTable("Person");
try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATE)", now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); }
}
void ODBCOracleTest::recreateIntsTable() void ODBCOracleTest::recreateIntsTable()
{ {
dropTable("Strings"); dropTable("Strings");
@@ -1201,6 +1240,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testEmptyDB); CppUnit_addTest(pSuite, ODBCOracleTest, testEmptyDB);
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOB); CppUnit_addTest(pSuite, ODBCOracleTest, testBLOB);
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOBStmt); CppUnit_addTest(pSuite, ODBCOracleTest, testBLOBStmt);
CppUnit_addTest(pSuite, ODBCOracleTest, testDateTime);
CppUnit_addTest(pSuite, ODBCOracleTest, testFloat); CppUnit_addTest(pSuite, ODBCOracleTest, testFloat);
CppUnit_addTest(pSuite, ODBCOracleTest, testDouble); CppUnit_addTest(pSuite, ODBCOracleTest, testDouble);
CppUnit_addTest(pSuite, ODBCOracleTest, testTuple); CppUnit_addTest(pSuite, ODBCOracleTest, testTuple);

View File

@@ -109,6 +109,7 @@ public:
void testBLOB(); void testBLOB();
void testBLOBStmt(); void testBLOBStmt();
void testDateTime();
void testFloat(); void testFloat();
void testDouble(); void testDouble();
@@ -130,6 +131,7 @@ private:
void dropTable(const std::string& tableName); void dropTable(const std::string& tableName);
void recreatePersonTable(); void recreatePersonTable();
void recreatePersonBLOBTable(); void recreatePersonBLOBTable();
void recreatePersonDateTimeTable();
void recreateStringsTable(); void recreateStringsTable();
void recreateIntsTable(); void recreateIntsTable();
void recreateFloatsTable(); void recreateFloatsTable();

View File

@@ -756,6 +756,21 @@ void ODBCSQLServerTest::testBLOBStmt()
} }
void ODBCSQLServerTest::testDateTime()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonDateTimeTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->dateTime();
i += 2;
}
}
void ODBCSQLServerTest::testFloat() void ODBCSQLServerTest::testFloat()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@@ -868,6 +883,7 @@ void ODBCSQLServerTest::testStoredProcedure()
"SET @outParam = @inParam*@inParam " "SET @outParam = @inParam*@inParam "
, now; , now;
fail("TODO");
i = 2; i = 2;
int j = 0; int j = 0;
/*not working */ /*not working */
@@ -1010,6 +1026,15 @@ void ODBCSQLServerTest::recreatePersonBLOBTable()
} }
void ODBCSQLServerTest::recreatePersonDateTimeTable()
{
dropObject("TABLE", "Person");
try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); }
}
void ODBCSQLServerTest::recreateIntsTable() void ODBCSQLServerTest::recreateIntsTable()
{ {
dropObject("TABLE", "Strings"); dropObject("TABLE", "Strings");
@@ -1202,6 +1227,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testEmptyDB); CppUnit_addTest(pSuite, ODBCSQLServerTest, testEmptyDB);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOB); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOB);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOBStmt); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOBStmt);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDateTime);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testFloat); CppUnit_addTest(pSuite, ODBCSQLServerTest, testFloat);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDouble); CppUnit_addTest(pSuite, ODBCSQLServerTest, testDouble);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple); CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple);

View File

@@ -111,6 +111,8 @@ public:
void testBLOB(); void testBLOB();
void testBLOBStmt(); void testBLOBStmt();
void testDateTime();
void testFloat(); void testFloat();
void testDouble(); void testDouble();
@@ -132,6 +134,7 @@ private:
void dropObject(const std::string& type, const std::string& name); void dropObject(const std::string& type, const std::string& name);
void recreatePersonTable(); void recreatePersonTable();
void recreatePersonBLOBTable(); void recreatePersonBLOBTable();
void recreatePersonDateTimeTable();
void recreateStringsTable(); void recreateStringsTable();
void recreateIntsTable(); void recreateIntsTable();
void recreateFloatsTable(); void recreateFloatsTable();

View File

@@ -36,6 +36,7 @@
#include "Poco/Format.h" #include "Poco/Format.h"
#include "Poco/Tuple.h" #include "Poco/Tuple.h"
#include "Poco/Any.h" #include "Poco/Any.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include "Poco/Data/Common.h" #include "Poco/Data/Common.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
@@ -62,6 +63,7 @@ using Poco::format;
using Poco::Tuple; using Poco::Tuple;
using Poco::Any; using Poco::Any;
using Poco::AnyCast; using Poco::AnyCast;
using Poco::DateTime;
using Poco::NotFoundException; using Poco::NotFoundException;
using Poco::InvalidAccessException; using Poco::InvalidAccessException;
using Poco::BadCastException; using Poco::BadCastException;
@@ -1725,6 +1727,32 @@ void SQLExecutor::blobStmt()
poco_assert (res == blob); poco_assert (res == blob);
} }
void SQLExecutor::dateTime()
{
std::string funct = "dateTime()";
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
DateTime born(1965, 6, 18, 5, 35, 1);
int count = 0;
try { *_pSession << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(born), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
try { *_pSession << "SELECT COUNT(*) FROM PERSON", into(count), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assert (count == 1);
DateTime res;
try { *_pSession << "SELECT Born FROM Person", into(res), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assert (res == born);
}
void SQLExecutor::tuples() void SQLExecutor::tuples()
{ {
typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType; typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType;

View File

@@ -120,6 +120,7 @@ public:
void blob(int bigSize = 1024); void blob(int bigSize = 1024);
void blobStmt(); void blobStmt();
void dateTime();
void floats(); void floats();
void doubles(); void doubles();
void tuples(); void tuples();

View File

@@ -45,8 +45,10 @@
namespace Poco { namespace Poco {
namespace Data {
class DateTime;
namespace Data {
class BLOB; class BLOB;
@@ -107,6 +109,9 @@ public:
virtual void bind(std::size_t pos, const BLOB& val) = 0; virtual void bind(std::size_t pos, const BLOB& val) = 0;
/// Binds a BLOB. /// Binds a BLOB.
virtual void bind(std::size_t pos, const DateTime& val) = 0;
/// Binds a DateTime.
bool isInBound() const; bool isInBound() const;
/// Returns true if binder is in-bound. /// Returns true if binder is in-bound.

View File

@@ -45,8 +45,10 @@
namespace Poco { namespace Poco {
namespace Data {
class DateTime;
namespace Data {
class BLOB; class BLOB;
@@ -103,6 +105,9 @@ public:
virtual bool extract(std::size_t pos, BLOB& val) = 0; virtual bool extract(std::size_t pos, BLOB& val) = 0;
/// Extracts a BLOB. Returns false if null was received. /// Extracts a BLOB. Returns false if null was received.
virtual bool extract(std::size_t pos, DateTime& val) = 0;
/// Extracts a DateTime. Returns false if null was received.
}; };

View File

@@ -46,8 +46,11 @@
namespace Poco { namespace Poco {
namespace Data {
class DateTime;
class Any;
namespace Data {
class BLOB; class BLOB;
@@ -106,6 +109,12 @@ public:
virtual void prepare(std::size_t pos, const BLOB&) = 0; virtual void prepare(std::size_t pos, const BLOB&) = 0;
/// Prepares a BLOB. /// Prepares a BLOB.
virtual void prepare(std::size_t pos, const DateTime&) = 0;
/// Prepares a DateTime.
virtual void prepare(std::size_t pos, const Any&) = 0;
/// Prepares an Any.
}; };

View File

@@ -54,7 +54,7 @@ namespace Data {
template <class T, class C = std::vector<T> > template <class T, class C = std::vector<T> >
class Column class Column
/// Column class is column data container. /// Column class is column data container.
/// Data (a pointer to vector of contained values) is assigned to the class /// Data (a pointer to container) is assigned to the class
/// through either constructor or set() member function. /// through either constructor or set() member function.
/// Construction with null pointer is not allowed. /// Construction with null pointer is not allowed.
/// This class owns the data assigned to it and deletes the storage on destruction. /// This class owns the data assigned to it and deletes the storage on destruction.
@@ -62,6 +62,7 @@ class Column
public: public:
typedef C Container; typedef C Container;
typedef typename Container::const_iterator Iterator; typedef typename Container::const_iterator Iterator;
typedef typename Container::const_reverse_iterator RIterator;
typedef typename Container::size_type Size; typedef typename Container::size_type Size;
Column(const MetaColumn& metaColumn, C* pData): _metaColumn(metaColumn), _pData(pData) Column(const MetaColumn& metaColumn, C* pData): _metaColumn(metaColumn), _pData(pData)
@@ -190,6 +191,7 @@ class Column<T, std::list<T> >
public: public:
typedef std::list<T> List; typedef std::list<T> List;
typedef typename List::const_iterator Iterator; typedef typename List::const_iterator Iterator;
typedef typename List::const_reverse_iterator RIterator;
typedef typename List::size_type Size; typedef typename List::size_type Size;
Column(const MetaColumn& metaColumn, std::list<T>* pData): _metaColumn(metaColumn), _pData(pData) Column(const MetaColumn& metaColumn, std::list<T>* pData): _metaColumn(metaColumn), _pData(pData)
@@ -231,11 +233,30 @@ public:
const T& value(std::size_t row) const const T& value(std::size_t row) const
/// Returns the field value in specified row. /// Returns the field value in specified row.
/// This is the std::list specialization and std::list
/// is not the optimal solution for cases where random
/// access is needed.
/// However, to allow for compatibility with other
/// containers, this functionality is provided here.
/// To alleviate the problem, an effort is made
/// to start iteration from beginning or end,
/// depending on the position requested.
{ {
List::const_iterator it = _pData->begin(); if (row <= (std::size_t) (_pData->size() / 2))
List::const_iterator end = _pData->end(); {
for (int i = 0; it != end; ++it, ++i) Iterator it = _pData->begin();
if (i == row) return *it; Iterator end = _pData->end();
for (int i = 0; it != end; ++it, ++i)
if (i == row) return *it;
}
else
{
row = _pData->size() - row;
RIterator it = _pData->rbegin();
RIterator end = _pData->rend();
for (int i = 1; it != end; ++it, ++i)
if (i == row) return *it;
}
throw RangeException("Invalid row number."); throw RangeException("Invalid row number.");
} }

View File

@@ -67,6 +67,7 @@ public:
FDT_DOUBLE, FDT_DOUBLE,
FDT_STRING, FDT_STRING,
FDT_BLOB, FDT_BLOB,
FDT_TIMESTAMP,
FDT_UNKNOWN FDT_UNKNOWN
}; };

View File

@@ -255,11 +255,11 @@ private:
Limit _extrLimit; Limit _extrLimit;
Poco::UInt32 _lowerLimit; Poco::UInt32 _lowerLimit;
int _columnsExtracted; int _columnsExtracted;
SessionImpl& _rSession;
Storage _storage;
std::ostringstream _ostr; std::ostringstream _ostr;
AbstractBindingVec _bindings; AbstractBindingVec _bindings;
AbstractExtractionVec _extractors; AbstractExtractionVec _extractors;
SessionImpl& _rSession;
Storage _storage;
friend class Statement; friend class Statement;
}; };