1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-09-14 12:07:09 +02:00

Major plugin refactor and cleanup.

Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
This commit is contained in:
Sandu Liviu Catalin
2021-01-30 08:51:39 +02:00
parent e0e34b4030
commit 4a6bfc086c
6219 changed files with 1209835 additions and 454916 deletions

View File

@@ -0,0 +1,667 @@
//
// Binder.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: Binder
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/Binder.h"
#include "Poco/NumberFormatter.h"
#include "Poco/DateTimeFormat.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
Binder::Binder()
{
}
Binder::~Binder()
{
}
void Binder::bind(std::size_t pos, const Poco::Int8& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_INT8, &val, sizeof(Poco::Int8));
}
void Binder::bind(std::size_t pos, const Poco::UInt8& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UINT8, &val, sizeof(Poco::UInt8));
}
void Binder::bind(std::size_t pos, const Poco::Int16& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_INT16, &val, sizeof(Poco::Int16));
}
void Binder::bind(std::size_t pos, const Poco::UInt16& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UINT16, &val, sizeof(Poco::UInt16));
}
void Binder::bind(std::size_t pos, const Poco::Int32& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_INT32, &val, sizeof(Poco::Int32));
}
void Binder::bind(std::size_t pos, const Poco::UInt32& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UINT32, &val, sizeof(Poco::UInt32));
}
void Binder::bind(std::size_t pos, const Poco::Int64& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_INT64, &val, sizeof(Poco::Int64));
}
void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UINT64, &val, sizeof(Poco::UInt64));
}
#ifndef POCO_INT64_IS_LONG
void Binder::bind(std::size_t pos, const long& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_INT64, &val, sizeof(Poco::Int64));
}
void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UINT64, &val, sizeof(Poco::UInt64));
}
#endif
void Binder::bind(std::size_t pos, const bool& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_BOOL, &val, sizeof(bool));
}
void Binder::bind(std::size_t pos, const float& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_FLOAT, &val, sizeof(float));
}
void Binder::bind(std::size_t pos, const double& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_DOUBLE, &val, sizeof(double));
}
void Binder::bind(std::size_t pos, const char& val, Direction dir)
{
poco_assert(dir == PD_IN);
// USING UINT8 because Poco::Data::MetaColumn does not have a single character type, just std::string
realBind(pos, Poco::Data::MetaColumn::FDT_UINT8, &val, sizeof(char));
}
// complex types
void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_STRING, &val, static_cast<int>(val.size()));
}
void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_BLOB, &val, static_cast<int>(val.size()));
}
void Binder::bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_CLOB, &val, static_cast<int>(val.size()));
}
void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_TIMESTAMP, &val, sizeof(Poco::DateTime));
}
void Binder::bind(std::size_t pos, const Date& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_DATE, &val, sizeof(Date));
}
void Binder::bind(std::size_t pos, const Time& val, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_TIME, &val, sizeof(Time));
}
void Binder::bind(std::size_t pos, const NullData&, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UNKNOWN, 0, 0);
}
std::size_t Binder::size() const
{
return static_cast<std::size_t>(_bindVector.size());
}
InputParameterVector
Binder::bindVector() const
{
return _bindVector;
}
void Binder::updateBindVectorToCurrentValues()
{
InputParameterVector::iterator itr = _bindVector.begin();
InputParameterVector::iterator itrEnd = _bindVector.end();
for (; itr != itrEnd; ++itr)
{
switch (itr->fieldType())
{
case Poco::Data::MetaColumn::FDT_INT8:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::Int8*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_UINT8:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::UInt8*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_INT16:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::Int16*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_UINT16:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::UInt16*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_INT32:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::Int32*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_UINT32:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::UInt32*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_INT64:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::Int64*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_UINT64:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const Poco::UInt64*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_BOOL:
{
const bool currentBoolValue = * static_cast<const bool*>(itr->pData());
itr->setStringVersionRepresentation(currentBoolValue ? "TRUE" : "FALSE");
}
break;
case Poco::Data::MetaColumn::FDT_FLOAT:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const float*>(itr->pData())));
break;
case Poco::Data::MetaColumn::FDT_DOUBLE:
itr->setStringVersionRepresentation(Poco::NumberFormatter::format(* static_cast<const double*>(itr->pData())));
break;
// case Poco::Data::MetaColumn::FDT_CHAR:
// itr->setStringVersionRepresentation(std::string(static_cast<const char*>(itr->pData()), 1)); // single character string
// break;
case Poco::Data::MetaColumn::FDT_STRING:
itr->setStringVersionRepresentation(* static_cast<const std::string*>(itr->pData()));
break;
case Poco::Data::MetaColumn::FDT_TIMESTAMP:
{
const Poco::DateTime& dateTime = * static_cast<const Poco::DateTime*>(itr->pData());
itr->setStringVersionRepresentation(DateTimeFormatter::format(dateTime, Poco::DateTimeFormat::ISO8601_FRAC_FORMAT));
}
break;
case Poco::Data::MetaColumn::FDT_DATE:
{
const Poco::Data::Date& date = * static_cast<const Poco::Data::Date*>(itr->pData());
itr->setStringVersionRepresentation(DateTimeFormatter::format(Poco::DateTime(date.year(), date.month(), date.day()), "%Y-%m-%d"));
}
break;
case Poco::Data::MetaColumn::FDT_TIME:
{
const Poco::Data::Time& time = * static_cast<const Poco::Data::Time*>(itr->pData());
itr->setStringVersionRepresentation(DateTimeFormatter::format(Poco::DateTime(0, 1, 1, time.hour(), time.minute(), time.second()), "%H:%M:%s%z"));
}
break;
case Poco::Data::MetaColumn::FDT_BLOB:
{
const Poco::Data::BLOB& blob = * static_cast<const Poco::Data::BLOB*>(itr->pData());
itr->setNonStringVersionRepresentation(static_cast<const void*> (blob.rawContent()), blob.size());
}
break;
case Poco::Data::MetaColumn::FDT_CLOB:
{
const Poco::Data::CLOB& clob = * static_cast<const Poco::Data::CLOB*>(itr->pData());
itr->setNonStringVersionRepresentation(static_cast<const void*> (clob.rawContent()), clob.size());
}
case Poco::Data::MetaColumn::FDT_UNKNOWN:
default:
break;
}
}
}
void Binder::realBind(std::size_t aPosition, Poco::Data::MetaColumn::ColumnDataType aFieldType, const void* aBufferPtr, std::size_t aLength)
{
try
{
if (aPosition >= _bindVector.size())
{
_bindVector.resize(aPosition + 1);
}
InputParameter inputParameter(aFieldType, aBufferPtr, aLength);
_bindVector[aPosition] = inputParameter;
}
catch (std::bad_alloc&)
{
PostgreSQLException("Memory allocation error while binding");
}
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Int8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Int8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Int8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::UInt8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::UInt8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::UInt8>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Int16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Int16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Int16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::UInt16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::UInt16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::UInt16>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Int32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Int32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Int32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::UInt32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::UInt32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::UInt32>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Int64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Int64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Int64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::UInt64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::UInt64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::UInt64>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<bool>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<bool>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<bool>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<float>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<float>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<float>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<double>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<double>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<double>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<char>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<char>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<char>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::BLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::BLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::BLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::CLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::CLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::CLOB>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::DateTime>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::DateTime>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::DateTime>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::Date>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::Date>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::Date>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::Time>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::Time>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::Time>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::vector<std::string>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::deque<std::string>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
void Binder::bind(std::size_t /*pos*/, const std::list<std::string>& /*val*/, Direction /*dir*/)
{
throw NotImplementedException();
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,62 @@
//
// Connector.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: Connector
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/Connector.h"
#include "Poco/Data/PostgreSQL/SessionImpl.h"
#include "Poco/Data/SessionFactory.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
const std::string Connector::KEY("postgresql");
Connector::Connector()
{
}
Connector::~Connector()
{
}
const std::string& Connector::name() const
{
return KEY;
}
SessionImpl::Ptr Connector::createSession(const std::string& aConnectionString, std::size_t aTimeout)
{
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(aConnectionString, aTimeout));
}
void Connector::registerConnector()
{
Poco::Data::SessionFactory::instance().add(new Connector());
}
void Connector::unregisterConnector()
{
Poco::Data::SessionFactory::instance().remove(KEY);
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,870 @@
//
// Extractor.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: Extractor
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/Extractor.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/Time.h"
#include "Poco/NumberParser.h"
#include "Poco/DateTimeParser.h"
#include <limits>
namespace Poco {
namespace Data {
namespace PostgreSQL {
Extractor::Extractor(StatementExecutor& st /*, ResultMetadata& md */):
_statementExecutor (st)
{
}
Extractor::~Extractor()
{
}
bool Extractor::extract(std::size_t pos, Poco::Int8& val)
{
OutputParameter outputParameter = extractPreamble(pos);
int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)
)
{
return false;
}
val = static_cast<Int8>(tempVal);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::UInt8& val)
{
OutputParameter outputParameter = extractPreamble(pos);
unsigned int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)
)
{
return false;
}
val = static_cast<Int8>(tempVal);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Int16& val)
{
OutputParameter outputParameter = extractPreamble(pos);
int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)
)
{
return false;
}
val = static_cast<Int8>(tempVal);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::UInt16& val)
{
OutputParameter outputParameter = extractPreamble(pos);
unsigned int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)
)
{
return false;
}
val = static_cast<Int8>(tempVal);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Int32& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), val)
)
{
return false;
}
return true;
}
bool Extractor::extract(std::size_t pos, Poco::UInt32& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), val)
)
{
return false;
}
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Int64& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse64(outputParameter.pData(), val)
)
{
return false;
}
return true;
}
bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), val)
)
{
return false;
}
return true;
}
#ifndef POCO_INT64_IS_LONG
bool Extractor::extract(std::size_t pos, long& val)
{
OutputParameter outputParameter = extractPreamble(pos);
Poco::Int64 tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), tempVal)
)
{
return false;
}
val = (long)tempVal;
return true;
}
bool Extractor::extract(std::size_t pos, unsigned long& val)
{
OutputParameter outputParameter = extractPreamble(pos);
Poco::UInt64 tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), tempVal)
)
{
return false;
}
val = (unsigned long)tempVal;
return true;
}
#endif
bool Extractor::extract(std::size_t pos, bool& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter))
{
return false;
}
if ('t' == *outputParameter.pData())
{
val = true;
}
else
{
val = false;
}
return true;
}
bool Extractor::extract(std::size_t pos, float& val)
{
OutputParameter outputParameter = extractPreamble(pos);
double tempVal = 0.0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseFloat(outputParameter.pData(), tempVal)
)
{
return false;
}
val = (float)tempVal;
return true;
}
bool Extractor::extract(std::size_t pos, double& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseFloat(outputParameter.pData(), val)
)
{
return false;
}
return true;
}
bool Extractor::extract(std::size_t pos, char& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
val = *outputParameter.pData();
return true;
}
bool Extractor::extract(std::size_t pos, std::string& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
val.assign(outputParameter.pData(), outputParameter.size());
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
// convert the PostgreSQL text format to binary and append to the BLOB
// Format: \x10843029479abcf ... two characters for every byte
//
// The code below can be made more efficient by converting more than one byte at a time
// also if BLOB had a resize method it would be useful to allocate memory in one
// attempt.
//
const char * pBLOB = reinterpret_cast<const char*>(outputParameter.pData());
std::size_t BLOBSize = outputParameter.size();
if ( '\\' == pBLOB[0]
&& 'x' == pBLOB[1] // preamble to BYTEA data format in text form is \x
)
{
BLOBSize -= 2; // lose the preamble
BLOBSize /= 2; // each byte is encoded as two text characters
for (int i = 0; i < BLOBSize * 2; i += 2)
{
std::string buffer(&pBLOB[i + 2], 2);
unsigned int binaryBuffer = 0;
if (Poco::NumberParser::tryParseHex(buffer, binaryBuffer))
{
UInt8 finalBinaryBuffer = static_cast<UInt8>(binaryBuffer); // downsize
val.appendRaw(&finalBinaryBuffer, 1);
}
}
}
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
val.assignRaw(outputParameter.pData(), outputParameter.size());
return true;
}
bool Extractor::extract(std::size_t pos, DateTime& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
{
return false;
}
dateTime.makeUTC(tzd);
val = dateTime;
return true;
}
bool Extractor::extract(std::size_t pos, Date& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
{
return false;
}
dateTime.makeUTC(tzd);
val.assign(dateTime.year(), dateTime.month(), dateTime.day());
return true;
}
bool Extractor::extract(std::size_t pos, Time& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse("%H:%M:%s%z", outputParameter.pData(), dateTime, tzd))
{
return false;
}
// dateTime.makeUTC(tzd); // TODO
// Note: Poco::Data::Time should be extended to support the fractional components of Poco::DateTime
val.assign(dateTime.hour(), dateTime.minute(), dateTime.second());
return true;
}
bool Extractor::extract(std::size_t pos, Any& val)
{
return extractStringImpl (pos, val);
}
bool Extractor::extract(std::size_t pos, Dynamic::Var& val)
{
return extractStringImpl (pos, val);
}
bool Extractor::isNull(std::size_t col, std::size_t /*row*/)
{
OutputParameter outputParameter = extractPreamble(col);
if (isColumnNull(outputParameter))
{
return true;
}
return false;
}
void Extractor::reset()
{
AbstractExtractor::reset();
}
const OutputParameter&
Extractor::extractPreamble(std::size_t aPosition) const
{
if (_statementExecutor.columnsReturned() <= aPosition)
{
throw PostgreSQLException("Extractor: attempt to extract more parameters than query result contains");
}
return _statementExecutor.resultColumn(aPosition);
}
bool
Extractor::isColumnNull (const OutputParameter& anOutputParameter) const
{
return anOutputParameter.isNull()
|| 0 == anOutputParameter.pData();
}
//////////////
// Not implemented
//////////////
bool Extractor::extract(std::size_t , std::vector<Poco::Int8>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int8>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int8>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt8>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt8>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt8>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int16>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int16>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int16>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt16>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt16>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt16>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int32>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int32>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int32>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt32>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt32>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt32>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int64>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int64>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int64>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt64>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt64>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt64>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
#ifndef POCO_INT64_IS_LONG
bool Extractor::extract(std::size_t , std::vector<long>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<long>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<long>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
#endif
bool Extractor::extract(std::size_t , std::vector<bool>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<bool>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<bool>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<float>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<float>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<float>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<double>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<double>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<double>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<char>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<char>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<char>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<std::string>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<std::string>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<std::string>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<BLOB>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<BLOB>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<BLOB>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<CLOB>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<CLOB>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<CLOB>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<DateTime>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<DateTime>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<DateTime>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Date>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Date>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Date>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Time>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Time>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Time>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Any>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Any>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Any>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Dynamic::Var>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Dynamic::Var>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Dynamic::Var>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,72 @@
//
// PostgreSQLException.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: PostgreSQLException
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
PostgreSQLException::PostgreSQLException(const std::string& aMessage):
Poco::Data::DataException(std::string("[PostgreSQL]: ") + aMessage)
{
}
PostgreSQLException::PostgreSQLException(const PostgreSQLException& anException):
Poco::Data::DataException(anException)
{
}
PostgreSQLException::~PostgreSQLException() throw()
{
}
//
// ConnectionException
//
ConnectionException::ConnectionException(const std::string& aMessage):
PostgreSQLException(aMessage)
{
}
//
// TransactionException
//
TransactionException::TransactionException(const std::string& aMessage):
ConnectionException(aMessage)
{
}
//
// StatementException
//
StatementException::StatementException(const std::string& aMessage):
PostgreSQLException(aMessage)
{
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,169 @@
//
// PostgreSQLStatementImpl.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: PostgreSQLStatementImpl
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/PostgreSQLStatementImpl.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
PostgreSQLStatementImpl::PostgreSQLStatementImpl(SessionImpl& aSessionImpl):
Poco::Data::StatementImpl(aSessionImpl),
_statementExecutor(aSessionImpl.handle()),
_pBinder(new Binder),
_pExtractor(new Extractor (_statementExecutor)),
_hasNext(NEXT_DONTKNOW)
{
}
PostgreSQLStatementImpl::~PostgreSQLStatementImpl()
{
}
std::size_t PostgreSQLStatementImpl::columnsReturned() const
{
return _statementExecutor.columnsReturned();
}
int PostgreSQLStatementImpl::affectedRowCount() const
{
return (int)_statementExecutor.getAffectedRowCount();
}
const MetaColumn& PostgreSQLStatementImpl::metaColumn(std::size_t aPosition) const
{
return _statementExecutor.metaColumn(aPosition);
}
bool PostgreSQLStatementImpl::hasNext()
{
if (NEXT_DONTKNOW == _hasNext)
{
if (columnsReturned() == 0)
{
return false;
}
if (_statementExecutor.fetch())
{
_hasNext = NEXT_TRUE;
return true;
}
_hasNext = NEXT_FALSE;
return false;
}
else if (NEXT_TRUE == _hasNext)
{
return true;
}
return false;
}
std::size_t PostgreSQLStatementImpl::next()
{
if (! hasNext())
{
throw StatementException("No data received");
}
Poco::Data::AbstractExtractionVec::iterator it= extractions().begin();
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
std::size_t position = 0;
for (; it != itEnd; ++it)
{
(*it)->extract(position);
position += (*it)->numOfColumnsHandled();
}
_hasNext = NEXT_DONTKNOW;
return 1;
}
bool PostgreSQLStatementImpl::canBind() const
{
bool ret = false;
if ((_statementExecutor.state() >= StatementExecutor::STMT_COMPILED)
&& !bindings().empty())
{
ret = (*bindings().begin())->canBind();
}
return ret;
}
bool PostgreSQLStatementImpl::canCompile() const
{
return (_statementExecutor.state() < StatementExecutor::STMT_COMPILED);
}
void PostgreSQLStatementImpl::compileImpl()
{
_statementExecutor.prepare(toString());
}
void PostgreSQLStatementImpl::bindImpl()
{
Poco::Data::AbstractBindingVec& binds = bindings();
std::size_t position = 0;
Poco::Data::AbstractBindingVec::iterator it= binds.begin();
Poco::Data::AbstractBindingVec::iterator itEnd = binds.end();
for (; it != itEnd && (*it)->canBind(); ++it)
{
(*it)->bind(position);
position += (*it)->numOfColumnsHandled();
}
_pBinder->updateBindVectorToCurrentValues();
_statementExecutor.bindParams(_pBinder->bindVector());
_statementExecutor.execute();
_hasNext = NEXT_DONTKNOW;
}
Poco::Data::AbstractExtractor::Ptr PostgreSQLStatementImpl::extractor()
{
return _pExtractor;
}
Poco::Data::AbstractBinder::Ptr PostgreSQLStatementImpl::binder()
{
return _pBinder;
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,107 @@
//
// PostgreSQLTypes.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: PostgreSQLTypes
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
Poco::Data::MetaColumn::ColumnDataType oidToColumnDataType(const Oid anOID)
{
Poco::Data::MetaColumn::ColumnDataType cdt = Poco::Data::MetaColumn::FDT_UNKNOWN;
switch (anOID)
{
// bool
case BOOLOID:
cdt = Poco::Data::MetaColumn::FDT_BOOL;
break;
// integers
case INT2OID:
cdt = Poco::Data::MetaColumn::FDT_INT16;
break;
case INT4OID:
cdt = Poco::Data::MetaColumn::FDT_INT32;
break;
case INT8OID:
cdt = Poco::Data::MetaColumn::FDT_INT64;
break;
// floating point
case FLOAT8OID:
cdt = Poco::Data::MetaColumn::FDT_DOUBLE;
break;
case FLOAT4OID:
// cdt = Poco::Data::MetaColumn::FDT_FLOAT; This a bug in Poco::Data:: as a 4 byte "float" can't be cast/ugraded to an 8 byte "double"
cdt = Poco::Data::MetaColumn::FDT_DOUBLE;
break;
case NUMERICOID:
cdt = Poco::Data::MetaColumn::FDT_DOUBLE;
break;
// character strings
case CHAROID:
cdt = Poco::Data::MetaColumn::FDT_STRING;
break;
case BPCHAROID:
cdt = Poco::Data::MetaColumn::FDT_STRING;
break;
case VARCHAROID:
cdt = Poco::Data::MetaColumn::FDT_STRING;
break;
// BLOB, CLOB
case BYTEAOID:
cdt = Poco::Data::MetaColumn::FDT_BLOB;
break;
case TEXTOID:
cdt = Poco::Data::MetaColumn::FDT_CLOB;
break;
// date
case DATEOID:
cdt = Poco::Data::MetaColumn::FDT_DATE;
break;
// time
case TIMEOID:
cdt = Poco::Data::MetaColumn::FDT_TIME;
break;
case TIMETZOID:
cdt = Poco::Data::MetaColumn::FDT_TIME;
break;
//timestamp
case TIMESTAMPOID:
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
break;
case TIMESTAMPZOID:
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
break;
// everything else is a string
default:
cdt = Poco::Data::MetaColumn::FDT_STRING;
break;
}
return cdt;
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,563 @@
//
// SessionHandle.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: SessionHandle
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/SessionHandle.h"
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/Session.h"
#include "Poco/NumberFormatter.h"
#define POCO_POSTGRESQL_VERSION_NUMBER ((NDB_VERSION_MAJOR<<16) | (NDB_VERSION_MINOR<<8) | (NDB_VERSION_BUILD&0xFF))
namespace Poco {
namespace Data {
namespace PostgreSQL {
//const std::string SessionHandle::POSTGRESQL_READ_UNCOMMITTED = "READ UNCOMMITTED";
const std::string SessionHandle::POSTGRESQL_READ_COMMITTED = "READ COMMITTED";
const std::string SessionHandle::POSTGRESQL_REPEATABLE_READ = "REPEATABLE READ";
const std::string SessionHandle::POSTGRESQL_SERIALIZABLE = "SERIALIZABLE";
SessionHandle::SessionHandle():
_pConnection(0),
_inTransaction(false),
_isAutoCommit(true),
_isAsynchronousCommit(false),
_tranactionIsolationLevel(Session::TRANSACTION_READ_COMMITTED)
{
}
SessionHandle::~SessionHandle()
{
try
{
disconnect();
}
catch (...)
{
}
}
bool SessionHandle::isConnected() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
return isConnectedNoLock();
}
bool SessionHandle::isConnectedNoLock() const
{
// DO NOT ACQUIRE THE MUTEX IN PRIVATE METHODS
if (_pConnection && PQstatus(_pConnection) == CONNECTION_OK)
{
return true;
}
return false;
}
void SessionHandle::connect(const std::string& aConnectionString)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (isConnectedNoLock())
{
throw ConnectionFailedException("Already Connected");
}
_pConnection = PQconnectdb(aConnectionString.c_str());
if (! isConnectedNoLock())
{
throw ConnectionFailedException(std::string("Connection Error: ") + lastErrorNoLock());
}
_connectionString = aConnectionString;
}
void SessionHandle::connect(const char* aConnectionString)
{
connect(std::string(aConnectionString));
}
void SessionHandle::connect(const char* aHost, const char* aUser, const char* aPassword,
const char* aDatabase, unsigned short aPort, unsigned int aConnectionTimeout)
{
std::string connectionString;
connectionString.append("host=");
connectionString.append(aHost);
connectionString.append(" ");
connectionString.append("user=");
connectionString.append(aUser);
connectionString.append(" ");
connectionString.append("password=");
connectionString.append(aPassword);
connectionString.append(" ");
connectionString.append("dbname=");
connectionString.append(aDatabase);
connectionString.append(" ");
connectionString.append("port=");
Poco::NumberFormatter::append(connectionString, aPort);
connectionString.append(" ");
connectionString.append("connect_timeout=");
Poco::NumberFormatter::append(connectionString, aConnectionTimeout);
connect(connectionString);
}
void SessionHandle::disconnect()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (isConnectedNoLock())
{
PQfinish(_pConnection);
_pConnection = 0;
_connectionString = std::string();
_inTransaction= false;
_isAutoCommit = true;
_isAsynchronousCommit = false;
_tranactionIsolationLevel = Session::TRANSACTION_READ_COMMITTED;
}
}
// TODO: Figure out what happens if a connection is reset with a pending transaction
bool SessionHandle::reset()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (_pConnection)
{
PQreset(_pConnection);
}
if (isConnectedNoLock())
{
return true;
}
return false;
}
std::string SessionHandle::lastError() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
return std::string();
}
return lastErrorNoLock();
}
std::string SessionHandle::lastErrorNoLock() const
{
// DO NOT ACQUIRE THE MUTEX IN PRIVATE METHODS
std::string lastErrorString (0 != _pConnection ? PQerrorMessage(_pConnection) : "not connected");
return lastErrorString;
}
void SessionHandle::startTransaction()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
if (_inTransaction)
{
return; // NO-OP
}
PGresult* pPQResult = PQexec(_pConnection, "BEGIN");
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("BEGIN statement failed:: ") + lastErrorNoLock());
}
_inTransaction = true;
}
void SessionHandle::commit()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
PGresult* pPQResult = PQexec(_pConnection, "COMMIT");
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("COMMIT statement failed:: ") + lastErrorNoLock());
}
_inTransaction = false;
deallocateStoredPreparedStatements();
}
void SessionHandle::rollback()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
PGresult* pPQResult = PQexec(_pConnection, "ROLLBACK");
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("ROLLBACK statement failed:: ") + lastErrorNoLock());
}
_inTransaction = false;
deallocateStoredPreparedStatements();
}
void SessionHandle::setAutoCommit(bool aShouldAutoCommit)
{
if (aShouldAutoCommit == _isAutoCommit)
{
return;
}
if (aShouldAutoCommit)
{
commit(); // end any in process transaction
}
else
{
startTransaction(); // start a new transaction
}
_isAutoCommit = aShouldAutoCommit;
}
void SessionHandle::setAsynchronousCommit(bool aShouldAsynchronousCommit)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
if (aShouldAsynchronousCommit == _isAsynchronousCommit)
{
return;
}
PGresult* pPQResult = PQexec(_pConnection, aShouldAsynchronousCommit ? "SET SYNCHRONOUS COMMIT TO OFF" : "SET SYNCHRONOUS COMMIT TO ON");
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("SET SYNCHRONUS COMMIT statement failed:: ") + lastErrorNoLock());
}
_isAsynchronousCommit = aShouldAsynchronousCommit;
}
void SessionHandle::cancel()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
PGcancel* ptrPGCancel = PQgetCancel(_pConnection);
PGCancelFree cancelFreer(ptrPGCancel);
PQcancel(ptrPGCancel, 0, 0); // no error buffer
}
void SessionHandle::setTransactionIsolation(Poco::UInt32 aTI)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
if (aTI == _tranactionIsolationLevel)
{
return;
}
if (! hasTransactionIsolation(aTI))
{
throw Poco::InvalidArgumentException("setTransactionIsolation()");
}
std::string isolationLevel;
switch (aTI)
{
case Session::TRANSACTION_READ_COMMITTED:
isolationLevel = POSTGRESQL_READ_COMMITTED; break;
case Session::TRANSACTION_REPEATABLE_READ:
isolationLevel = POSTGRESQL_REPEATABLE_READ; break;
case Session::TRANSACTION_SERIALIZABLE:
isolationLevel = POSTGRESQL_SERIALIZABLE; break;
}
PGresult* pPQResult = PQexec(_pConnection, Poco::format("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL %s", isolationLevel).c_str());
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("set transaction isolation statement failed: ") + lastErrorNoLock());
}
_tranactionIsolationLevel = aTI;
}
Poco::UInt32 SessionHandle::transactionIsolation()
{
return _tranactionIsolationLevel;
}
bool SessionHandle::hasTransactionIsolation(Poco::UInt32 aTI)
{
return Session::TRANSACTION_READ_COMMITTED == aTI
|| Session::TRANSACTION_REPEATABLE_READ == aTI
|| Session::TRANSACTION_SERIALIZABLE == aTI;
}
void SessionHandle::deallocatePreparedStatement(const std::string& aPreparedStatementToDeAllocate)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
if (! _inTransaction)
{
deallocatePreparedStatementNoLock(aPreparedStatementToDeAllocate);
}
else
{
try
{
_preparedStatementsToBeDeallocated.push_back(aPreparedStatementToDeAllocate);
}
catch (std::bad_alloc&)
{
}
}
}
void SessionHandle::deallocatePreparedStatementNoLock(const std::string& aPreparedStatementToDeAllocate)
{
PGresult* pPQResult = PQexec(_pConnection, (std::string("DEALLOCATE ") + aPreparedStatementToDeAllocate).c_str());
PQResultClear resultClearer(pPQResult);
if (PQresultStatus(pPQResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("DEALLOCATE statement failed: ") + lastErrorNoLock());
}
}
void SessionHandle::deallocateStoredPreparedStatements()
{
// DO NOT ACQUIRE THE MUTEX IN PRIVATE METHODS
while (! _preparedStatementsToBeDeallocated.empty())
{
deallocatePreparedStatementNoLock(_preparedStatementsToBeDeallocated.back());
_preparedStatementsToBeDeallocated.pop_back();
}
}
int SessionHandle::serverVersion() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
return PQserverVersion(_pConnection);
}
int SessionHandle::serverProcessID() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
return PQbackendPID(_pConnection);
}
int SessionHandle::protocoVersion() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
return PQprotocolVersion(_pConnection);
}
std::string SessionHandle::clientEncoding() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
{
throw NotConnectedException();
}
return pg_encoding_to_char(PQclientEncoding(_pConnection));
}
int SessionHandle::libpqVersion() const
{
return PQlibVersion();
}
SessionParametersMap SessionHandle::setConnectionInfoParameters(PQconninfoOption* pConnInfOpt)
{
SessionParametersMap sessionParametersMap;
while (0 != pConnInfOpt->keyword)
{
try
{
std::string keyword = pConnInfOpt->keyword ? pConnInfOpt->keyword : std::string();
std::string environmentVariableVersion = pConnInfOpt->envvar ? pConnInfOpt->envvar : std::string();
std::string compiledVersion = pConnInfOpt->compiled ? pConnInfOpt->compiled : std::string();
std::string currentValue = pConnInfOpt->val ? pConnInfOpt->val : std::string();
std::string dialogLabel = pConnInfOpt->label? pConnInfOpt->label: std::string();
std::string dialogDisplayCharacter = pConnInfOpt->dispchar ? pConnInfOpt->dispchar : std::string();
int dialogDisplaysize = pConnInfOpt->dispsize;
SessionParameters connParams(keyword, environmentVariableVersion, compiledVersion,
currentValue, dialogLabel, dialogDisplayCharacter, dialogDisplaysize);
sessionParametersMap.insert(SessionParametersMap::value_type(connParams.keyword(), connParams));
}
catch (std::bad_alloc&)
{
}
++pConnInfOpt;
}
return sessionParametersMap;
}
SessionParametersMap SessionHandle::connectionDefaultParameters()
{
PQconninfoOption* ptrConnInfoOptions = PQconndefaults();
PQConnectionInfoOptionsFree connectionOptionsFreeer(ptrConnInfoOptions);
return setConnectionInfoParameters(ptrConnInfoOptions);
}
SessionParametersMap SessionHandle::connectionParameters() const
{
if (! isConnected())
{
throw NotConnectedException();
}
PQconninfoOption* ptrConnInfoOptions = 0;
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
ptrConnInfoOptions = PQconninfo(_pConnection);
}
PQConnectionInfoOptionsFree connectionOptionsFreeer(ptrConnInfoOptions);
return setConnectionInfoParameters(ptrConnInfoOptions);
}
} } } // Poco::Data::PostgreSQL

View File

@@ -0,0 +1,246 @@
//
// SessionImpl.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: SessionImpl
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/SessionImpl.h"
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
#include "Poco/Data/PostgreSQL/PostgreSQLStatementImpl.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/Session.h"
#include "Poco/NumberParser.h"
#include "Poco/String.h"
#include <map>
namespace
{
std::string copyStripped(std::string::const_iterator aFromStringCItr, std::string::const_iterator aToStringCItr)
{
// skip leading spaces
while ((aFromStringCItr != aToStringCItr) && isspace(*aFromStringCItr)) aFromStringCItr++;
// skip trailing spaces
while ((aFromStringCItr != aToStringCItr) && isspace(*(aToStringCItr - 1))) aToStringCItr--;
return std::string(aFromStringCItr, aToStringCItr);
}
std::string createConnectionStringFromOptionsMap(const std::map <std::string, std::string> anOptionsMap)
{
std::string connectionString;
for (std::map<std::string, std::string>::const_iterator citr = anOptionsMap.begin(); citr != anOptionsMap.end(); ++citr)
{
connectionString.append(citr->first);
connectionString.append("=");
connectionString.append(citr->second);
connectionString.append(" ");
}
return connectionString;
}
}
namespace Poco {
namespace Data {
namespace PostgreSQL {
SessionImpl::SessionImpl(const std::string& aConnectionString, std::size_t aLoginTimeout):
Poco::Data::AbstractSessionImpl<SessionImpl>(aConnectionString, aLoginTimeout)
{
setProperty("handle", static_cast<SessionHandle*>(&_sessionHandle));
setConnectionTimeout(CONNECTION_TIMEOUT_DEFAULT);
open();
}
SessionImpl::~SessionImpl()
{
try
{
close();
}
catch (...)
{
}
}
void SessionImpl::setConnectionTimeout(std::size_t aTimeout)
{
_timeout = aTimeout;
}
void SessionImpl::open(const std::string& aConnectionString)
{
if (connectionString() != aConnectionString)
{
if (isConnected())
{
throw ConnectionException("Session already connected");
}
if (! aConnectionString.empty())
{
setConnectionString(aConnectionString);
}
}
poco_assert_dbg (! connectionString().empty());
unsigned int timeout = static_cast<unsigned int>(getLoginTimeout());
// PostgreSQL connections can use environment variables for connection parameters.
// As such it is not an error if they are not part of the connection string
std::map <std::string, std::string> optionsMap;
// Default values
optionsMap["connect_timeout"] = Poco::NumberFormatter::format(timeout);
const std::string& connString = connectionString();
for (std::string::const_iterator start = connString.begin();;)
{
std::string::const_iterator finish = std::find(start, connString.end(), ' '); // space is the separator between keyword=value pairs
std::string::const_iterator middle = std::find(start, finish, '=');
if (middle == finish)
{
throw PostgreSQLException("create session: bad connection string format, cannot find '='");
}
optionsMap[ copyStripped(start, middle) ] = copyStripped(middle + 1, finish);
if ((finish == connString.end()) || (finish + 1 == connString.end())) break;
start = finish + 1;
}
// Real connect
_sessionHandle.connect(createConnectionStringFromOptionsMap(optionsMap));
addFeature("autoCommit",
&SessionImpl::setAutoCommit,
&SessionImpl::isAutoCommit);
addFeature("asynchronousCommit",
&SessionImpl::setAutoCommit,
&SessionImpl::isAutoCommit);
}
void SessionImpl::close()
{
if (isConnected())
{
_sessionHandle.disconnect();
}
}
void SessionImpl::reset()
{
}
bool SessionImpl::isConnected() const
{
return _sessionHandle.isConnected();
}
StatementImpl::Ptr SessionImpl::createStatementImpl()
{
return new PostgreSQLStatementImpl (*this);
}
bool SessionImpl::isTransaction() const
{
return _sessionHandle.isTransaction();
}
void SessionImpl::begin()
{
if (isTransaction())
{
throw Poco::InvalidAccessException("Already in transaction.");
}
_sessionHandle.startTransaction();
}
void SessionImpl::commit()
{
// Not an error to issue a COMMIT without a preceding BEGIN
_sessionHandle.commit();
}
void SessionImpl::rollback()
{
// Not an error to issue a ROLLBACK without a preceding BEGIN
_sessionHandle.rollback();
}
void SessionImpl::setAutoCommit(const std::string&, bool aValue)
{
_sessionHandle.setAutoCommit(aValue);
}
bool SessionImpl::isAutoCommit(const std::string&) const
{
return _sessionHandle.isAutoCommit();
}
void SessionImpl::setAsynchronousCommit(const std::string&, bool aValue)
{
_sessionHandle.setAsynchronousCommit(aValue);
}
bool SessionImpl::isAsynchronousCommit(const std::string&) const
{
return _sessionHandle.isAsynchronousCommit();
}
void SessionImpl::setTransactionIsolation(Poco::UInt32 aTI)
{
return _sessionHandle.setTransactionIsolation(aTI);
}
Poco::UInt32 SessionImpl::getTransactionIsolation() const
{
return _sessionHandle.transactionIsolation();
}
bool SessionImpl::hasTransactionIsolation(Poco::UInt32 aTI) const
{
return _sessionHandle.hasTransactionIsolation(aTI);
}
} } } // namespace Poco::Data::PostgreSQL

View File

@@ -0,0 +1,414 @@
//
// StatementExecutor.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: StatementExecutor
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/StatementExecutor.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Format.h"
#include "Poco/UUID.h"
#include "Poco/UUIDGenerator.h"
#include "Poco/NumberParser.h"
#include "Poco/NumberParser.h"
#include "Poco/RegularExpression.h"
#include <algorithm>
#include <set>
namespace
{
std::size_t countOfPlaceHoldersInSQLStatement(const std::string& aSQLStatement)
{
// Find unique placeholders.
// Unique placeholders allow the same placeholder to be used multiple times in the same statement.
// NON C++11 implementation
//if (aSQLStatement.empty())
//{
//return 0;
//}
// set to hold the unique placeholders ($1, $2, $3, etc.).
// A set is used because the same placeholder can be used muliple times
std::set<std::string> placeholderSet;
Poco::RegularExpression placeholderRE("[$][0-9]+");
Poco::RegularExpression::Match match = { 0 , 0 }; // Match is a struct, not a class :-(
std::size_t startingPosition = 0;
while (match.offset != std::string::npos)
{
try
{
if (placeholderRE.match(aSQLStatement, startingPosition, match))
{
placeholderSet.insert(aSQLStatement.substr(match.offset, match.length));
startingPosition = match.offset + match.length;
}
}
catch (Poco::RegularExpressionException &)
{
break;
}
}
return placeholderSet.size();
}
} // namespace
namespace Poco {
namespace Data {
namespace PostgreSQL {
StatementExecutor::StatementExecutor(SessionHandle& sessionHandle):
_sessionHandle(sessionHandle),
_state(STMT_INITED),
_pResultHandle(0),
_countPlaceholdersInSQLStatement(0),
_currentRow(0),
_affectedRowCount(0)
{
}
StatementExecutor::~StatementExecutor()
{
try
{
// remove the prepared statement from the session
if(_sessionHandle.isConnected() && _state >= STMT_COMPILED)
{
_sessionHandle.deallocatePreparedStatement(_preparedStatementName);
}
PQResultClear resultClearer(_pResultHandle);
}
catch (...)
{
}
}
StatementExecutor::State StatementExecutor::state() const
{
return _state;
}
void StatementExecutor::prepare(const std::string& aSQLStatement)
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (_state >= STMT_COMPILED) return;
// clear out the metadata. One way or another it is now obsolete.
_countPlaceholdersInSQLStatement = 0;
_SQLStatement= std::string();
_preparedStatementName = std::string();
_resultColumns.clear();
// clear out any result data. One way or another it is now obsolete.
clearResults();
// prepare parameters for the call to PQprepare
const char* ptrCSQLStatement = aSQLStatement.c_str();
std::size_t countPlaceholdersInSQLStatement = countOfPlaceHoldersInSQLStatement(aSQLStatement);
Poco::UUIDGenerator& generator = Poco::UUIDGenerator::defaultGenerator();
Poco::UUID uuid(generator.create()); // time based
std::string statementName = uuid.toString();
statementName.insert(0, 1, 'p'); // prepared statement names can't start with a number
std::replace(statementName.begin(), statementName.end(), '-', 'p'); // PostgreSQL doesn't like dashes in prepared statement names
const char* pStatementName = statementName.c_str();
PGresult* ptrPGResult = 0;
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionHandle.mutex());
// prepare the statement - temporary PGresult returned
ptrPGResult = PQprepare(_sessionHandle, pStatementName, ptrCSQLStatement, (int)countPlaceholdersInSQLStatement, 0);
}
{
// setup to clear the result from PQprepare
PQResultClear resultClearer(ptrPGResult);
if (!ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("postgresql_stmt_prepare error: ") + PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement);
}
}
// Determine what the structure of a statement result will look like
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionHandle.mutex());
ptrPGResult = PQdescribePrepared(_sessionHandle, pStatementName);
}
{
PQResultClear resultClearer(ptrPGResult);
if (! ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("postgresql_stmt_describe error: ") +
PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement);
}
// remember the structure of the statement result
int fieldCount = PQnfields(ptrPGResult);
if (fieldCount < 0) fieldCount = 0;
for (int i = 0; i < fieldCount; ++i)
{
_resultColumns.push_back(MetaColumn(i, PQfname(ptrPGResult, i),
oidToColumnDataType(PQftype(ptrPGResult, i)), 0, 0, true));
}
}
_SQLStatement = aSQLStatement;
_preparedStatementName = statementName;
_countPlaceholdersInSQLStatement = countPlaceholdersInSQLStatement;
_state = STMT_COMPILED; // must be last
}
void StatementExecutor::bindParams(const InputParameterVector& anInputParameterVector)
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (_state < STMT_COMPILED) throw StatementException("Statement is not compiled yet");
if (anInputParameterVector.size() != _countPlaceholdersInSQLStatement)
{
throw StatementException(std::string("incorrect bind parameters count for SQL Statement: ") +
_SQLStatement);
}
// Just record the input vector for later execution
_inputParameterVector = anInputParameterVector;
}
void StatementExecutor::execute()
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (_state < STMT_COMPILED) throw StatementException("Statement is not compiled yet");
if (_countPlaceholdersInSQLStatement != 0 &&
_inputParameterVector.size() != _countPlaceholdersInSQLStatement)
{
throw StatementException("Count of Parameters in Statement different than supplied parameters");
}
// "transmogrify" the _inputParameterVector to the C format required by PQexecPrepared
/* - from example
const char *paramValues[1];
int paramLengths[1];
int paramFormats[1];
*/
std::vector<const char *> pParameterVector;
std::vector<int> parameterLengthVector;
std::vector<int> parameterFormatVector;
InputParameterVector::const_iterator cItr = _inputParameterVector.begin();
InputParameterVector::const_iterator cItrEnd = _inputParameterVector.end();
for (; cItr != cItrEnd; ++cItr)
{
try
{
pParameterVector.push_back (static_cast<const char*>(cItr->pInternalRepresentation()));
parameterLengthVector.push_back((int)cItr->size());
parameterFormatVector.push_back((int)cItr->isBinary() ? 1 : 0);
}
catch (std::bad_alloc&)
{
throw StatementException("Memory Allocation Error");
}
}
// clear out any result data. One way or another it is now obsolete.
clearResults();
PGresult* ptrPGResult = 0;
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionHandle.mutex());
ptrPGResult = PQexecPrepared (_sessionHandle,
_preparedStatementName.c_str(), (int)_countPlaceholdersInSQLStatement,
_inputParameterVector.size() != 0 ? &pParameterVector[ 0 ] : 0,
_inputParameterVector.size() != 0 ? &parameterLengthVector[ 0 ] : 0,
_inputParameterVector.size() != 0 ? &parameterFormatVector[ 0 ] : 0, 0);
}
// Don't setup to auto clear the result (ptrPGResult). It is required to retrieve the results later.
if (!ptrPGResult || (PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK &&
PQresultStatus(ptrPGResult) != PGRES_TUPLES_OK))
{
PQResultClear resultClearer(ptrPGResult);
const char* pSeverity = PQresultErrorField(ptrPGResult, PG_DIAG_SEVERITY);
const char* pSQLState = PQresultErrorField(ptrPGResult, PG_DIAG_SQLSTATE);
const char* pDetail = PQresultErrorField(ptrPGResult, PG_DIAG_MESSAGE_DETAIL);
const char* pHint = PQresultErrorField(ptrPGResult, PG_DIAG_MESSAGE_HINT);
const char* pConstraint = PQresultErrorField(ptrPGResult, PG_DIAG_CONSTRAINT_NAME);
throw StatementException(std::string("postgresql_stmt_execute error: ")
+ PQresultErrorMessage (ptrPGResult)
+ " Severity: " + (pSeverity ? pSeverity : "N/A")
+ " State: " + (pSQLState ? pSQLState : "N/A")
+ " Detail: " + (pDetail ? pDetail : "N/A")
+ " Hint: " + (pHint ? pHint : "N/A")
+ " Constraint: " + (pConstraint ? pConstraint : "N/A"));
}
_pResultHandle = ptrPGResult;
// are there any results?
int affectedRowCount = 0;
if (PGRES_TUPLES_OK == PQresultStatus(_pResultHandle))
{
affectedRowCount = PQntuples(_pResultHandle);
if (affectedRowCount >= 0)
{
_affectedRowCount = static_cast<std::size_t>(affectedRowCount);
}
}
else
{ // non Select DML statments also have an affected row count.
// unfortunately PostgreSQL offers up this count as a char * - go figure!
const char * pNonSelectAffectedRowCountString = PQcmdTuples(_pResultHandle);
if (0 != pNonSelectAffectedRowCountString)
{
if ( Poco::NumberParser::tryParse(pNonSelectAffectedRowCountString, affectedRowCount)
&& affectedRowCount >= 0
)
{
_affectedRowCount = static_cast<std::size_t>(affectedRowCount);
_currentRow = _affectedRowCount; // no fetching on these statements!
}
}
}
_state = STMT_EXECUTED;
}
bool StatementExecutor::fetch()
{
if (! _sessionHandle.isConnected())
{
throw NotConnectedException();
}
if (_state < STMT_EXECUTED)
{
throw StatementException("Statement is not yet executed");
}
std::size_t countColumns = columnsReturned();
// first time to fetch?
if (0 == _outputParameterVector.size())
{
// setup a output vector for the results
_outputParameterVector.resize(countColumns);
}
// already retrieved last row?
if (_currentRow == getAffectedRowCount())
{
return false;
}
if (0 == countColumns || PGRES_TUPLES_OK != PQresultStatus(_pResultHandle))
{
return false;
}
for (int i = 0; i < countColumns; ++i)
{
int fieldLength = PQgetlength(_pResultHandle, static_cast<int> (_currentRow), static_cast<int> (i));
Oid columnInternalDataType = PQftype(_pResultHandle, i); // Oid of column
_outputParameterVector.at(i).setValues(oidToColumnDataType(columnInternalDataType), // Poco::Data::MetaData version of the Column Data Type
columnInternalDataType, // Postgres Version
_currentRow, // the row number of the result
PQgetvalue(_pResultHandle, (int)_currentRow, i), // a pointer to the data
(-1 == fieldLength ? 0 : fieldLength), // the length of the data returned
PQgetisnull(_pResultHandle, (int)_currentRow, i) == 1 ? true : false); // is the column value null?
}
++_currentRow;
return true;
}
std::size_t StatementExecutor::getAffectedRowCount() const
{
return _affectedRowCount;
}
std::size_t StatementExecutor::columnsReturned() const
{
return static_cast<std::size_t> (_resultColumns.size());
}
const MetaColumn& StatementExecutor::metaColumn(std::size_t aPosition) const
{
if (aPosition >= columnsReturned())
{
throw StatementException("Invalid column number for metaColumn");
}
return _resultColumns.at(aPosition);
}
const OutputParameter& StatementExecutor::resultColumn(std::size_t aPosition) const
{
if (aPosition >= columnsReturned())
{
throw StatementException("Invalid column number for resultColumn");
}
return _outputParameterVector.at(aPosition);
}
void StatementExecutor::clearResults()
{
// clear out any old result first
{
PQResultClear resultClearer(_pResultHandle);
}
_outputParameterVector.clear();
_affectedRowCount = 0;
_currentRow = 0;
}
} } } // Poco::Data::PostgreSQL

View File

@@ -0,0 +1,92 @@
//
// Utility.cpp
//
// Library: Data/PostgreSQL
// Package: PostgreSQL
// Module: Utility
//
// Implementation of Utility
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/PostgreSQL/Utility.h"
#include "Poco/Data/PostgreSQL/SessionImpl.h"
#include "Poco/NumberFormatter.h"
namespace Poco {
namespace Data {
namespace PostgreSQL {
std::string Utility::serverInfo(SessionHandle* aHandlePtr)
{
std::string srvrInfo = "Process ID: ";
srvrInfo.append(Poco::NumberFormatter::format(aHandlePtr->serverProcessID()));
srvrInfo.append(" Protocol Version: ");
srvrInfo.append(Poco::NumberFormatter::format(aHandlePtr->protocoVersion()));
return srvrInfo;
}
std::string Utility::serverInfo(Session& aSession)
{
return serverInfo(handle(aSession));
}
int Utility::serverVersion(SessionHandle* aHandlePtr)
{
return aHandlePtr->serverVersion();
}
int Utility::serverVersion(Session& aSession)
{
return serverVersion(handle(aSession));
}
std::string Utility::hostInfo(SessionHandle* aHandlePtr)
{
SessionParametersMap parametersMap = aHandlePtr->connectionParameters();
SessionParametersMap::const_iterator cItr = parametersMap.find("host");
if (parametersMap.end() == cItr)
{
return std::string();
}
return cItr->second.currentValue();
}
std::string Utility::hostInfo(Session& aSession)
{
return hostInfo(handle(aSession));
}
std::string Utility::sessionEncoding(SessionHandle* aHandlePtr)
{
return aHandlePtr->clientEncoding();
}
std::string Utility::sessionEncoding(Poco::Data::Session& aSession)
{
return sessionEncoding(handle(aSession));
}
} } } // namespace Poco::Data::PostgreSQL