merge pg binary extraction support

This commit is contained in:
Günter Obiltschnig 2022-05-17 07:22:04 +02:00
parent 7852153db5
commit ae25f95454
17 changed files with 1712 additions and 70 deletions

View File

@ -8,7 +8,7 @@ include $(POCO_BASE)/build/rules/global
include PostgreSQL.make include PostgreSQL.make
objects = Extractor Binder SessionImpl Connector \ objects = Extractor BinaryExtractor Binder SessionImpl Connector \
PostgreSQLStatementImpl PostgreSQLException \ PostgreSQLStatementImpl PostgreSQLException \
SessionHandle StatementExecutor PostgreSQLTypes Utility SessionHandle StatementExecutor PostgreSQLTypes Utility

View File

@ -0,0 +1,346 @@
//
// BinaryExtractor.h
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: Extractor
//
// Definition of the BinaryExtractor class.
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SQL_PostgreSQL_BinaryExtractor_INCLUDED
#define SQL_PostgreSQL_BinaryExtractor_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/PostgreSQL/StatementExecutor.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/LOB.h"
#include "Poco/Types.h"
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
#include "Poco/Dynamic/Var.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
class PostgreSQL_API BinaryExtractor: public Poco::Data::AbstractExtractor
/// Extracts and converts data values from the result row returned by PostgreSQL.
/// If NULL is received, the incoming val value is not changed and false is returned
{
public:
using Ptr = SharedPtr<BinaryExtractor>;
BinaryExtractor(StatementExecutor& st);
/// Creates the Extractor.
virtual ~BinaryExtractor();
/// Destroys the Extractor.
virtual bool extract(std::size_t pos, Poco::Int8& val);
/// Extracts an Int8.
virtual bool extract(std::size_t pos, Poco::UInt8& val);
/// Extracts an UInt8.
virtual bool extract(std::size_t pos, Poco::Int16& val);
/// Extracts an Int16.
virtual bool extract(std::size_t pos, Poco::UInt16& val);
/// Extracts an UInt16.
virtual bool extract(std::size_t pos, Poco::Int32& val);
/// Extracts an Int32.
virtual bool extract(std::size_t pos, Poco::UInt32& val);
/// Extracts an UInt32.
virtual bool extract(std::size_t pos, Poco::Int64& val);
/// Extracts an Int64.
virtual bool extract(std::size_t pos, Poco::UInt64& val);
/// Extracts an UInt64.
#ifndef POCO_INT64_IS_LONG
virtual bool extract(std::size_t pos, long& val);
/// Extracts a long. Returns false if null was received.
virtual bool extract(std::size_t pos, unsigned long& val);
/// Extracts an unsigned long. Returns false if null was received.
#endif
virtual bool extract(std::size_t pos, bool& val);
/// Extracts a boolean.
virtual bool extract(std::size_t pos, float& val);
/// Extracts a float.
virtual bool extract(std::size_t pos, double& val);
/// Extracts a double.
virtual bool extract(std::size_t pos, char& val);
/// Extracts a single character.
virtual bool extract(std::size_t pos, std::string& val);
/// Extracts a string.
virtual bool extract(std::size_t pos, Poco::Data::BLOB& val);
/// Extracts a BLOB.
virtual bool extract(std::size_t pos, Poco::Data::CLOB& val);
/// Extracts a CLOB.
virtual bool extract(std::size_t pos, DateTime& val);
/// Extracts a DateTime. Returns false if null was received.
virtual bool extract(std::size_t pos, Date& val);
/// Extracts a Date. Returns false if null was received.
virtual bool extract(std::size_t pos, Time& val);
/// Extracts a Time. Returns false if null was received.
virtual bool extract(std::size_t pos, UUID& val);
/// Extracts a UUID. Returns false if null was received.
virtual bool extract(std::size_t pos, Any& val);
/// Extracts an Any. Returns false if null was received.
virtual bool extract(std::size_t pos, Dynamic::Var& val);
/// Extracts a Dynamic::Var. Returns false if null was received.
virtual bool isNull(std::size_t col, std::size_t row);
/// Returns true if the value at [col,row] position is null.
virtual void reset();
/// Resets any information internally cached by the extractor.
////////////
// Not implemented extract functions
////////////
virtual bool extract(std::size_t pos, std::vector<Poco::Int8>& val);
/// Extracts an Int8 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::Int8>& val);
/// Extracts an Int8 deque.
virtual bool extract(std::size_t pos, std::list<Poco::Int8>& val);
/// Extracts an Int8 list.
virtual bool extract(std::size_t pos, std::vector<Poco::UInt8>& val);
/// Extracts an UInt8 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::UInt8>& val);
/// Extracts an UInt8 deque.
virtual bool extract(std::size_t pos, std::list<Poco::UInt8>& val);
/// Extracts an UInt8 list.
virtual bool extract(std::size_t pos, std::vector<Poco::Int16>& val);
/// Extracts an Int16 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::Int16>& val);
/// Extracts an Int16 deque.
virtual bool extract(std::size_t pos, std::list<Poco::Int16>& val);
/// Extracts an Int16 list.
virtual bool extract(std::size_t pos, std::vector<Poco::UInt16>& val);
/// Extracts an UInt16 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::UInt16>& val);
/// Extracts an UInt16 deque.
virtual bool extract(std::size_t pos, std::list<Poco::UInt16>& val);
/// Extracts an UInt16 list.
virtual bool extract(std::size_t pos, std::vector<Poco::Int32>& val);
/// Extracts an Int32 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::Int32>& val);
/// Extracts an Int32 deque.
virtual bool extract(std::size_t pos, std::list<Poco::Int32>& val);
/// Extracts an Int32 list.
virtual bool extract(std::size_t pos, std::vector<Poco::UInt32>& val);
/// Extracts an UInt32 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::UInt32>& val);
/// Extracts an UInt32 deque.
virtual bool extract(std::size_t pos, std::list<Poco::UInt32>& val);
/// Extracts an UInt32 list.
virtual bool extract(std::size_t pos, std::vector<Poco::Int64>& val);
/// Extracts an Int64 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::Int64>& val);
/// Extracts an Int64 deque.
virtual bool extract(std::size_t pos, std::list<Poco::Int64>& val);
/// Extracts an Int64 list.
virtual bool extract(std::size_t pos, std::vector<Poco::UInt64>& val);
/// Extracts an UInt64 vector.
virtual bool extract(std::size_t pos, std::deque<Poco::UInt64>& val);
/// Extracts an UInt64 deque.
virtual bool extract(std::size_t pos, std::list<Poco::UInt64>& val);
/// Extracts an UInt64 list.
#ifndef POCO_INT64_IS_LONG
virtual bool extract(std::size_t pos, std::vector<long>& val);
/// Extracts a long vector.
virtual bool extract(std::size_t pos, std::deque<long>& val);
/// Extracts a long deque.
virtual bool extract(std::size_t pos, std::list<long>& val);
/// Extracts a long list.
#endif
virtual bool extract(std::size_t pos, std::vector<bool>& val);
/// Extracts a boolean vector.
virtual bool extract(std::size_t pos, std::deque<bool>& val);
/// Extracts a boolean deque.
virtual bool extract(std::size_t pos, std::list<bool>& val);
/// Extracts a boolean list.
virtual bool extract(std::size_t pos, std::vector<float>& val);
/// Extracts a float vector.
virtual bool extract(std::size_t pos, std::deque<float>& val);
/// Extracts a float deque.
virtual bool extract(std::size_t pos, std::list<float>& val);
/// Extracts a float list.
virtual bool extract(std::size_t pos, std::vector<double>& val);
/// Extracts a double vector.
virtual bool extract(std::size_t pos, std::deque<double>& val);
/// Extracts a double deque.
virtual bool extract(std::size_t pos, std::list<double>& val);
/// Extracts a double list.
virtual bool extract(std::size_t pos, std::vector<char>& val);
/// Extracts a character vector.
virtual bool extract(std::size_t pos, std::deque<char>& val);
/// Extracts a character deque.
virtual bool extract(std::size_t pos, std::list<char>& val);
/// Extracts a character list.
virtual bool extract(std::size_t pos, std::vector<std::string>& val);
/// Extracts a string vector.
virtual bool extract(std::size_t pos, std::deque<std::string>& val);
/// Extracts a string deque.
virtual bool extract(std::size_t pos, std::list<std::string>& val);
/// Extracts a string list.
virtual bool extract(std::size_t pos, std::vector<BLOB>& val);
/// Extracts a BLOB vector.
virtual bool extract(std::size_t pos, std::deque<BLOB>& val);
/// Extracts a BLOB deque.
virtual bool extract(std::size_t pos, std::list<BLOB>& val);
/// Extracts a BLOB list.
virtual bool extract(std::size_t pos, std::vector<CLOB>& val);
/// Extracts a CLOB vector.
virtual bool extract(std::size_t pos, std::deque<CLOB>& val);
/// Extracts a CLOB deque.
virtual bool extract(std::size_t pos, std::list<CLOB>& val);
/// Extracts a CLOB list.
virtual bool extract(std::size_t pos, std::vector<DateTime>& val);
/// Extracts a DateTime vector.
virtual bool extract(std::size_t pos, std::deque<DateTime>& val);
/// Extracts a DateTime deque.
virtual bool extract(std::size_t pos, std::list<DateTime>& val);
/// Extracts a DateTime list.
virtual bool extract(std::size_t pos, std::vector<Date>& val);
/// Extracts a Date vector.
virtual bool extract(std::size_t pos, std::deque<Date>& val);
/// Extracts a Date deque.
virtual bool extract(std::size_t pos, std::list<Date>& val);
/// Extracts a Date list.
virtual bool extract(std::size_t pos, std::vector<Time>& val);
/// Extracts a Time vector.
virtual bool extract(std::size_t pos, std::deque<Time>& val);
/// Extracts a Time deque.
virtual bool extract(std::size_t pos, std::list<Time>& val);
/// Extracts a Time list.
virtual bool extract(std::size_t pos, std::vector<Any>& val);
/// Extracts an Any vector.
virtual bool extract(std::size_t pos, std::deque<Any>& val);
/// Extracts an Any deque.
virtual bool extract(std::size_t pos, std::list<Any>& val);
/// Extracts an Any list.
virtual bool extract(std::size_t pos, std::vector<Dynamic::Var>& val);
/// Extracts a Dynamic::Var vector.
virtual bool extract(std::size_t pos, std::deque<Dynamic::Var>& val);
/// Extracts a Dynamic::Var deque.
virtual bool extract(std::size_t pos, std::list<Dynamic::Var>& val);
/// Extracts a Dynamic::Var list.
private:
const OutputParameter& extractPreamble(std::size_t aPosition) const;
bool isColumnNull(const OutputParameter& anOutputParameter) const;
// Prevent VC8 warning "operator= could not be generated"
BinaryExtractor& operator = (const BinaryExtractor&);
private:
StatementExecutor& _statementExecutor;
};
//
// inlines
//
inline bool BinaryExtractor::isColumnNull(const OutputParameter& anOutputParameter) const
{
return anOutputParameter.isNull() || 0 == anOutputParameter.pData();
}
} } } // namespace Poco::Data::PostgreSQL
#endif // SQL_PostgreSQL_BinaryExtractor_INCLUDED

View File

@ -351,6 +351,15 @@ private:
}; };
//
// inlines
//
inline bool Extractor::isColumnNull(const OutputParameter& anOutputParameter) const
{
return anOutputParameter.isNull() || 0 == anOutputParameter.pData();
}
} } } // namespace Poco::Data::PostgreSQL } } } // namespace Poco::Data::PostgreSQL

View File

@ -21,9 +21,9 @@
#include "Poco/Data/PostgreSQL/PostgreSQL.h" #include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/PostgreSQL/SessionImpl.h" #include "Poco/Data/PostgreSQL/SessionImpl.h"
#include "Poco/Data/PostgreSQL/Binder.h" #include "Poco/Data/PostgreSQL/Binder.h"
#include "Poco/Data/PostgreSQL/Extractor.h"
#include "Poco/Data/PostgreSQL/StatementExecutor.h" #include "Poco/Data/PostgreSQL/StatementExecutor.h"
#include "Poco/Data/StatementImpl.h" #include "Poco/Data/StatementImpl.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
#include "Poco/Format.h" #include "Poco/Format.h"
@ -89,7 +89,7 @@ private:
StatementExecutor _statementExecutor; StatementExecutor _statementExecutor;
Binder::Ptr _pBinder; Binder::Ptr _pBinder;
Extractor::Ptr _pExtractor; AbstractExtractor::Ptr _pExtractor;
NextState _hasNext; NextState _hasNext;
}; };

View File

@ -31,6 +31,7 @@ namespace PostgreSQL {
/// Oid constants duplicated from PostgreSQL "include/postgresql/server/catalog/pg_type.h" /// Oid constants duplicated from PostgreSQL "include/postgresql/server/catalog/pg_type.h"
/// because PostgreSQL compile time definitions are too onerous to reproduce for this module /// because PostgreSQL compile time definitions are too onerous to reproduce for this module
const Oid INVALIDOID = 0;
const Oid BOOLOID = 16; const Oid BOOLOID = 16;
@ -53,7 +54,7 @@ const Oid DATEOID = 1082;
const Oid TIMEOID = 1083; const Oid TIMEOID = 1083;
const Oid TIMETZOID = 1266; const Oid TIMETZOID = 1266;
const Oid TIMESTAMPOID = 1114; const Oid TIMESTAMPOID = 1114;
const Oid TIMESTAMPZOID = 1184; const Oid TIMESTAMPTZOID = 1184;
// future use // future use
const Oid BITOID = 1560; const Oid BITOID = 1560;

View File

@ -155,6 +155,9 @@ public:
std::string clientEncoding() const; std::string clientEncoding() const;
/// returns the client encoding /// returns the client encoding
std::string parameterStatus(const std::string& param) const;
/// Returns the value configured on the server for the given parameter.
int libpqVersion() const; int libpqVersion() const;
/// returns the version of libpq /// returns the version of libpq

View File

@ -111,6 +111,19 @@ public:
bool isAsynchronousCommit(const std::string& aName = std::string()) const; bool isAsynchronousCommit(const std::string& aName = std::string()) const;
/// is the connection in Asynchronous commit mode? /// is the connection in Asynchronous commit mode?
void setBinaryExtraction(const std::string& feature, bool enabled);
/// Sets the "binaryExtraction" feature. If set, column values received from
/// PostgreSQL client will be extracted as binary values. This improves
/// extraction performance, but will not work with all types.
///
/// If not set, all column values will be extracted as strings. This gives
/// lower performance, but allows to extract also types not supported
/// directly by Poco::Data.
bool isBinaryExtraction(const std::string& feature = std::string()) const;
/// Returns true if binary extraction is enabled, otherwise false.
/// See setBinaryExtraction() for more information.
SessionHandle& handle(); SessionHandle& handle();
/// Get handle /// Get handle
@ -120,7 +133,8 @@ public:
private: private:
std::string _connectorName; std::string _connectorName;
mutable SessionHandle _sessionHandle; mutable SessionHandle _sessionHandle;
std::size_t _timeout; std::size_t _timeout = 0;
bool _binaryExtraction = false;
}; };
@ -159,6 +173,12 @@ inline std::size_t SessionImpl::getConnectionTimeout() const
} }
inline bool SessionImpl::isBinaryExtraction(const std::string&) const
{
return _binaryExtraction;
}
} } } // namespace Poco::Data::PostgreSQL } } } // namespace Poco::Data::PostgreSQL

View File

@ -43,7 +43,7 @@ public:
STMT_EXECUTED STMT_EXECUTED
}; };
explicit StatementExecutor(SessionHandle& aSessionHandle); explicit StatementExecutor(SessionHandle& aSessionHandle, bool binaryExtraction);
/// Creates the StatementExecutor. /// Creates the StatementExecutor.
~StatementExecutor(); ~StatementExecutor();
@ -90,6 +90,7 @@ private:
typedef std::vector<MetaColumn> ColVec; typedef std::vector<MetaColumn> ColVec;
SessionHandle& _sessionHandle; SessionHandle& _sessionHandle;
bool _binaryExtraction;
State _state; State _state;
PGresult* _pResultHandle; PGresult* _pResultHandle;
std::string _SQLStatement; std::string _SQLStatement;

File diff suppressed because it is too large Load Diff

View File

@ -40,8 +40,7 @@ Extractor::~Extractor()
bool Extractor::extract(std::size_t pos, Poco::Int8& val) bool Extractor::extract(std::size_t pos, Poco::Int8& val)
{ {
const OutputParameter& outputParameter = extractPreamble(pos);
OutputParameter outputParameter = extractPreamble(pos);
int tempVal = 0; int tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal))
@ -56,7 +55,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int8& val)
bool Extractor::extract(std::size_t pos, Poco::UInt8& val) bool Extractor::extract(std::size_t pos, Poco::UInt8& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
unsigned int tempVal = 0; unsigned int tempVal = 0;
if (isColumnNull(outputParameter)|| !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter)|| !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal))
@ -71,7 +70,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt8& val)
bool Extractor::extract(std::size_t pos, Poco::Int16& val) bool Extractor::extract(std::size_t pos, Poco::Int16& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
int tempVal = 0; int tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal))
@ -86,7 +85,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int16& val)
bool Extractor::extract(std::size_t pos, Poco::UInt16& val) bool Extractor::extract(std::size_t pos, Poco::UInt16& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
unsigned int tempVal = 0; unsigned int tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal))
@ -101,7 +100,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt16& val)
bool Extractor::extract(std::size_t pos, Poco::Int32& val) bool Extractor::extract(std::size_t pos, Poco::Int32& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), val)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), val))
{ {
@ -114,7 +113,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int32& val)
bool Extractor::extract(std::size_t pos, Poco::UInt32& val) bool Extractor::extract(std::size_t pos, Poco::UInt32& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), val)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), val))
{ {
@ -127,7 +126,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt32& val)
bool Extractor::extract(std::size_t pos, Poco::Int64& val) bool Extractor::extract(std::size_t pos, Poco::Int64& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), val)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), val))
{ {
@ -140,7 +139,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int64& val)
bool Extractor::extract(std::size_t pos, Poco::UInt64& val) bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), val)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), val))
{ {
@ -154,7 +153,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
#ifndef POCO_INT64_IS_LONG #ifndef POCO_INT64_IS_LONG
bool Extractor::extract(std::size_t pos, long& val) bool Extractor::extract(std::size_t pos, long& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
Poco::Int64 tempVal = 0; Poco::Int64 tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), tempVal))
@ -169,7 +168,7 @@ bool Extractor::extract(std::size_t pos, long& val)
bool Extractor::extract(std::size_t pos, unsigned long& val) bool Extractor::extract(std::size_t pos, unsigned long& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
Poco::UInt64 tempVal = 0; Poco::UInt64 tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), tempVal))
@ -185,7 +184,7 @@ bool Extractor::extract(std::size_t pos, unsigned long& val)
bool Extractor::extract(std::size_t pos, bool& val) bool Extractor::extract(std::size_t pos, bool& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -200,7 +199,7 @@ bool Extractor::extract(std::size_t pos, bool& val)
bool Extractor::extract(std::size_t pos, float& val) bool Extractor::extract(std::size_t pos, float& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
double tempVal = 0.0; double tempVal = 0.0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), tempVal)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), tempVal))
@ -215,7 +214,7 @@ bool Extractor::extract(std::size_t pos, float& val)
bool Extractor::extract(std::size_t pos, double& val) bool Extractor::extract(std::size_t pos, double& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), val)) if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), val))
{ {
@ -228,7 +227,7 @@ bool Extractor::extract(std::size_t pos, double& val)
bool Extractor::extract(std::size_t pos, char& val) bool Extractor::extract(std::size_t pos, char& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -242,7 +241,7 @@ bool Extractor::extract(std::size_t pos, char& val)
bool Extractor::extract(std::size_t pos, std::string& val) bool Extractor::extract(std::size_t pos, std::string& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -256,7 +255,7 @@ bool Extractor::extract(std::size_t pos, std::string& val)
bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val) bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -291,7 +290,7 @@ bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val) bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -305,7 +304,7 @@ bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val)
bool Extractor::extract(std::size_t pos, DateTime& val) bool Extractor::extract(std::size_t pos, DateTime& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -314,7 +313,7 @@ bool Extractor::extract(std::size_t pos, DateTime& val)
int tzd = -1; int tzd = -1;
DateTime dateTime; DateTime dateTime;
if (!DateTimeParser::tryParse("%Y-%m-%d %H:%M:%s", outputParameter.pData(), dateTime, tzd)) if (!DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
{ {
return false; return false;
} }
@ -327,7 +326,7 @@ bool Extractor::extract(std::size_t pos, DateTime& val)
bool Extractor::extract(std::size_t pos, Date& val) bool Extractor::extract(std::size_t pos, Date& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -348,7 +347,7 @@ bool Extractor::extract(std::size_t pos, Date& val)
bool Extractor::extract(std::size_t pos, Time& val) bool Extractor::extract(std::size_t pos, Time& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -372,7 +371,7 @@ bool Extractor::extract(std::size_t pos, Time& val)
bool Extractor::extract(std::size_t pos, UUID& val) bool Extractor::extract(std::size_t pos, UUID& val)
{ {
OutputParameter outputParameter = extractPreamble(pos); const OutputParameter& outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -397,7 +396,7 @@ bool Extractor::extract(std::size_t pos, Dynamic::Var& val)
bool Extractor::isNull(std::size_t col, std::size_t /*row*/) bool Extractor::isNull(std::size_t col, std::size_t /*row*/)
{ {
OutputParameter outputParameter = extractPreamble(col); const OutputParameter& outputParameter = extractPreamble(col);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -425,15 +424,9 @@ const OutputParameter& Extractor::extractPreamble(std::size_t aPosition) const
} }
bool Extractor::isColumnNull(const OutputParameter& anOutputParameter) const
{
return anOutputParameter.isNull() || 0 == anOutputParameter.pData();
}
bool Extractor::extractToDynamic(std::size_t pos, Dynamic::Var& val) bool Extractor::extractToDynamic(std::size_t pos, Dynamic::Var& val)
{ {
OutputParameter outputParameter = _statementExecutor.resultColumn(pos); const OutputParameter& outputParameter = _statementExecutor.resultColumn(pos);
if (isColumnNull(outputParameter)) if (isColumnNull(outputParameter))
{ {
@ -525,7 +518,7 @@ bool Extractor::extractToDynamic(std::size_t pos, Dynamic::Var& val)
} }
//timestamp //timestamp
case TIMESTAMPOID: case TIMESTAMPOID:
case TIMESTAMPZOID: case TIMESTAMPTZOID:
{ {
DateTime dt; DateTime dt;
success = extract(pos, dt); success = extract(pos, dt);

View File

@ -13,7 +13,8 @@
#include "Poco/Data/PostgreSQL/PostgreSQLStatementImpl.h" #include "Poco/Data/PostgreSQL/PostgreSQLStatementImpl.h"
#include "Poco/Data/PostgreSQL/Extractor.h"
#include "Poco/Data/PostgreSQL/BinaryExtractor.h"
namespace Poco { namespace Poco {
namespace Data { namespace Data {
@ -22,11 +23,14 @@ namespace PostgreSQL {
PostgreSQLStatementImpl::PostgreSQLStatementImpl(SessionImpl& aSessionImpl): PostgreSQLStatementImpl::PostgreSQLStatementImpl(SessionImpl& aSessionImpl):
Poco::Data::StatementImpl(aSessionImpl), Poco::Data::StatementImpl(aSessionImpl),
_statementExecutor(aSessionImpl.handle()), _statementExecutor(aSessionImpl.handle(), aSessionImpl.isBinaryExtraction()),
_pBinder(new Binder), _pBinder(new Binder),
_pExtractor(new Extractor (_statementExecutor)),
_hasNext(NEXT_DONTKNOW) _hasNext(NEXT_DONTKNOW)
{ {
if (aSessionImpl.isBinaryExtraction())
_pExtractor = new BinaryExtractor(_statementExecutor);
else
_pExtractor = new Extractor(_statementExecutor);
} }

View File

@ -90,7 +90,7 @@ Poco::Data::MetaColumn::ColumnDataType oidToColumnDataType(const Oid anOID)
case TIMESTAMPOID: case TIMESTAMPOID:
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP; cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
break; break;
case TIMESTAMPZOID: case TIMESTAMPTZOID:
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP; cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
break; break;

View File

@ -493,6 +493,23 @@ std::string SessionHandle::clientEncoding() const
} }
std::string SessionHandle::parameterStatus(const std::string& param) const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
const char* pValue = PQparameterStatus(_pConnection, param.c_str());
if (pValue)
return std::string(pValue);
else
return std::string();
}
int SessionHandle::libpqVersion() const int SessionHandle::libpqVersion() const
{ {
return PQlibVersion(); return PQlibVersion();

View File

@ -140,6 +140,10 @@ void SessionImpl::open(const std::string& aConnectionString)
addFeature("asynchronousCommit", addFeature("asynchronousCommit",
&SessionImpl::setAutoCommit, &SessionImpl::setAutoCommit,
&SessionImpl::isAutoCommit); &SessionImpl::isAutoCommit);
addFeature("binaryExtraction",
&SessionImpl::setBinaryExtraction,
&SessionImpl::isBinaryExtraction);
} }
@ -244,4 +248,13 @@ bool SessionImpl::hasTransactionIsolation(Poco::UInt32 aTI) const
} }
void SessionImpl::setBinaryExtraction(const std::string& feature, bool enabled)
{
if (enabled && _sessionHandle.parameterStatus("integer_datetimes") != "on")
throw PostgreSQLException("binary extraction is not supported with this server (ingeger_datetimes must be enabled on the server)");
_binaryExtraction = enabled;
}
} } } // namespace Poco::Data::PostgreSQL } } } // namespace Poco::Data::PostgreSQL

View File

@ -72,8 +72,9 @@ namespace Data {
namespace PostgreSQL { namespace PostgreSQL {
StatementExecutor::StatementExecutor(SessionHandle& sessionHandle): StatementExecutor::StatementExecutor(SessionHandle& sessionHandle, bool binaryExtraction):
_sessionHandle(sessionHandle), _sessionHandle(sessionHandle),
_binaryExtraction(binaryExtraction),
_state(STMT_INITED), _state(STMT_INITED),
_pResultHandle(0), _pResultHandle(0),
_countPlaceholdersInSQLStatement(0), _countPlaceholdersInSQLStatement(0),
@ -252,7 +253,8 @@ void StatementExecutor::execute()
_preparedStatementName.c_str(), (int)_countPlaceholdersInSQLStatement, _preparedStatementName.c_str(), (int)_countPlaceholdersInSQLStatement,
_inputParameterVector.size() != 0 ? &pParameterVector[ 0 ] : 0, _inputParameterVector.size() != 0 ? &pParameterVector[ 0 ] : 0,
_inputParameterVector.size() != 0 ? &parameterLengthVector[ 0 ] : 0, _inputParameterVector.size() != 0 ? &parameterLengthVector[ 0 ] : 0,
_inputParameterVector.size() != 0 ? &parameterFormatVector[ 0 ] : 0, 0); _inputParameterVector.size() != 0 ? &parameterFormatVector[ 0 ] : 0,
_binaryExtraction ? 1 : 0);
} }
// Don't setup to auto clear the result (ptrPGResult). It is required to retrieve the results later. // Don't setup to auto clear the result (ptrPGResult). It is required to retrieve the results later.

View File

@ -647,6 +647,7 @@ void PostgreSQLTest::testBLOB()
catch (DataException&) { } catch (DataException&) { }
} }
void PostgreSQLTest::testCLOBStmt() void PostgreSQLTest::testCLOBStmt()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@ -655,6 +656,7 @@ void PostgreSQLTest::testCLOBStmt()
_pExecutor->clobStmt(); _pExecutor->clobStmt();
} }
void PostgreSQLTest::testBLOBStmt() void PostgreSQLTest::testBLOBStmt()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@ -663,6 +665,7 @@ void PostgreSQLTest::testBLOBStmt()
_pExecutor->blobStmt(); _pExecutor->blobStmt();
} }
void PostgreSQLTest::testUnsignedInts() void PostgreSQLTest::testUnsignedInts()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@ -698,6 +701,7 @@ void PostgreSQLTest::testUUID()
_pExecutor->uuids(); _pExecutor->uuids();
} }
void PostgreSQLTest::testTuple() void PostgreSQLTest::testTuple()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@ -888,10 +892,133 @@ void PostgreSQLTest::testTupleWithNullable()
assertTrue (result[5].get<1>() == std::string("B")); assertTrue (result[5].get<1>() == std::string("B"));
assertTrue (result[5].get<2>() == null); assertTrue (result[5].get<2>() == null);
} }
void PostgreSQLTest::testBinarySimpleAccess()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonTable();
_pExecutor->simpleAccess();
}
void PostgreSQLTest::testBinaryComplexType()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonTable();
_pExecutor->complexType();
}
void PostgreSQLTest::testBinarySimpleAccessVector()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonTable();
_pExecutor->simpleAccessVector();
}
void PostgreSQLTest::testBinaryComplexTypeVector()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonTable();
_pExecutor->complexTypeVector();
}
void PostgreSQLTest::testBinaryInts()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreateUnsignedIntsTable();
_pExecutor->unsignedInts();
}
void PostgreSQLTest::testBinaryFloat()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreateFloatsTable();
_pExecutor->floats();
}
void PostgreSQLTest::testBinaryDouble()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreateFloatsTable();
_pExecutor->doubles();
}
void PostgreSQLTest::testBinaryUUID()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreateUUIDsTable();
_pExecutor->uuids();
}
void PostgreSQLTest::testBinaryDateTime()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonDateTimeTable();
_pExecutor->dateTime();
recreatePersonDateTable();
_pExecutor->date();
recreatePersonTimeTable();
_pExecutor->time();
}
void PostgreSQLTest::testBinaryCLOBStmt()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonCLOBTable();
_pExecutor->clobStmt();
}
void PostgreSQLTest::testBinaryBLOBStmt()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("binaryExtraction", true);
recreatePersonBLOBTable();
_pExecutor->blobStmt();
}
void PostgreSQLTest::dropTable(const std::string& tableName) void PostgreSQLTest::dropTable(const std::string& tableName)
{ {
try try
@ -994,6 +1121,14 @@ void PostgreSQLTest::recreateFloatsTable()
} }
void PostgreSQLTest::recreateDoublesTable()
{
dropTable("Strings");
try { *_pSession << "CREATE TABLE Strings (str DOUBLE)", now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateDoublesTable()"); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateDoublesTable()"); }
}
void PostgreSQLTest::recreateUUIDsTable() void PostgreSQLTest::recreateUUIDsTable()
{ {
dropTable("Strings"); dropTable("Strings");
@ -1055,6 +1190,7 @@ void PostgreSQLTest::tearDown()
{ {
dropTable("Person"); dropTable("Person");
dropTable("Strings"); dropTable("Strings");
_pSession->setFeature("binaryExtraction", false);
} }
@ -1135,6 +1271,19 @@ CppUnit::Test* PostgreSQLTest::suite()
CppUnit_addTest(pSuite, PostgreSQLTest, testNullableInt); CppUnit_addTest(pSuite, PostgreSQLTest, testNullableInt);
CppUnit_addTest(pSuite, PostgreSQLTest, testNullableString); CppUnit_addTest(pSuite, PostgreSQLTest, testNullableString);
CppUnit_addTest(pSuite, PostgreSQLTest, testTupleWithNullable); CppUnit_addTest(pSuite, PostgreSQLTest, testTupleWithNullable);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinarySimpleAccess);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryComplexType);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinarySimpleAccessVector);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryComplexTypeVector);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryInts);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryFloat);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryDouble);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryUUID);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryDateTime);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryCLOBStmt);
CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryBLOBStmt);
CppUnit_addTest(pSuite, PostgreSQLTest, testSessionTransaction); CppUnit_addTest(pSuite, PostgreSQLTest, testSessionTransaction);
CppUnit_addTest(pSuite, PostgreSQLTest, testTransaction); CppUnit_addTest(pSuite, PostgreSQLTest, testTransaction);
CppUnit_addTest(pSuite, PostgreSQLTest, testReconnect); CppUnit_addTest(pSuite, PostgreSQLTest, testReconnect);

View File

@ -96,6 +96,18 @@ public:
void testNullableString(); void testNullableString();
void testTupleWithNullable(); void testTupleWithNullable();
void testBinarySimpleAccess();
void testBinaryComplexType();
void testBinarySimpleAccessVector();
void testBinaryComplexTypeVector();
void testBinaryInts();
void testBinaryFloat();
void testBinaryDouble();
void testBinaryUUID();
void testBinaryDateTime();
void testBinaryBLOBStmt();
void testBinaryCLOBStmt();
void testSessionTransaction(); void testSessionTransaction();
void testTransaction(); void testTransaction();
@ -119,6 +131,7 @@ private:
void recreateIntsTable(); void recreateIntsTable();
void recreateUnsignedIntsTable(); void recreateUnsignedIntsTable();
void recreateFloatsTable(); void recreateFloatsTable();
void recreateDoublesTable();
void recreateUUIDsTable(); void recreateUUIDsTable();
void recreateTuplesTable(); void recreateTuplesTable();
void recreateVectorsTable(); void recreateVectorsTable();