mirror of
https://github.com/KingDuckZ/dindexer.git
synced 2025-10-19 17:09:25 +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;
|
std::string operator[] ( std::size_t parIndex ) const;
|
||||||
Row& operator= ( const Row& ) = delete;
|
Row& operator= ( const Row& ) = delete;
|
||||||
Row& operator= ( 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 begin ( void ) const;
|
||||||
const_iterator end ( void ) const;
|
const_iterator end ( void ) const;
|
||||||
|
@ -53,6 +55,8 @@ namespace pq {
|
||||||
private:
|
private:
|
||||||
struct LocalData;
|
struct LocalData;
|
||||||
|
|
||||||
|
std::string get_as_str_assume_valid ( int parIndex ) const;
|
||||||
|
|
||||||
std::unique_ptr<LocalData> m_localData;
|
std::unique_ptr<LocalData> m_localData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,8 @@ namespace pq {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultSet Connection::query_params (const std::string& parQuery, PGParams& parParams) {
|
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());
|
assert(parParams.get());
|
||||||
ResultInfo info(
|
ResultInfo info(
|
||||||
PQparamExec(
|
PQparamExec(
|
||||||
|
|
|
@ -25,8 +25,46 @@
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
#include "libpqtypes.h"
|
||||||
|
|
||||||
namespace pq {
|
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 {
|
struct Row::LocalData {
|
||||||
LocalData ( const PGresult* parResult, std::size_t parRow, const std::map<std::string, int>* parCols, std::size_t parColCount ) :
|
LocalData ( const PGresult* parResult, std::size_t parRow, const std::map<std::string, int>* parCols, std::size_t parColCount ) :
|
||||||
result(parResult),
|
result(parResult),
|
||||||
|
@ -70,13 +108,7 @@ namespace pq {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Row::operator[] (const std::string& parIndex) const {
|
std::string Row::operator[] (const std::string& parIndex) const {
|
||||||
assert(m_localData->columns);
|
return get_as_str_assume_valid(conv_col_index_or_throw(parIndex, *m_localData->columns, __FILE__, __LINE__));
|
||||||
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 {
|
std::size_t Row::size() const {
|
||||||
|
@ -88,13 +120,47 @@ namespace pq {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Row::operator[] (std::size_t parIndex) const {
|
std::string Row::operator[] (std::size_t parIndex) const {
|
||||||
if (parIndex >= m_localData->col_count) {
|
return get_as_str_assume_valid(cast_col_index_or_throw(parIndex, m_localData->col_count, __FILE__, __LINE__));
|
||||||
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));
|
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 {
|
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) {
|
void write_to_db (const dinlib::SettingsDB& parDB, const std::vector<FileRecordData>& parData, const SetRecordData& parSetData) {
|
||||||
using std::chrono::system_clock;
|
using std::chrono::system_clock;
|
||||||
|
using boost::lexical_cast;
|
||||||
|
|
||||||
if (parData.empty()) {
|
if (parData.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -90,22 +91,30 @@ namespace din {
|
||||||
conn.connect();
|
conn.connect();
|
||||||
|
|
||||||
conn.query("BEGIN;");
|
conn.query("BEGIN;");
|
||||||
conn.query("INSERT INTO \"sets\" (\"desc\",\"type\") VALUES ($1, $2)",
|
uint32_t new_group_id;
|
||||||
|
{
|
||||||
|
auto id_res = conn.query("INSERT INTO \"sets\" (\"desc\",\"type\") VALUES ($1, $2) RETURNING \"id\";",
|
||||||
parSetData.name,
|
parSetData.name,
|
||||||
std::string(1, parSetData.type)
|
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) {
|
for (std::size_t z = 0; z < parData.size(); ++z) {
|
||||||
const std::string query = "INSERT INTO \"files\" (path, hash, "
|
const std::string query = "INSERT INTO \"files\" (path, hash, "
|
||||||
"level, group_id, is_directory, is_symlink, size, "
|
"level, group_id, is_directory, is_symlink, size, "
|
||||||
"access_time, modify_time, is_hash_valid, unreadable) VALUES "
|
"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];
|
const auto& itm = parData[z];
|
||||||
conn.query(query,
|
conn.query(query,
|
||||||
itm.path,
|
itm.path,
|
||||||
tiger_to_string(itm.hash),
|
tiger_to_string(itm.hash),
|
||||||
itm.level,
|
itm.level,
|
||||||
|
new_group_id,
|
||||||
itm.is_directory,
|
itm.is_directory,
|
||||||
itm.is_symlink,
|
itm.is_symlink,
|
||||||
itm.size,
|
itm.size,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue