mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-18 03:29:47 +02:00
DateTime binding (only Oracle tested)
This commit is contained in:
@@ -47,7 +47,10 @@
|
||||
#include "Poco/Data/ODBC/Parameter.h"
|
||||
#include "Poco/Data/ODBC/ODBCColumn.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@@ -69,6 +72,12 @@ public:
|
||||
PB_AT_EXEC
|
||||
};
|
||||
|
||||
enum Direction
|
||||
{
|
||||
PD_IN,
|
||||
PD_OUT
|
||||
};
|
||||
|
||||
Binder(const StatementHandle& rStmt,
|
||||
ParameterBinding dataBinding = PB_IMMEDIATE);
|
||||
/// Creates the Binder.
|
||||
@@ -118,6 +127,9 @@ public:
|
||||
void bind(std::size_t pos, const Poco::Data::BLOB& val);
|
||||
/// Binds a BLOB.
|
||||
|
||||
void bind(std::size_t pos, const Poco::DateTime& val);
|
||||
/// Binds a DateTime.
|
||||
|
||||
void setDataBinding(ParameterBinding binding);
|
||||
/// Set data binding type.
|
||||
|
||||
@@ -127,7 +139,12 @@ public:
|
||||
std::size_t dataSize(SQLPOINTER pAddr) const;
|
||||
/// Returns bound data size for parameter at specified position.
|
||||
|
||||
void sync(Direction direction);
|
||||
/// Synchronizes non-POD parameters.
|
||||
|
||||
private:
|
||||
typedef std::vector<SQLLEN*> LengthVec;
|
||||
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
||||
typedef std::map<SQLPOINTER, SQLLEN> SizeMap;
|
||||
|
||||
void bind(std::size_t pos, const char* const &pVal);
|
||||
@@ -135,6 +152,8 @@ private:
|
||||
/// This is a private no-op in this implementation
|
||||
/// due to security risk.
|
||||
|
||||
SQLSMALLINT getParamType() const;
|
||||
|
||||
template <typename T>
|
||||
void bindImpl(std::size_t pos, T& val, SQLSMALLINT cDataType)
|
||||
{
|
||||
@@ -165,17 +184,9 @@ private:
|
||||
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,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
ioType,
|
||||
getParamType(),
|
||||
cDataType,
|
||||
sqlDataType,
|
||||
columnSize,
|
||||
@@ -189,9 +200,10 @@ private:
|
||||
}
|
||||
|
||||
const StatementHandle& _rStmt;
|
||||
std::vector<SQLLEN*> _lengthIndicator;
|
||||
LengthVec _lengthIndicator;
|
||||
SizeMap _dataSize;
|
||||
ParameterBinding _paramBinding;
|
||||
TimestampMap _timestamps;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -46,6 +46,8 @@
|
||||
#include "Poco/Data/ODBC/ODBCColumn.h"
|
||||
#include "Poco/Data/ODBC/Error.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <map>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
@@ -112,6 +114,9 @@ public:
|
||||
|
||||
bool extract(std::size_t pos, Poco::Data::BLOB& val);
|
||||
/// Extracts a BLOB.
|
||||
|
||||
bool extract(std::size_t pos, Poco::DateTime& val);
|
||||
/// Extracts a DateTime.
|
||||
|
||||
bool extract(std::size_t pos, Poco::Any& val);
|
||||
/// Extracts an Any.
|
||||
@@ -124,10 +129,10 @@ public:
|
||||
|
||||
private:
|
||||
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;
|
||||
/// 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);
|
||||
/// This check is only performed for bound data
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "Poco/Data/AbstractPreparation.h"
|
||||
#include "Poco/Data/BLOB.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <vector>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
@@ -143,6 +144,9 @@ public:
|
||||
void prepare(std::size_t pos, const Poco::Data::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&);
|
||||
/// 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;
|
||||
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&)
|
||||
{
|
||||
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&)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -42,6 +42,7 @@
|
||||
|
||||
#include "Poco/Data/ODBC/ODBC.h"
|
||||
#include "Poco/Data/ODBC/DataTypes.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include <sstream>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#include <windows.h>
|
||||
@@ -93,6 +94,12 @@ public:
|
||||
static int sqlDataType(int cDataType);
|
||||
/// 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;
|
||||
/// ODBC size for bool data type.
|
||||
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/BLOB.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <sql.h>
|
||||
|
||||
@@ -56,14 +57,21 @@ Binder::Binder(const StatementHandle& rStmt, Binder::ParameterBinding dataBindin
|
||||
|
||||
Binder::~Binder()
|
||||
{
|
||||
std::vector<SQLLEN*>::iterator it = _lengthIndicator.begin();
|
||||
std::vector<SQLLEN*>::iterator itEnd = _lengthIndicator.end();
|
||||
for(; it != itEnd; ++it) delete *it;
|
||||
LengthVec::iterator itLen = _lengthIndicator.begin();
|
||||
LengthVec::iterator itLenEnd = _lengthIndicator.end();
|
||||
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)
|
||||
{
|
||||
if (isOutBound())
|
||||
throw InvalidAccessException("std::string can only be in-bound");
|
||||
|
||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = SQL_NTS;
|
||||
@@ -85,38 +93,72 @@ void Binder::bind(std::size_t pos, const std::string& val)
|
||||
(SQLINTEGER) size,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt,
|
||||
"SQLBindParameter()");
|
||||
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val)
|
||||
{
|
||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = size;
|
||||
if (isOutBound())
|
||||
throw InvalidAccessException("BLOB can only be in-bound");
|
||||
|
||||
if (PB_AT_EXEC == _paramBinding)
|
||||
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
|
||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*pLenIn = size;
|
||||
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
_dataSize.insert(SizeMap::value_type((SQLPOINTER) val.rawContent(), size));
|
||||
if (PB_AT_EXEC == _paramBinding)
|
||||
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
SQL_PARAM_INPUT,
|
||||
SQL_C_BINARY,
|
||||
SQL_LONGVARBINARY,
|
||||
(SQLUINTEGER) size,
|
||||
0,
|
||||
(SQLPOINTER) val.rawContent(),
|
||||
(SQLINTEGER) size,
|
||||
_lengthIndicator.back())))
|
||||
{
|
||||
throw StatementException(_rStmt,
|
||||
"SQLBindParameter()");
|
||||
}
|
||||
_lengthIndicator.push_back(pLenIn);
|
||||
_dataSize.insert(SizeMap::value_type((SQLPOINTER) val.rawContent(), size));
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
SQL_PARAM_INPUT,
|
||||
SQL_C_BINARY,
|
||||
SQL_LONGVARBINARY,
|
||||
(SQLUINTEGER) size,
|
||||
0,
|
||||
(SQLPOINTER) val.rawContent(),
|
||||
(SQLINTEGER) size,
|
||||
_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
|
||||
|
@@ -40,7 +40,6 @@
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/BLOB.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
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<>
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (Preparation::DE_MANUAL == _dataExtraction)
|
||||
@@ -358,6 +405,9 @@ bool Extractor::extract(std::size_t pos, Poco::Any& val)
|
||||
case MetaColumn::FDT_BLOB:
|
||||
{ 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:
|
||||
throw DataFormatException("Unsupported data type.");
|
||||
}
|
||||
|
@@ -125,6 +125,8 @@ void ODBCColumn::init()
|
||||
case SQL_LONGVARBINARY:
|
||||
case -98:// IBM DB2 non-standard type
|
||||
setType(MetaColumn::FDT_BLOB); break;
|
||||
case SQL_TIMESTAMP:
|
||||
setType(MetaColumn::FDT_TIMESTAMP); break;
|
||||
default:
|
||||
throw DataFormatException("Unsupported data type.");
|
||||
}
|
||||
|
@@ -163,6 +163,8 @@ void ODBCStatementImpl::bindImpl()
|
||||
|
||||
if (SQL_NEED_DATA == rc) putData();
|
||||
else checkError(rc, "SQLExecute()");
|
||||
|
||||
_pBinder->sync(Binder::PD_OUT);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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&)
|
||||
{
|
||||
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);
|
||||
|
||||
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:
|
||||
return prepareRaw(pos, SQL_C_BINARY, maxDataSize(pos));
|
||||
return prepareRaw<char>(pos, SQL_C_BINARY, maxDataSize(pos));
|
||||
|
||||
default:
|
||||
throw DataFormatException("Unsupported data type.");
|
||||
}
|
||||
|
||||
prepareRaw(pos, SQL_C_BINARY, maxDataSize(pos));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -38,6 +38,8 @@
|
||||
#include "Poco/Data/ODBC/Handle.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include <cmath>
|
||||
|
||||
|
||||
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
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Tuple.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Data/Common.h"
|
||||
#include "Poco/Data/BLOB.h"
|
||||
@@ -56,6 +57,7 @@ using Poco::Data::ODBC::StatementException;
|
||||
using Poco::Data::ODBC::StatementDiagnostics;
|
||||
using Poco::format;
|
||||
using Poco::Tuple;
|
||||
using Poco::DateTime;
|
||||
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()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@@ -884,6 +901,19 @@ void ODBCOracleTest::testStoredProcedure()
|
||||
|
||||
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);
|
||||
*_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()
|
||||
{
|
||||
dropTable("Strings");
|
||||
@@ -1201,6 +1240,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testDateTime);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testFloat);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testDouble);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testTuple);
|
||||
|
@@ -109,6 +109,7 @@ public:
|
||||
void testBLOB();
|
||||
void testBLOBStmt();
|
||||
|
||||
void testDateTime();
|
||||
void testFloat();
|
||||
void testDouble();
|
||||
|
||||
@@ -130,6 +131,7 @@ private:
|
||||
void dropTable(const std::string& tableName);
|
||||
void recreatePersonTable();
|
||||
void recreatePersonBLOBTable();
|
||||
void recreatePersonDateTimeTable();
|
||||
void recreateStringsTable();
|
||||
void recreateIntsTable();
|
||||
void recreateFloatsTable();
|
||||
|
@@ -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()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@@ -868,6 +883,7 @@ void ODBCSQLServerTest::testStoredProcedure()
|
||||
"SET @outParam = @inParam*@inParam "
|
||||
, now;
|
||||
|
||||
fail("TODO");
|
||||
i = 2;
|
||||
int j = 0;
|
||||
/*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()
|
||||
{
|
||||
dropObject("TABLE", "Strings");
|
||||
@@ -1202,6 +1227,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDateTime);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testFloat);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDouble);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple);
|
||||
|
@@ -111,6 +111,8 @@ public:
|
||||
void testBLOB();
|
||||
void testBLOBStmt();
|
||||
|
||||
void testDateTime();
|
||||
|
||||
void testFloat();
|
||||
void testDouble();
|
||||
|
||||
@@ -132,6 +134,7 @@ private:
|
||||
void dropObject(const std::string& type, const std::string& name);
|
||||
void recreatePersonTable();
|
||||
void recreatePersonBLOBTable();
|
||||
void recreatePersonDateTimeTable();
|
||||
void recreateStringsTable();
|
||||
void recreateIntsTable();
|
||||
void recreateFloatsTable();
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/Tuple.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Data/Common.h"
|
||||
#include "Poco/Data/BLOB.h"
|
||||
@@ -62,6 +63,7 @@ using Poco::format;
|
||||
using Poco::Tuple;
|
||||
using Poco::Any;
|
||||
using Poco::AnyCast;
|
||||
using Poco::DateTime;
|
||||
using Poco::NotFoundException;
|
||||
using Poco::InvalidAccessException;
|
||||
using Poco::BadCastException;
|
||||
@@ -1725,6 +1727,32 @@ void SQLExecutor::blobStmt()
|
||||
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()
|
||||
{
|
||||
typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType;
|
||||
|
@@ -120,6 +120,7 @@ public:
|
||||
void blob(int bigSize = 1024);
|
||||
void blobStmt();
|
||||
|
||||
void dateTime();
|
||||
void floats();
|
||||
void doubles();
|
||||
void tuples();
|
||||
|
@@ -45,8 +45,10 @@
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
class DateTime;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class BLOB;
|
||||
|
||||
@@ -107,6 +109,9 @@ public:
|
||||
virtual void bind(std::size_t pos, const BLOB& val) = 0;
|
||||
/// Binds a BLOB.
|
||||
|
||||
virtual void bind(std::size_t pos, const DateTime& val) = 0;
|
||||
/// Binds a DateTime.
|
||||
|
||||
bool isInBound() const;
|
||||
/// Returns true if binder is in-bound.
|
||||
|
||||
|
@@ -45,8 +45,10 @@
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
class DateTime;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class BLOB;
|
||||
|
||||
@@ -103,6 +105,9 @@ public:
|
||||
|
||||
virtual bool extract(std::size_t pos, BLOB& val) = 0;
|
||||
/// 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.
|
||||
};
|
||||
|
||||
|
||||
|
@@ -46,8 +46,11 @@
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
class DateTime;
|
||||
class Any;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class BLOB;
|
||||
|
||||
@@ -106,6 +109,12 @@ public:
|
||||
|
||||
virtual void prepare(std::size_t pos, const BLOB&) = 0;
|
||||
/// 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.
|
||||
};
|
||||
|
||||
|
||||
|
@@ -54,7 +54,7 @@ namespace Data {
|
||||
template <class T, class C = std::vector<T> >
|
||||
class Column
|
||||
/// 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.
|
||||
/// Construction with null pointer is not allowed.
|
||||
/// This class owns the data assigned to it and deletes the storage on destruction.
|
||||
@@ -62,6 +62,7 @@ class Column
|
||||
public:
|
||||
typedef C Container;
|
||||
typedef typename Container::const_iterator Iterator;
|
||||
typedef typename Container::const_reverse_iterator RIterator;
|
||||
typedef typename Container::size_type Size;
|
||||
|
||||
Column(const MetaColumn& metaColumn, C* pData): _metaColumn(metaColumn), _pData(pData)
|
||||
@@ -190,6 +191,7 @@ class Column<T, std::list<T> >
|
||||
public:
|
||||
typedef std::list<T> List;
|
||||
typedef typename List::const_iterator Iterator;
|
||||
typedef typename List::const_reverse_iterator RIterator;
|
||||
typedef typename List::size_type Size;
|
||||
|
||||
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
|
||||
/// 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();
|
||||
List::const_iterator end = _pData->end();
|
||||
for (int i = 0; it != end; ++it, ++i)
|
||||
if (i == row) return *it;
|
||||
if (row <= (std::size_t) (_pData->size() / 2))
|
||||
{
|
||||
Iterator it = _pData->begin();
|
||||
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.");
|
||||
}
|
||||
|
@@ -67,6 +67,7 @@ public:
|
||||
FDT_DOUBLE,
|
||||
FDT_STRING,
|
||||
FDT_BLOB,
|
||||
FDT_TIMESTAMP,
|
||||
FDT_UNKNOWN
|
||||
};
|
||||
|
||||
|
@@ -255,11 +255,11 @@ private:
|
||||
Limit _extrLimit;
|
||||
Poco::UInt32 _lowerLimit;
|
||||
int _columnsExtracted;
|
||||
SessionImpl& _rSession;
|
||||
Storage _storage;
|
||||
std::ostringstream _ostr;
|
||||
AbstractBindingVec _bindings;
|
||||
AbstractExtractionVec _extractors;
|
||||
SessionImpl& _rSession;
|
||||
Storage _storage;
|
||||
|
||||
friend class Statement;
|
||||
};
|
||||
|
Reference in New Issue
Block a user