mirror of
https://github.com/KingDuckZ/dindexer.git
synced 2024-11-25 00:53:43 +00:00
Fix reading values from ResultSet/Row.
Send correct group_id to the db in a safer way.
This commit is contained in:
parent
9bb5689d48
commit
1532d3c083
4 changed files with 99 additions and 19 deletions
|
@ -44,6 +44,8 @@ namespace pq {
|
|||
std::string operator[] ( std::size_t parIndex ) const;
|
||||
Row& operator= ( const Row& ) = delete;
|
||||
Row& operator= ( Row&& ) = delete;
|
||||
bool is_null ( std::size_t parIndex ) const;
|
||||
bool is_null ( const std::string& parIndex ) const;
|
||||
|
||||
const_iterator begin ( void ) const;
|
||||
const_iterator end ( void ) const;
|
||||
|
@ -53,6 +55,8 @@ namespace pq {
|
|||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::string get_as_str_assume_valid ( int parIndex ) const;
|
||||
|
||||
std::unique_ptr<LocalData> m_localData;
|
||||
};
|
||||
|
||||
|
|
|
@ -196,7 +196,8 @@ namespace pq {
|
|||
}
|
||||
|
||||
ResultSet Connection::query_params (const std::string& parQuery, PGParams& parParams) {
|
||||
int result_format = 1;
|
||||
//TODO: make result_format parametric
|
||||
int result_format = 0;
|
||||
assert(parParams.get());
|
||||
ResultInfo info(
|
||||
PQparamExec(
|
||||
|
|
|
@ -25,8 +25,46 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/bind.hpp>
|
||||
#include "libpqtypes.h"
|
||||
|
||||
namespace pq {
|
||||
namespace {
|
||||
int cast_col_index_or_throw (std::size_t parIndex, std::size_t parCount, const char* parFile, int parLine) {
|
||||
if (parIndex >= parCount) {
|
||||
std::ostringstream oss;
|
||||
oss << "Requested column at index " << parIndex << " is out of range (column count is " << parCount << ')';
|
||||
throw DatabaseException("Error retrieving column", oss.str(), parFile, parLine);
|
||||
}
|
||||
return static_cast<int>(parIndex);
|
||||
}
|
||||
|
||||
int conv_col_index_or_throw (const std::string& parIndex, const std::map<std::string, int>& parCols, const char* parFile, int parLine) {
|
||||
const auto num_index_it = parCols.find(parIndex);
|
||||
if (parCols.end() == num_index_it) {
|
||||
throw DatabaseException("Error retrieving column", "Requested column \"" + parIndex + "\" doesn't exist", parFile, parLine);
|
||||
}
|
||||
|
||||
return num_index_it->second;
|
||||
}
|
||||
|
||||
std::string binary_to_string (const char* parValue, Oid parType, int parLength) {
|
||||
using boost::lexical_cast;
|
||||
|
||||
assert(parValue);
|
||||
assert(parLength > 0);
|
||||
|
||||
//TODO: use libpqtypes
|
||||
switch (parType) {
|
||||
case 21:
|
||||
return lexical_cast<std::string>(*reinterpret_cast<const uint16_t*>(parValue));
|
||||
default:
|
||||
//not implemented
|
||||
assert(false);
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
struct Row::LocalData {
|
||||
LocalData ( const PGresult* parResult, std::size_t parRow, const std::map<std::string, int>* parCols, std::size_t parColCount ) :
|
||||
result(parResult),
|
||||
|
@ -70,13 +108,7 @@ namespace pq {
|
|||
}
|
||||
|
||||
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);
|
||||
return get_as_str_assume_valid(conv_col_index_or_throw(parIndex, *m_localData->columns, __FILE__, __LINE__));
|
||||
}
|
||||
|
||||
std::size_t Row::size() const {
|
||||
|
@ -88,13 +120,47 @@ namespace pq {
|
|||
}
|
||||
|
||||
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 get_as_str_assume_valid(cast_col_index_or_throw(parIndex, m_localData->col_count, __FILE__, __LINE__));
|
||||
}
|
||||
|
||||
return PQgetvalue(m_localData->result, static_cast<int>(m_localData->row_index), static_cast<int>(parIndex));
|
||||
std::string Row::get_as_str_assume_valid (int parIndex) const {
|
||||
const int num_index = parIndex;
|
||||
const auto row_index = static_cast<int>(m_localData->row_index);
|
||||
const auto format = PQfformat(m_localData->result, num_index);
|
||||
const int data_len = PQgetlength(m_localData->result, row_index, num_index);
|
||||
switch (format) {
|
||||
case 0:
|
||||
//textual data
|
||||
return std::string(PQgetvalue(m_localData->result, row_index, num_index), data_len);
|
||||
case 1:
|
||||
//binary data
|
||||
if (is_null(num_index)) {
|
||||
return std::string();
|
||||
}
|
||||
else {
|
||||
return binary_to_string(
|
||||
PQgetvalue(m_localData->result, row_index, num_index),
|
||||
PQftype(m_localData->result, num_index),
|
||||
data_len
|
||||
);
|
||||
}
|
||||
default:
|
||||
//unknown
|
||||
assert(false);
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
bool Row::is_null (std::size_t parIndex) const {
|
||||
const auto num_index = cast_col_index_or_throw(parIndex, m_localData->col_count, __FILE__, __LINE__);
|
||||
const auto row_index = static_cast<int>(m_localData->row_index);
|
||||
return (1 == PQgetisnull(m_localData->result, row_index, num_index) ? true : false);
|
||||
}
|
||||
|
||||
bool Row::is_null (const std::string& parIndex) const {
|
||||
const auto num_index = conv_col_index_or_throw(parIndex, *m_localData->columns, __FILE__, __LINE__);
|
||||
const auto row_index = static_cast<int>(m_localData->row_index);
|
||||
return (1 == PQgetisnull(m_localData->result, row_index, num_index) ? true : false);
|
||||
}
|
||||
|
||||
Row::const_iterator Row::begin() const {
|
||||
|
|
|
@ -81,6 +81,7 @@ namespace din {
|
|||
|
||||
void write_to_db (const dinlib::SettingsDB& parDB, const std::vector<FileRecordData>& parData, const SetRecordData& parSetData) {
|
||||
using std::chrono::system_clock;
|
||||
using boost::lexical_cast;
|
||||
|
||||
if (parData.empty()) {
|
||||
return;
|
||||
|
@ -90,22 +91,30 @@ namespace din {
|
|||
conn.connect();
|
||||
|
||||
conn.query("BEGIN;");
|
||||
conn.query("INSERT INTO \"sets\" (\"desc\",\"type\") VALUES ($1, $2)",
|
||||
parSetData.name,
|
||||
std::string(1, parSetData.type)
|
||||
);
|
||||
uint32_t new_group_id;
|
||||
{
|
||||
auto id_res = conn.query("INSERT INTO \"sets\" (\"desc\",\"type\") VALUES ($1, $2) RETURNING \"id\";",
|
||||
parSetData.name,
|
||||
std::string(1, parSetData.type)
|
||||
);
|
||||
assert(id_res.size() == 1);
|
||||
assert(id_res[0].size() == 1);
|
||||
//TODO: make it possible to get the id directly as a string
|
||||
new_group_id = lexical_cast<uint32_t>(id_res[0][0]);
|
||||
}
|
||||
|
||||
for (std::size_t z = 0; z < parData.size(); ++z) {
|
||||
const std::string query = "INSERT INTO \"files\" (path, hash, "
|
||||
"level, group_id, is_directory, is_symlink, size, "
|
||||
"access_time, modify_time, is_hash_valid, unreadable) VALUES "
|
||||
"($1, $2, $3, currval('\"sets_id_seq\"'), $4, $5, $6, $7, $8, $9, $10);";
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);";
|
||||
|
||||
const auto& itm = parData[z];
|
||||
conn.query(query,
|
||||
itm.path,
|
||||
tiger_to_string(itm.hash),
|
||||
itm.level,
|
||||
new_group_id,
|
||||
itm.is_directory,
|
||||
itm.is_symlink,
|
||||
itm.size,
|
||||
|
|
Loading…
Reference in a new issue