720 lines
20 KiB
C++
720 lines
20 KiB
C++
#include "SqlValue.h"
|
|
|
|
#include <libpq-fe.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <charconv>
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <variant>
|
|
|
|
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
|
# define __WINDOWS__
|
|
#endif
|
|
#if defined(__linux__) || defined(__CYGWIN__)
|
|
# include <endian.h>
|
|
#elif defined(__APPLE__)
|
|
# include <libkern/OSByteOrder.h>
|
|
# define htobe16(x) OSSwapHostToBigInt16(x)
|
|
# define htole16(x) OSSwapHostToLittleInt16(x)
|
|
# define be16toh(x) OSSwapBigToHostInt16(x)
|
|
# define le16toh(x) OSSwapLittleToHostInt16(x)
|
|
# define htobe32(x) OSSwapHostToBigInt32(x)
|
|
# define htole32(x) OSSwapHostToLittleInt32(x)
|
|
# define be32toh(x) OSSwapBigToHostInt32(x)
|
|
# define le32toh(x) OSSwapLittleToHostInt32(x)
|
|
# define htobe64(x) OSSwapHostToBigInt64(x)
|
|
# define htole64(x) OSSwapHostToLittleInt64(x)
|
|
# define be64toh(x) OSSwapBigToHostInt64(x)
|
|
# define le64toh(x) OSSwapLittleToHostInt64(x)
|
|
# define __BYTE_ORDER BYTE_ORDER
|
|
# define __BIG_ENDIAN BIG_ENDIAN
|
|
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
|
# define __PDP_ENDIAN PDP_ENDIAN
|
|
#elif defined(__OpenBSD__)
|
|
# include <sys/endian.h>
|
|
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
|
# include <sys/endian.h>
|
|
# define be16toh(x) betoh16(x)
|
|
# define le16toh(x) letoh16(x)
|
|
# define be32toh(x) betoh32(x)
|
|
# define le32toh(x) letoh32(x)
|
|
# define be64toh(x) betoh64(x)
|
|
# define le64toh(x) letoh64(x)
|
|
#elif defined(__WINDOWS__)
|
|
# include <winsock2.h>
|
|
# if BYTE_ORDER == LITTLE_ENDIAN
|
|
# define htobe16(x) htons(x)
|
|
# define htole16(x) (x)
|
|
# define be16toh(x) ntohs(x)
|
|
# define le16toh(x) (x)
|
|
# define htobe32(x) htonl(x)
|
|
# define htole32(x) (x)
|
|
# define be32toh(x) ntohl(x)
|
|
# define le32toh(x) (x)
|
|
# define htobe64(x) htonll(x)
|
|
# define htole64(x) (x)
|
|
# define be64toh(x) ntohll(x)
|
|
# define le64toh(x) (x)
|
|
# elif BYTE_ORDER == BIG_ENDIAN
|
|
/* that would be xbox 360 */
|
|
# define htobe16(x) (x)
|
|
# define htole16(x) __builtin_bswap16(x)
|
|
# define be16toh(x) (x)
|
|
# define le16toh(x) __builtin_bswap16(x)
|
|
# define htobe32(x) (x)
|
|
# define htole32(x) __builtin_bswap32(x)
|
|
# define be32toh(x) (x)
|
|
# define le32toh(x) __builtin_bswap32(x)
|
|
# define htobe64(x) (x)
|
|
# define htole64(x) __builtin_bswap64(x)
|
|
# define be64toh(x) (x)
|
|
# define le64toh(x) __builtin_bswap64(x)
|
|
# else
|
|
# error byte order not supported
|
|
# endif
|
|
# define __BYTE_ORDER BYTE_ORDER
|
|
# define __BIG_ENDIAN BIG_ENDIAN
|
|
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
|
# define __PDP_ENDIAN PDP_ENDIAN
|
|
#else
|
|
# error platform not supported
|
|
#endif
|
|
|
|
|
|
|
|
namespace AsyncPg {
|
|
|
|
#define BOOLOID 16
|
|
#define CHAROID 18
|
|
#define NAMEOID 19
|
|
#define JSONOID 114
|
|
#define XMLOID 142
|
|
#define VARCHAROID 1043
|
|
#define TEXTOID 25
|
|
#define INT8OID 20
|
|
#define INT2OID 21
|
|
#define INT4OID 23
|
|
#define NUMERICOID 1700
|
|
#define FLOAT4OID 700
|
|
#define FLOAT8OID 701
|
|
#define DATEOID 1082
|
|
#define TIMEOID 1083
|
|
#define TIMETZOID 1266
|
|
#define TIMESTAMPOID 1114
|
|
#define TIMESTAMPTZOID 1184
|
|
#define BYTEAOID 17
|
|
#define UUIDOID 2950
|
|
|
|
#define POSTGRES_EPOCH_USEC 946684800000000
|
|
#define POSTGRES_DAY_USEC 86400000000
|
|
|
|
template <typename T>
|
|
constexpr T htonT (T value) noexcept
|
|
{
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
char* ptr = reinterpret_cast<char*>(&value);
|
|
std::reverse(ptr, ptr + sizeof(T));
|
|
#endif
|
|
return value;
|
|
}
|
|
|
|
#if BIG_ENDIAN
|
|
template <typename T>
|
|
constexpr static T& swap_endian(T& pX)
|
|
{
|
|
return pX;
|
|
}
|
|
#else
|
|
template <typename T>
|
|
constexpr static T& swap_endian(T& pX)
|
|
{
|
|
char& raw = reinterpret_cast<char&>(pX);
|
|
std::reverse(&raw, &raw + sizeof(T));
|
|
return pX;
|
|
}
|
|
#endif
|
|
|
|
static const char *asChar(PGresult* pgresult, int row, int col)
|
|
{
|
|
return PQgetvalue(pgresult, row, col);
|
|
}
|
|
|
|
static bool asBool(PGresult* pgresult, int row, int col)
|
|
{
|
|
return *asChar(pgresult, row, col) != 0;
|
|
}
|
|
|
|
static int8_t asInt8(PGresult* pgresult, int row, int col)
|
|
{
|
|
void *ptr = PQgetvalue(pgresult, row, col);
|
|
return *static_cast<int8_t*>(ptr);
|
|
}
|
|
|
|
static int16_t asInt16(PGresult* pgresult, int row, int col)
|
|
{
|
|
void *ptr = PQgetvalue(pgresult, row, col);
|
|
return htonT(*static_cast<int16_t*>(ptr));
|
|
}
|
|
|
|
static int32_t asInt32(PGresult* pgresult, int row, int col)
|
|
{
|
|
void *ptr = PQgetvalue(pgresult, row, col);
|
|
return htonT(*static_cast<int32_t*>(ptr));
|
|
}
|
|
|
|
static int64_t asInt64(PGresult* pgresult, int row, int col)
|
|
{
|
|
void *ptr = PQgetvalue(pgresult, row, col);
|
|
return htonT(*static_cast<int64_t*>(ptr));
|
|
}
|
|
|
|
static std::time_t asTimeStamp(PGresult* pgresult, int row, int col)
|
|
{
|
|
return (asInt64(pgresult, row, col) + POSTGRES_EPOCH_USEC) / 1000000;
|
|
}
|
|
|
|
static std::time_t asTimeStampTz(PGresult* pgresult, int row, int col)
|
|
{
|
|
return (asInt64(pgresult, row, col) + POSTGRES_EPOCH_USEC) / 1000000;
|
|
}
|
|
|
|
static std::time_t asTime(PGresult* pgresult, int row, int col)
|
|
{
|
|
return asInt64(pgresult, row, col) / 1000000;
|
|
}
|
|
|
|
static std::time_t asTimeTz(PGresult* pgresult, int row, int col)
|
|
{
|
|
return asInt64(pgresult, row, col) / 1000000;
|
|
}
|
|
|
|
static std::time_t asDate(PGresult* pgresult, int row, int col)
|
|
{
|
|
return (asInt32(pgresult, row, col) * POSTGRES_DAY_USEC + POSTGRES_EPOCH_USEC) / 1000000;
|
|
}
|
|
|
|
static std::vector<char> asVector(PGresult* pgresult, int row, int col)
|
|
{
|
|
const auto len = PQgetlength(pgresult, row, col);
|
|
auto ptr = PQgetvalue(pgresult, row, col);
|
|
std::vector<char> result;
|
|
result.reserve(len);
|
|
result.assign(ptr, ptr + len);
|
|
return result;
|
|
}
|
|
|
|
static std::vector<char> asBytea(PGresult* pgresult, int row, int col)
|
|
{
|
|
const auto len = PQgetlength(pgresult, row, col);
|
|
auto ptr = PQgetvalue(pgresult, row, col);
|
|
std::vector<char> result;
|
|
result.reserve(len);
|
|
result.assign(ptr, ptr + len);
|
|
return result;
|
|
}
|
|
|
|
template<class T, std::size_t N, std::size_t... I>
|
|
constexpr std::array<std::remove_cv_t<T>, N>
|
|
to_array_impl(T *a, std::index_sequence<I...> /*unused*/)
|
|
{
|
|
return {{a[I]...}};
|
|
}
|
|
|
|
template<class T, std::size_t N>
|
|
constexpr std::array<std::remove_cv_t<T>, N> to_array(T *a)
|
|
{
|
|
return to_array_impl<T, N>(a, std::make_index_sequence<N>{});
|
|
}
|
|
|
|
static std::array<char, 16> asUuid(PGresult* pgresult, int row, int col)
|
|
{
|
|
auto *ptr = PQgetvalue(pgresult, row, col);
|
|
return to_array<char, 16>(ptr);
|
|
}
|
|
|
|
static std::string asString(PGresult* pgresult, int row, int col)
|
|
{
|
|
const auto len = PQgetlength(pgresult, row, col);
|
|
auto ptr = PQgetvalue(pgresult, row, col);
|
|
return std::string(ptr, len);
|
|
}
|
|
|
|
static double asDouble(PGresult* pgresult, int row, int col)
|
|
{
|
|
double ptr = *reinterpret_cast<double*>(PQgetvalue(pgresult, row, col));
|
|
return htonT(ptr);
|
|
}
|
|
|
|
static float asFloat(PGresult* pgresult, int row, int col)
|
|
{
|
|
union {
|
|
int32_t value;
|
|
float retval;
|
|
} castunion{};
|
|
|
|
castunion.value = asInt32(pgresult, row, col);
|
|
return castunion.retval;
|
|
}
|
|
|
|
static std::string asDecimal(PGresult* pgresult, int row, int col)
|
|
{
|
|
std::string str;
|
|
auto *decimal = reinterpret_cast<int16_t *>(PQgetvalue(pgresult, row, col));
|
|
auto ndigits = htonT(decimal[0]);
|
|
auto width = htonT(decimal[1]);
|
|
auto sign = htonT(decimal[2]);
|
|
auto dscale = htonT(decimal[3]);
|
|
if (sign != 0)
|
|
str += "-";
|
|
|
|
if (width < 0) {
|
|
str += "0.";
|
|
++width;
|
|
while (width++ < 0)
|
|
str += "0000";
|
|
width = -1;
|
|
}
|
|
|
|
for (int n = 0; n < ndigits; ++n) {
|
|
std::string digit = std::to_string(htonT(decimal[4 + n]));
|
|
if (!str.empty())
|
|
str += std::string(4 - digit.size(), '0');
|
|
str += digit;
|
|
|
|
if (width == 0 && ndigits - 1 != n)
|
|
str += ".";
|
|
|
|
if (dscale > 0 && width < 0)
|
|
dscale -= 4;
|
|
|
|
if (width >= 0)
|
|
--width;
|
|
}
|
|
|
|
while (width-- >= 0)
|
|
str += "0000";
|
|
|
|
return (dscale < 0) ? str.substr(0, str.size() + dscale) : str;
|
|
}
|
|
|
|
SqlValue asSqlValue(PGresult *pgresult, int row, int col)
|
|
{
|
|
SqlValue result;
|
|
|
|
if (!pgresult)
|
|
return result;
|
|
|
|
auto oid = PQftype(pgresult, col);
|
|
switch (oid) {
|
|
case BOOLOID:
|
|
result.emplace<SqlType::Boolean>(asBool(pgresult, row, col));
|
|
break;
|
|
case INT2OID:
|
|
result.emplace<SqlType::SmallInt>(asInt16(pgresult, row, col));
|
|
break;
|
|
case INT4OID:
|
|
result.emplace<SqlType::Integer>(asInt32(pgresult, row, col));
|
|
break;
|
|
case INT8OID:
|
|
result.emplace<SqlType::BigInt>(asInt64(pgresult, row, col));
|
|
break;
|
|
case FLOAT4OID:
|
|
result.emplace<SqlType::Real>(asFloat(pgresult, row, col));
|
|
break;
|
|
case FLOAT8OID:
|
|
result.emplace<SqlType::Double>(asDouble(pgresult, row, col));
|
|
break;
|
|
case NUMERICOID:
|
|
result.emplace<SqlType::Decimal>(asDecimal(pgresult, row, col));
|
|
break;
|
|
case TIMESTAMPOID:
|
|
result.emplace<SqlType::TimeStamp>(asTimeStamp(pgresult, row, col));
|
|
break;
|
|
case TIMESTAMPTZOID:
|
|
result.emplace<SqlType::TimeStampTz>(asTimeStampTz(pgresult, row, col));
|
|
break;
|
|
case TIMEOID:
|
|
result.emplace<SqlType::Time>(asTime(pgresult, row, col));
|
|
break;
|
|
case TIMETZOID:
|
|
result.emplace<SqlType::TimeTz>(asTimeTz(pgresult, row, col));
|
|
break;
|
|
case BYTEAOID:
|
|
result.emplace<SqlType::Bytea>(asBytea(pgresult, row, col));
|
|
break;
|
|
case DATEOID:
|
|
result.emplace<SqlType::Date>(asDate(pgresult, row, col));
|
|
break;
|
|
case UUIDOID:
|
|
result.emplace<SqlType::Uuid>(asUuid(pgresult, row, col));
|
|
break;
|
|
case CHAROID:
|
|
result.emplace<SqlType::Char>(asString(pgresult, row, col));
|
|
case NAMEOID:
|
|
result.emplace<SqlType::Name>(asString(pgresult, row, col));
|
|
case JSONOID:
|
|
result.emplace<SqlType::Json>(asString(pgresult, row, col));
|
|
case XMLOID:
|
|
result.emplace<SqlType::Xml>(asString(pgresult, row, col));
|
|
case VARCHAROID:
|
|
result.emplace<SqlType::VarChar>(asString(pgresult, row, col));
|
|
case TEXTOID:
|
|
result.emplace<SqlType::Text>(asString(pgresult, row, col));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromBool(const std::optional<bool> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(BOOLOID, 0, nullptr);
|
|
|
|
char *v = new char[1];
|
|
*v = *value ? 1 : 0;
|
|
return std::make_tuple(BOOLOID, 1, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromInt16(const std::optional<int16_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(INT2OID, 0, nullptr);
|
|
|
|
char *v = new char[2];
|
|
*reinterpret_cast<int16_t *>(v) = htonT(*value);
|
|
return std::make_tuple(INT2OID, 2, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromInt32(const std::optional<int32_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(INT4OID, 0, nullptr);
|
|
|
|
char *v = new char[4];
|
|
*reinterpret_cast<int32_t *>(v) = htonT(*value);
|
|
return std::make_tuple(INT4OID, 4, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromInt64(const std::optional<int64_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(INT8OID, 0, nullptr);
|
|
|
|
char *v = new char[8];
|
|
*reinterpret_cast<int64_t *>(v) = htonT(*value);
|
|
return std::make_tuple(INT8OID, 8, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromFloat(const std::optional<float> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(FLOAT4OID, 0, nullptr);
|
|
|
|
union {
|
|
int32_t value;
|
|
float retval;
|
|
} castunion{};
|
|
castunion.retval = *value;
|
|
char *v = new char[4];
|
|
*reinterpret_cast<int32_t *>(v) = htonT(castunion.value);
|
|
return std::make_tuple(FLOAT4OID, 4, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromDouble(const std::optional<double> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(FLOAT8OID, 0, nullptr);
|
|
|
|
union {
|
|
int64_t value;
|
|
double retval;
|
|
} castunion{};
|
|
|
|
castunion.retval = *value;
|
|
char *v = new char[8];
|
|
*reinterpret_cast<int64_t *>(v) = htonT(castunion.value);
|
|
return std::make_tuple(FLOAT8OID, 8, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromDecimal(
|
|
const std::optional<std::string> &value)
|
|
{
|
|
if (!value || value->empty())
|
|
return std::make_tuple(NUMERICOID, 0, nullptr);
|
|
|
|
std::deque<int16_t> decimal;
|
|
int16_t ndigits = 0;
|
|
int16_t width = -1;
|
|
int16_t sign = value->substr(0, 1) == "-" ? 1 : 0;
|
|
int16_t dscale = 0;
|
|
|
|
auto pos = value->find('.');
|
|
bool existIntPart = (
|
|
value->substr(sign, (pos == std::string::npos ? value->length() - sign : pos)) != "0");
|
|
bool existFracPart = (pos != std::string::npos || pos + 1 > value->length());
|
|
|
|
if (existIntPart) {
|
|
int beg = (sign != 0) ? 1 : 0;
|
|
int end = static_cast<int>(pos == std::string::npos ? value->length() : pos) - 1;
|
|
|
|
std::size_t count = 0;
|
|
std::size_t notZeroPos = end;
|
|
for (auto i = end; i >= beg; --i) {
|
|
if (value->at(i) != '0')
|
|
notZeroPos = i;
|
|
|
|
if (++count == 4 || i == beg) {
|
|
auto zeroCount = notZeroPos - i;
|
|
int16_t digit = static_cast<int16_t>(
|
|
std::stoi(value->substr(i + zeroCount, count - zeroCount)));
|
|
count = 0;
|
|
++width;
|
|
|
|
if (!existFracPart && digit == 0 && !decimal.empty())
|
|
continue;
|
|
|
|
decimal.emplace_front(htonT(digit));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (existFracPart) {
|
|
std::size_t count = 0;
|
|
for (auto i = pos + 1, e = value->length(); i < e; ++i) {
|
|
if (++count == 4 || i + 1 == e) {
|
|
std::string sdigit = value->substr(i - count + 1, count);
|
|
if (count < 4)
|
|
sdigit += std::string(4 - count, '0');
|
|
auto digit = static_cast<int16_t>(std::stoi(sdigit));
|
|
dscale = static_cast<int16_t>(dscale + count);
|
|
count = 0;
|
|
|
|
if (!existIntPart && digit == 0 && decimal.empty()) {
|
|
--width;
|
|
continue;
|
|
}
|
|
|
|
decimal.emplace_back(htonT(digit));
|
|
}
|
|
}
|
|
}
|
|
|
|
ndigits = static_cast<int16_t>(decimal.size());
|
|
std::size_t size = 8 + ndigits * 2;
|
|
auto *v = new char[size];
|
|
auto *vv = reinterpret_cast<int16_t *>(v);
|
|
|
|
std::size_t it = 0;
|
|
vv[it++] = htonT(ndigits);
|
|
vv[it++] = htonT(width);
|
|
vv[it++] = htonT(sign);
|
|
vv[it++] = htonT(dscale);
|
|
|
|
for (int16_t digit : decimal)
|
|
vv[it++] = digit;
|
|
|
|
return std::make_tuple(NUMERICOID, size, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromTimeStamp(
|
|
unsigned int oid, const std::optional<std::time_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(oid, 0, nullptr);
|
|
|
|
char *v = new char[8];
|
|
*reinterpret_cast<int64_t *>(v) = htonT(*value * 1000000 - POSTGRES_EPOCH_USEC);
|
|
|
|
return std::make_tuple(oid, 8, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromTime(
|
|
unsigned int oid, const std::optional<std::time_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(oid, 0, nullptr);
|
|
|
|
char *v = new char[8];
|
|
*reinterpret_cast<int64_t *>(v) = htonT(*value * 1000000);
|
|
|
|
return std::make_tuple(oid, 8, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromDate(const std::optional<std::time_t> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(DATEOID, 0, nullptr);
|
|
|
|
char *v = new char[4];
|
|
*reinterpret_cast<int32_t *>(v) = static_cast<int32_t>(
|
|
htonT((*value * 1000000 - POSTGRES_EPOCH_USEC) / POSTGRES_DAY_USEC));
|
|
|
|
return std::make_tuple(DATEOID, 4, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromString(
|
|
unsigned int oid, const std::optional<std::string> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(oid, 0, nullptr);
|
|
|
|
auto size = value->size();
|
|
char *v = new char[size];
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
v[i] = value->data()[i];
|
|
|
|
return std::make_tuple(oid, size, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromUuid(
|
|
const std::optional<std::array<char, 16>> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(UUIDOID, 0, nullptr);
|
|
|
|
auto size = value->size();
|
|
char *v = new char[size];
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
v[i] = value->data()[i];
|
|
|
|
return std::make_tuple(UUIDOID, size, v);
|
|
}
|
|
|
|
static std::tuple<unsigned int, std::size_t, char *> fromBytea(
|
|
const std::optional<std::vector<char>> &value)
|
|
{
|
|
if (!value)
|
|
return std::make_tuple(BYTEAOID, 0, nullptr);
|
|
|
|
auto size = value->size();
|
|
char *v = new char[size];
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
v[i] = value->data()[i];
|
|
|
|
return std::make_tuple(BYTEAOID, size, v);
|
|
}
|
|
|
|
std::tuple<unsigned int, std::size_t, char *> asPgValue(const SqlValue &value)
|
|
{
|
|
switch (value.index()) {
|
|
case SqlType::Boolean:
|
|
return fromBool(std::get<SqlType::Boolean>(value));
|
|
case SqlType::SmallInt:
|
|
return fromInt16(std::get<SqlType::SmallInt>(value));
|
|
case SqlType::Integer:
|
|
return fromInt32(std::get<SqlType::Integer>(value));
|
|
case SqlType::BigInt:
|
|
return fromInt64(std::get<SqlType::BigInt>(value));
|
|
case SqlType::Real:
|
|
return fromFloat(std::get<SqlType::Real>(value));
|
|
case SqlType::Double:
|
|
return fromDouble(std::get<SqlType::Double>(value));
|
|
case SqlType::Decimal:
|
|
return fromDecimal(std::get<SqlType::Decimal>(value));
|
|
case SqlType::TimeStamp:
|
|
return fromTimeStamp(TIMESTAMPOID, std::get<SqlType::TimeStamp>(value));
|
|
case SqlType::TimeStampTz:
|
|
return fromTimeStamp(TIMESTAMPTZOID, std::get<SqlType::TimeStampTz>(value));
|
|
case SqlType::Time:
|
|
return fromTime(TIMEOID, std::get<SqlType::Time>(value));
|
|
case SqlType::TimeTz:
|
|
return fromTime(TIMETZOID, std::get<SqlType::TimeTz>(value));
|
|
case SqlType::Date:
|
|
return fromDate(std::get<SqlType::Date>(value));
|
|
case SqlType::Bytea:
|
|
return fromBytea(std::get<SqlType::Bytea>(value));
|
|
case SqlType::Uuid:
|
|
return fromUuid(std::get<SqlType::Uuid>(value));
|
|
case SqlType::Char:
|
|
return fromString(CHAROID, std::get<SqlType::Char>(value));
|
|
case SqlType::VarChar:
|
|
return fromString(VARCHAROID, std::get<SqlType::VarChar>(value));
|
|
case SqlType::Name:
|
|
return fromString(NAMEOID, std::get<SqlType::Name>(value));
|
|
case SqlType::Json:
|
|
return fromString(JSONOID, std::get<SqlType::Json>(value));
|
|
case SqlType::Xml:
|
|
return fromString(XMLOID, std::get<SqlType::Xml>(value));
|
|
case SqlType::Text:
|
|
return fromString(TEXTOID, std::get<SqlType::Text>(value));
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return std::make_tuple(0, 0, nullptr);
|
|
}
|
|
|
|
unsigned int toPgType(SqlType type)
|
|
{
|
|
switch (type) {
|
|
case SqlType::Boolean:
|
|
return BOOLOID;
|
|
case SqlType::SmallInt:
|
|
return INT2OID;
|
|
case SqlType::Integer:
|
|
return INT4OID;
|
|
case SqlType::BigInt:
|
|
return INT8OID;
|
|
case SqlType::Real:
|
|
return FLOAT4OID;
|
|
case SqlType::Double:
|
|
return FLOAT8OID;
|
|
case SqlType::Decimal:
|
|
return NUMERICOID;
|
|
case SqlType::TimeStamp:
|
|
return TIMESTAMPOID;
|
|
case SqlType::TimeStampTz:
|
|
return TIMESTAMPTZOID;
|
|
case SqlType::Time:
|
|
return TIMEOID;
|
|
case SqlType::TimeTz:
|
|
return TIMETZOID;
|
|
case SqlType::Date:
|
|
return DATEOID;
|
|
case SqlType::Bytea:
|
|
return BYTEAOID;
|
|
case SqlType::Uuid:
|
|
return UUIDOID;
|
|
case SqlType::Char:
|
|
return CHAROID;
|
|
case SqlType::VarChar:
|
|
return VARCHAROID;
|
|
case SqlType::Name:
|
|
return NAMEOID;
|
|
case SqlType::Json:
|
|
return JSONOID;
|
|
case SqlType::Xml:
|
|
return XMLOID;
|
|
case SqlType::Text:
|
|
return TEXTOID;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::string fromByteUuid(const std::array<char, 16> &uuid)
|
|
{
|
|
static const char* digits = "0123456789abcdef";
|
|
std::string result;
|
|
result.reserve(36);
|
|
for (std::size_t i = 0; i < 16; ++i) {
|
|
if (i == 4 || i == 6 || i == 8 || i == 10)
|
|
result += '-';
|
|
result += digits[(uuid[i] >> 4) & 0xF];
|
|
result += digits[uuid[i] & 0xF];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
}
|