1
0
Fork 0
mirror of https://github.com/KingDuckZ/dindexer.git synced 2025-02-23 12:54:56 +00:00
dindexer/src/pq/resultset.cpp

177 lines
5.5 KiB
C++
Raw Normal View History

2015-11-11 02:01:37 +00:00
/* Copyright 2015, Michele Santullo
* This file is part of "dindexer".
*
* "dindexer" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "dindexer" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "dindexer". If not, see <http://www.gnu.org/licenses/>.
*/
#include "pq/resultset.hpp"
#include "pq/resultinfo.hpp"
#include "pq/databaseexception.hpp"
#include <libpq-fe.h>
#include <map>
#include <cassert>
#include <ciso646>
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <boost/bind.hpp>
namespace pq {
struct Row::LocalData {
LocalData ( const PGresult* parResult, std::size_t parRow, const std::map<std::string, int>* parCols, std::size_t parColCount ) :
result(parResult),
columns(parCols),
row_index(parRow),
col_count(parColCount)
{
assert((result and columns) or (not (result or columns)));
}
const PGresult* const result;
const std::map<std::string, int>* const columns;
const std::size_t row_index;
const std::size_t col_count;
};
struct ResultSet::LocalData {
explicit LocalData ( PGresult* parResult ) :
result(parResult)
{
}
PGresult* result;
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)))
{
assert(not m_localData->result or static_cast<std::size_t>(std::max(0, PQnfields(m_localData->result))) == m_localData->col_count);
}
Row::Row (Row&& parOther) :
m_localData(std::move(parOther.m_localData))
{
}
//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 {
}
std::string Row::operator[] (const std::string& parIndex) const {
assert(m_localData->columns);
const auto num_index_it = m_localData->columns->find(parIndex);
if (num_index_it == m_localData->columns->end())
throw DatabaseException("Error retrieving column", "Requested column \"" + parIndex + "\" doesn't exist", __FILE__, __LINE__);
const int num_index = num_index_it->second;
return PQgetvalue(m_localData->result, static_cast<int>(m_localData->row_index), num_index);
}
std::size_t Row::size() const {
return m_localData->col_count;
}
bool Row::empty() const {
return size() == 0;
}
std::string Row::operator[] (std::size_t parIndex) const {
if (parIndex >= m_localData->col_count) {
std::ostringstream oss;
oss << "Requested column at index " << parIndex << " is out of range (column count is " << m_localData->col_count << ')';
throw DatabaseException("Error retrieving column", oss.str(), __FILE__, __LINE__);
}
return PQgetvalue(m_localData->result, static_cast<int>(m_localData->row_index), static_cast<int>(parIndex));
}
Row::const_iterator Row::begin() const {
return boost::make_transform_iterator(
boost::counting_iterator<std::size_t>(0),
boost::bind(static_cast<std::string (Row::*)(std::size_t) const>(&Row::operator[]), this, _1)
);
}
Row::const_iterator Row::end() const {
return boost::make_transform_iterator(
boost::counting_iterator<std::size_t>(m_localData->col_count),
boost::bind(static_cast<std::string (Row::*)(std::size_t) const>(&Row::operator[]), this, _1)
);
}
ResultSet::ResultSet (ResultInfo& parResult) :
m_localData(new LocalData(parResult.result))
{
const auto result = m_localData->result;
const int column_count = PQnfields(result);
std::string col_name;
for (int z = 0; z < column_count; ++z) {
m_localData->columns[PQfname(result, z)] = z;
}
}
ResultSet::ResultSet (ResultSet&& parOther) :
m_localData(std::move(parOther.m_localData))
{
}
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);
}
std::size_t ResultSet::size() const {
assert(m_localData->result);
const auto retval = PQntuples(m_localData->result);
assert(retval >= 0);
return static_cast<std::size_t>(std::max(0, retval));
}
bool ResultSet::empty() const {
return size() == 0;
}
ResultSet::const_iterator ResultSet::begin() const {
return boost::make_transform_iterator(
boost::counting_iterator<std::size_t>(0),
boost::bind(static_cast<Row (ResultSet::*)(std::size_t) const>(&ResultSet::operator[]), this, _1)
);
}
ResultSet::const_iterator ResultSet::end() const {
return boost::make_transform_iterator(
boost::counting_iterator<std::size_t>(size()),
boost::bind(static_cast<Row (ResultSet::*)(std::size_t) const>(&ResultSet::operator[]), this, _1)
);
}
} //namespace pq