#include "pqRecordSet.h" #include "dbTypes.h" #include "pqStmt.h" #include #include #include #include #include #include #include #include #include #include namespace MyGrate::Output::Pq { PqRecordSet::PqRecordSet(ResPtr r) : res {std::move(r)} { } std::size_t PqRecordSet::rows() const { return boost::numeric_cast(PQntuples(res.get())); } std::size_t PqRecordSet::columns() const { return boost::numeric_cast(PQnfields(res.get())); } DbValue PqRecordSet::at(std::size_t row, std::size_t col) const { if (PQgetisnull(res.get(), static_cast(row), static_cast(col))) { return nullptr; } const auto value {PQgetvalue(res.get(), static_cast(row), static_cast(col))}; const auto size {static_cast(PQgetlength(res.get(), static_cast(row), static_cast(col)))}; const auto type {PQftype(res.get(), static_cast(col))}; switch (type) { // case BITOID: TODO bool // case BOOLOID: TODO bool // case BOOLARRAYOID: case VARBITOID: case BYTEAOID: // This is wrong :) return Blob {reinterpret_cast(value), size}; case INT2OID: return static_cast(std::strtol(value, nullptr, 10)); case INT4OID: return static_cast(std::strtol(value, nullptr, 10)); case INT8OID: return std::strtol(value, nullptr, 10); case FLOAT4OID: return std::strtof(value, nullptr); case FLOAT8OID: case CASHOID: case NUMERICOID: return std::strtod(value, nullptr); case DATEOID: { tm tm {}; const auto end = strptime(value, "%F", &tm); verify(end && !*end, "Invalid date string"); return Date {tm}; } case TIMEOID: { tm tm {}; const auto end = strptime(value, "%T", &tm); verify(end && !*end, "Invalid time string"); return Time {tm}; } case TIMESTAMPOID: { tm tm {}; const auto end = strptime(value, "%F %T", &tm); verify(end && !*end, "Invalid timestamp string"); return DateTime {tm}; } // case TIMESTAMPTZOID: Maybe add TZ support? // case INTERVALOID: Maybe add interval support? // case TIMETZOID: Maybe add TZ support? case VOIDOID: return nullptr; default: return std::string_view {value, size}; } } }