mirror of
https://github.com/KingDuckZ/dindexer.git
synced 2024-11-25 00:53:43 +00:00
Clarify PGresult ownership and lifetime.
This commit is contained in:
parent
ff926d85a4
commit
43bec4711e
4 changed files with 51 additions and 49 deletions
|
@ -33,7 +33,7 @@ namespace pq {
|
|||
public:
|
||||
typedef boost::transform_iterator<boost::function<std::string(std::size_t)>, boost::counting_iterator<std::size_t>> const_iterator;
|
||||
|
||||
Row ( const ResultInfo& parResult, std::size_t parRow );
|
||||
Row ( const ResultInfo* parResult, std::size_t parRow );
|
||||
Row ( const Row& ) = delete;
|
||||
Row ( Row&& parOther );
|
||||
~Row ( void ) noexcept;
|
||||
|
@ -60,7 +60,7 @@ namespace pq {
|
|||
public:
|
||||
typedef boost::transform_iterator<boost::function<Row(std::size_t)>, boost::counting_iterator<std::size_t>> const_iterator;
|
||||
|
||||
explicit ResultSet ( ResultInfo& parResult );
|
||||
explicit ResultSet ( ResultInfo&& parResult );
|
||||
ResultSet ( const ResultSet& ) = delete;
|
||||
ResultSet ( ResultSet&& parOther );
|
||||
~ResultSet ( void ) noexcept;
|
||||
|
|
|
@ -173,29 +173,22 @@ namespace pq {
|
|||
}
|
||||
|
||||
ResultSet Connection::query (const std::string& parQuery) {
|
||||
//TODO: sanitize input string
|
||||
auto res = PQexec(m_localData->connection, parQuery.c_str());
|
||||
if (not res)
|
||||
ResultInfo info(PQexec(m_localData->connection, parQuery.c_str()));
|
||||
if (not info.result)
|
||||
throw DatabaseException("Error running query", "Error allocating result object", __FILE__, __LINE__);
|
||||
const int ress = PQresultStatus(res);
|
||||
const int ress = PQresultStatus(info.result.get());
|
||||
if (ress != PGRES_TUPLES_OK && ress != PGRES_COMMAND_OK) {
|
||||
PQclear(res);
|
||||
throw DatabaseException("Error running query", error_message(), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
ResultInfo info;
|
||||
info.result = res;
|
||||
info.column_mappings = nullptr;
|
||||
return ResultSet(info);
|
||||
return ResultSet(std::move(info));
|
||||
}
|
||||
|
||||
void Connection::query_void (const std::string& parQuery) {
|
||||
//TODO: sanitize input string
|
||||
auto deleter = [](PGresult* r) { PQclear(r); };
|
||||
std::unique_ptr<PGresult, decltype(deleter)> res(PQexec(m_localData->connection, parQuery.c_str()), deleter);
|
||||
if (not res)
|
||||
ResultInfo info(PQexec(m_localData->connection, parQuery.c_str()));
|
||||
if (not info.result)
|
||||
throw DatabaseException("Error running query", "Error allocating result object", __FILE__, __LINE__);
|
||||
const int ress = PQresultStatus(res.get());
|
||||
const int ress = PQresultStatus(info.result.get());
|
||||
if (ress != PGRES_TUPLES_OK && ress != PGRES_COMMAND_OK) {
|
||||
throw DatabaseException("Error running query", error_message(), __FILE__, __LINE__);
|
||||
}
|
||||
|
@ -213,26 +206,22 @@ namespace pq {
|
|||
}
|
||||
|
||||
void Connection::query_void_params (const std::string& parQuery, PGParams& parParams) {
|
||||
auto deleter = [](PGresult* r) { PQclear(r); };
|
||||
using ResultPtr = std::unique_ptr<PGresult, decltype(deleter)>;
|
||||
|
||||
int result_format = 1;
|
||||
assert(parParams.get());
|
||||
auto res = ResultPtr(
|
||||
ResultInfo info(
|
||||
PQparamExec(
|
||||
m_localData->connection,
|
||||
parParams.get(),
|
||||
parQuery.c_str(),
|
||||
result_format
|
||||
),
|
||||
deleter
|
||||
)
|
||||
);
|
||||
if (not res) {
|
||||
if (not info.result) {
|
||||
std::ostringstream oss;
|
||||
oss << "Error allocating result object while running \"" << parQuery << "\": " << PQgeterror();
|
||||
throw DatabaseException("Error running query", oss.str(), __FILE__, __LINE__);
|
||||
}
|
||||
const int ress = PQresultStatus(res.get());
|
||||
const int ress = PQresultStatus(info.result.get());
|
||||
if (ress != PGRES_TUPLES_OK && ress != PGRES_COMMAND_OK) {
|
||||
throw DatabaseException("Error running query", error_message(), __FILE__, __LINE__);
|
||||
}
|
||||
|
|
|
@ -21,10 +21,34 @@
|
|||
#include <libpq-fe.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace pq {
|
||||
struct ResultInfo {
|
||||
PGresult* result;
|
||||
typedef std::unique_ptr<PGresult, void(*)(PGresult*)> PGResultPtr;
|
||||
|
||||
ResultInfo ( void ) :
|
||||
result(nullptr, &PQclear),
|
||||
column_mappings(nullptr)
|
||||
{
|
||||
}
|
||||
ResultInfo ( const ResultInfo& ) = delete;
|
||||
ResultInfo ( ResultInfo&& ) = default;
|
||||
explicit ResultInfo ( PGresult* parRes ) :
|
||||
result(parRes, &PQclear),
|
||||
column_mappings(nullptr)
|
||||
{
|
||||
}
|
||||
ResultInfo ( PGResultPtr&& parRes, const std::map<std::string, int>* parColMappings ) :
|
||||
result(std::move(parRes)),
|
||||
column_mappings(parColMappings)
|
||||
{
|
||||
}
|
||||
~ResultInfo ( void ) noexcept = default;
|
||||
ResultInfo& operator= ( const ResultInfo& ) = delete;
|
||||
ResultInfo& operator= ( ResultInfo&& ) = default;
|
||||
|
||||
PGResultPtr result;
|
||||
const std::map<std::string, int>* column_mappings;
|
||||
};
|
||||
} //namespace pq
|
||||
|
|
|
@ -44,17 +44,19 @@ namespace pq {
|
|||
};
|
||||
|
||||
struct ResultSet::LocalData {
|
||||
explicit LocalData ( PGresult* parResult ) :
|
||||
result(parResult)
|
||||
typedef ResultInfo::PGResultPtr PGResultPtr;
|
||||
|
||||
explicit LocalData ( PGResultPtr&& parResult ) :
|
||||
info(std::move(parResult), &columns)
|
||||
{
|
||||
}
|
||||
|
||||
PGresult* result;
|
||||
ResultInfo info;
|
||||
std::map<std::string, int> columns;
|
||||
};
|
||||
|
||||
Row::Row (const ResultInfo& parResult, std::size_t parRow) :
|
||||
m_localData(new LocalData(parResult.result, parRow, parResult.column_mappings, (parResult.column_mappings ? parResult.column_mappings->size() : 0)))
|
||||
Row::Row (const ResultInfo* parResult, std::size_t parRow) :
|
||||
m_localData(new LocalData(parResult->result.get(), parRow, parResult->column_mappings, (parResult->column_mappings ? parResult->column_mappings->size() : 0)))
|
||||
{
|
||||
assert(not m_localData->result or static_cast<std::size_t>(std::max(0, PQnfields(m_localData->result))) == m_localData->col_count);
|
||||
}
|
||||
|
@ -64,11 +66,6 @@ namespace pq {
|
|||
{
|
||||
}
|
||||
|
||||
//Row::Row (const Row& parOther) :
|
||||
// m_localData(new LocalData(parOther.m_localData->result, parOther.m_localData->row_index, parOther.m_localData->columns, parOther.m_localData->col_count))
|
||||
//{
|
||||
//}
|
||||
|
||||
Row::~Row() noexcept {
|
||||
}
|
||||
|
||||
|
@ -115,10 +112,10 @@ namespace pq {
|
|||
}
|
||||
|
||||
|
||||
ResultSet::ResultSet (ResultInfo& parResult) :
|
||||
m_localData(new LocalData(parResult.result))
|
||||
ResultSet::ResultSet (ResultInfo&& parResult) :
|
||||
m_localData(new LocalData(std::move(parResult.result)))
|
||||
{
|
||||
const auto result = m_localData->result;
|
||||
const auto result = m_localData->info.result.get();
|
||||
const int column_count = PQnfields(result);
|
||||
std::string col_name;
|
||||
for (int z = 0; z < column_count; ++z) {
|
||||
|
@ -132,26 +129,18 @@ namespace pq {
|
|||
}
|
||||
|
||||
ResultSet::~ResultSet() noexcept {
|
||||
if (m_localData->result) {
|
||||
PQclear(m_localData->result);
|
||||
m_localData->result = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Row ResultSet::operator[] (std::size_t parIndex) const {
|
||||
ResultInfo info;
|
||||
info.result = m_localData->result;
|
||||
info.column_mappings = &m_localData->columns;
|
||||
|
||||
if (parIndex >= size())
|
||||
throw DatabaseException("Out of range", "Column index " + boost::lexical_cast<std::string>(parIndex) + " is out of range (column count is " + boost::lexical_cast<std::string>(size()) + ')', __FILE__, __LINE__);
|
||||
|
||||
return Row(info, parIndex);
|
||||
return Row(&m_localData->info, parIndex);
|
||||
}
|
||||
|
||||
std::size_t ResultSet::size() const {
|
||||
assert(m_localData->result);
|
||||
const auto retval = PQntuples(m_localData->result);
|
||||
assert(m_localData->info.result);
|
||||
const auto retval = PQntuples(m_localData->info.result.get());
|
||||
assert(retval >= 0);
|
||||
return static_cast<std::size_t>(std::max(0, retval));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue