added test for date and time, sql read and write functionality

This commit is contained in:
Sascha Kühl 2026-01-06 22:23:50 +01:00
parent 0c6b5a0a93
commit c48bd4f9d6
17 changed files with 516 additions and 360 deletions

View File

@ -9,8 +9,7 @@ namespace matador::backends::postgres {
namespace detail {
class empty_binder final : public utils::attribute_reader
{
class empty_binder final : public utils::attribute_reader {
public:
void read_value(const char *, size_t, int8_t &) override {}
void read_value(const char *, size_t, int16_t &) override {}
@ -23,8 +22,9 @@ public:
void read_value(const char *, size_t, bool &) override {}
void read_value(const char *, size_t, float &) override {}
void read_value(const char *, size_t, double &) override {}
void read_value(const char *, size_t, time &) override {}
void read_value(const char *, size_t, date &) override {}
void read_value(const char *, size_t, utils::date_type_t &) override {}
void read_value(const char *, size_t, utils::time_type_t &) override {}
void read_value(const char *, size_t, utils::timestamp &) override {}
void read_value(const char *, size_t, char *, size_t) override {}
void read_value(const char *, size_t, std::string &) override {}
void read_value(const char *, size_t, std::string &, size_t) override {}
@ -34,8 +34,7 @@ public:
}
class postgres_result_reader final : public sql::query_result_reader
{
class postgres_result_reader final : public sql::query_result_reader {
public:
explicit postgres_result_reader(PGresult *result);
~postgres_result_reader() override;
@ -57,8 +56,9 @@ public:
void read_value(const char *id, size_t index, bool &value) override;
void read_value(const char *id, size_t index, float &value) override;
void read_value(const char *id, size_t index, double &value) override;
void read_value(const char *id, size_t index, matador::time &value) override;
void read_value(const char *id, size_t index, matador::date &value) override;
void read_value(const char *id, size_t index, utils::date_type_t &) override;
void read_value(const char *id, size_t index, utils::time_type_t &) override;
void read_value(const char *id, size_t index, utils::timestamp &) override;
void read_value(const char *id, size_t index, char *value, size_t size) override;
void read_value(const char *id, size_t index, std::string &value) override;
void read_value(const char *id, size_t index, std::string &value, size_t size) override;

View File

@ -178,8 +178,10 @@ utils::basic_type oid2type(const Oid oid) {
return utils::basic_type::Double;
case 1082:
return utils::basic_type::Date;
case 1114:
case 1083:
return utils::basic_type::Time;
case 1114:
return utils::basic_type::DateTime;
default:
return utils::basic_type::Null;
}
@ -201,9 +203,12 @@ utils::basic_type string2type(const char *type) {
if (strcmp(type, "date") == 0) {
return utils::basic_type::Date;
}
if (strcmp(type, "timestamp") == 0) {
if (strcmp(type, "time") == 0) {
return utils::basic_type::Time;
}
if (strcmp(type, "timestamp") == 0) {
return utils::basic_type::DateTime;
}
if (strcmp(type, "float4") == 0) {
return utils::basic_type::Float;
}

View File

@ -20,7 +20,8 @@
{matador::utils::basic_type::UInt8, "SMALLINT"},
{matador::utils::basic_type::Float, "REAL"},
{matador::utils::basic_type::Double, "DOUBLE PRECISION"},
{matador::utils::basic_type::Time, "TIMESTAMP"},
{matador::utils::basic_type::Time, "TIME(6)"},
{matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"},
{matador::utils::basic_type::Blob, "BYTEA"}
})
.with_bool_strings("TRUE", "FALSE")

View File

@ -123,15 +123,23 @@ void postgres_parameter_binder::write_value(const size_t pos, const std::string
write_value(pos, x);
}
void postgres_parameter_binder::write_value(const size_t pos, const utils::date_type_t &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, utils::date_format::ISO8601);
void postgres_parameter_binder::write_value(const size_t pos, const utils::date_type_t &x) {
char buf[11]; // "YYYY-MM-DD" + '\0'
std::snprintf(buf, sizeof(buf), "%04d-%02u-%02u", x.year, static_cast<unsigned>(x.month), static_cast<unsigned>(x.day));
bind_data_.strings[pos] = std::string{buf};
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;
}
void postgres_parameter_binder::write_value(const size_t pos, const utils::time_type_t &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, "%Y-%m-%d %T.%f");
void postgres_parameter_binder::write_value(const size_t pos, const utils::time_type_t &x) {
char buf[16]; // "HH:MM:SS.ffffff" + '\0'
std::snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%06u",
static_cast<unsigned>(x.hour), static_cast<unsigned>(x.minute), static_cast<unsigned>(x.second), x.microsecond);
bind_data_.strings[pos] = std::string{buf};
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;

View File

@ -4,27 +4,23 @@
#include "matador/utils/value.hpp"
namespace matador::backends::postgres {
postgres_result_reader::postgres_result_reader(PGresult *result)
: result_(result)
, row_count_(PQntuples(result_))
, column_count_(PQnfields(result_))
{}
, column_count_(PQnfields(result_)) {
}
postgres_result_reader::~postgres_result_reader()
{
postgres_result_reader::~postgres_result_reader() {
if (result_) {
PQclear(result_);
}
}
size_t postgres_result_reader::column_count() const
{
size_t postgres_result_reader::column_count() const {
return column_count_;
}
const char *postgres_result_reader::column( const size_t index) const
{
const char *postgres_result_reader::column(const size_t index) const {
return PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
}
@ -106,16 +102,21 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
}
}
void postgres_result_reader::read_value(const char * /*id*/, const size_t /*index*/, time &/*value*/) {
// if (const auto val = column(index); strlen(val) > 0) {
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::date_type_t &value) {
if (const auto val = column(index); strlen(val) > 0) {
// value = time::parse(val, "%Y-%m-%d %T.%f");
// }
}
}
void postgres_result_reader::read_value(const char * /*id*/, const size_t /*index*/, date &/*value*/) {
// if (const auto val = column(index); strlen(val) > 0) {
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::time_type_t &value) {
if (const auto val = column(index); strlen(val) > 0) {
// value.set(val, matador::utils::date_format::ISO8601);
// }
}
}
void postgres_result_reader::read_value(const char * /*id*/, size_t index, utils::timestamp &value) {
if (const auto val = column(index); strlen(val) > 0) {
}
}
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, char *value, size_t size) {
@ -144,10 +145,8 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
value.assign(column(index));
}
void postgres_result_reader::read_value( const char* /*id*/, const size_t index, utils::blob& value )
{
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::blob &value) {
const auto *data = reinterpret_cast<const unsigned char *>(column(index));
// auto length = PQgetlength(result_, row_index_, static_cast<int>(index));
size_t length;
unsigned char *unescaped = PQunescapeBytea(data, &length);
@ -219,8 +218,13 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
break;
}
case utils::basic_type::Time:
case utils::basic_type::Date: {
val = std::string{column(index)};
set_value<utils::time_type_t>(column(index), val);
break;
case utils::basic_type::Date:
set_value<utils::date_type_t>(column(index), val);
break;
case utils::basic_type::DateTime: {
set_value<utils::timestamp>(column(index), val);
break;
}
case utils::basic_type::Null: {
@ -231,11 +235,12 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
set_value<utils::blob>(column(index), val);
break;
}
case utils::basic_type::Unknown:
break;
}
}
utils::attribute_reader &postgres_result_reader::result_binder() {
return empty_binder_;
}
} // namespace matador::backends::postgres

View File

@ -69,7 +69,7 @@ public:
[[nodiscard]] std::string prepare_literal(const std::string &str) const;
/**
* Wrap identifier quotes around a sql identifier keyword
* Wrap identifier quotes around a SQL identifier keyword
*
* @param str Identifier to put quotes around
*/
@ -259,7 +259,8 @@ private:
{utils::basic_type::Varchar, "VARCHAR"},
{utils::basic_type::Text, "TEXT"},
{utils::basic_type::Date, "DATE"},
{utils::basic_type::Time, "DATETIME"},
{utils::basic_type::Time, "TIME"},
{utils::basic_type::DateTime, "DATETIME"},
{utils::basic_type::Blob, "BLOB"},
{utils::basic_type::Null, "NULL"}
};

View File

@ -5,10 +5,6 @@
#include <string>
namespace matador {
class date;
class time;
}
namespace matador::utils {
class value;
@ -29,8 +25,9 @@ public:
virtual void read_value(const char *id, size_t index, bool &value) = 0;
virtual void read_value(const char *id, size_t index, float &value) = 0;
virtual void read_value(const char *id, size_t index, double &value) = 0;
virtual void read_value(const char *id, size_t index, time &value) = 0;
virtual void read_value(const char *id, size_t index, date &value) = 0;
virtual void read_value(const char *id, size_t index, time_type_t &value) = 0;
virtual void read_value(const char *id, size_t index, date_type_t &value) = 0;
virtual void read_value(const char *id, size_t index, timestamp &value) = 0;
virtual void read_value(const char *id, size_t index, char *value, size_t size) = 0;
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
virtual void read_value(const char *id, size_t index, std::string &value, size_t size) = 0;

View File

@ -256,26 +256,57 @@ template < typename DestType >
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, date_type_t>>* = nullptr) {
std::tm result{};
std::istringstream iss(source);
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
return ok(result);
iss >> std::get_time(&result, "%Y-%m-%d");
if (iss.fail()) {
return failure(conversion_error::NotConvertable);
}
return ok(date_type_t{result.tm_year + 1900, static_cast<uint8_t>(result.tm_mon + 1), static_cast<uint8_t>(result.tm_mday)});
}
template < typename DestType >
result<DestType, conversion_error> to(const char *source, std::enable_if_t<std::is_same_v<DestType, date_type_t>>* = nullptr) {
return to<DestType>(std::string{source});
}
template < typename DestType >
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, time_type_t>>* = nullptr) {
std::tm result{};
std::istringstream iss(source);
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
return ok(result);
iss >> std::get_time(&result, "%H:%M:%S");
if (iss.fail()) {
return failure(conversion_error::NotConvertable);
}
return ok(time_type_t{static_cast<uint8_t>(result.tm_hour), static_cast<uint8_t>(result.tm_min), static_cast<uint8_t>(result.tm_sec)});
}
template < typename DestType >
result<DestType, conversion_error> to(const char *source, std::enable_if_t<std::is_same_v<DestType, time_type_t>>* = nullptr) {
return to<DestType>(std::string{source});
}
template < typename DestType >
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, timestamp>>* = nullptr) {
std::tm result{};
std::istringstream iss(source);
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
return ok(result);
if (iss.fail()) {
return failure(conversion_error::NotConvertable);
}
const std::time_t tt = std::mktime(&result);
if (tt == -1) {
return failure(conversion_error::NotConvertable);
}
return ok(std::chrono::system_clock::from_time_t(tt));
}
template < typename DestType >
result<DestType, conversion_error> to(const char *source, std::enable_if_t<std::is_same_v<DestType, timestamp>>* = nullptr) {
return to<DestType>(std::string{source});
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<DestType> && !std::is_same_v<bool, DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
@ -351,6 +382,104 @@ result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<SourceType> && !std::is_same_v<bool, SourceType> && std::is_same_v<date_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<SourceType> && !std::is_same_v<bool, SourceType> && std::is_same_v<time_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<SourceType> && !std::is_same_v<bool, SourceType> && std::is_same_v<timestamp, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<SourceType> && std::is_same_v<date_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<SourceType> && std::is_same_v<time_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<SourceType> && std::is_same_v<timestamp, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const blob &/*source*/, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const blob &/*source*/, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const blob &/*source*/, std::enable_if_t<std::is_same_v<timestamp, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const bool &/*source*/, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const bool &/*source*/, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const bool &/*source*/, std::enable_if_t<std::is_same_v<timestamp, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const time_type_t &/*source*/, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const time_type_t &source, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
return ok(source);
}
template < typename DestType>
result<DestType, conversion_error> to(const date_type_t &/*source*/, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
return failure(conversion_error::NotConvertable);
}
template < typename DestType>
result<DestType, conversion_error> to(const date_type_t &source, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
return ok(source);
}
template < typename DestType>
result<DestType, conversion_error> to(const timestamp &source, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
const std::time_t tt = std::chrono::system_clock::to_time_t(source);
const std::tm* result = std::localtime(&tt);
return ok(time_type_t{static_cast<uint8_t>(result->tm_hour), static_cast<uint8_t>(result->tm_min), static_cast<uint8_t>(result->tm_sec)});
}
template < typename DestType>
result<DestType, conversion_error> to(const timestamp &source, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
const std::time_t tt = std::chrono::system_clock::to_time_t(source);
const std::tm* result = std::localtime(&tt);
return ok(date_type_t{result->tm_year + 1900, static_cast<uint8_t>(result->tm_mon + 1), static_cast<uint8_t>(result->tm_mday)});
}
}
#endif //MATADOR_CONVERT_HPP

View File

@ -8,159 +8,162 @@
#include <string>
namespace matador::utils {
/// @cond MATADOR_DEV
template <> struct data_type_traits<nullptr_t, void>
{
template<>
struct data_type_traits<nullptr_t, void> {
static basic_type type(std::size_t /*size*/) { return basic_type::Null; }
static void read_value(attribute_reader &reader, const char *id, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0);
static void read_value(attribute_reader &reader, const char *id, size_t index, nullptr_t &/*value*/,
size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0);
};
template <> struct data_type_traits<int8_t, void>
{
template<>
struct data_type_traits<int8_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Int8; }
static void read_value(attribute_reader &reader, const char *id, size_t index, int8_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const int8_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<int16_t, void>
{
template<>
struct data_type_traits<int16_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Int16; }
static void read_value(attribute_reader &reader, const char *id, size_t index, int16_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const int16_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<int32_t, void>
{
template<>
struct data_type_traits<int32_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Int32; }
static void read_value(attribute_reader &reader, const char *id, size_t index, int32_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const int32_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<int64_t, void>
{
template<>
struct data_type_traits<int64_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Int64; }
static void read_value(attribute_reader &reader, const char *id, size_t index, int64_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const int64_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<uint8_t, void>
{
template<>
struct data_type_traits<uint8_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::UInt8; }
static void read_value(attribute_reader &reader, const char *id, size_t index, uint8_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const uint8_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<uint16_t, void>
{
template<>
struct data_type_traits<uint16_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::UInt16; }
static void read_value(attribute_reader &reader, const char *id, size_t index, uint16_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const uint16_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<uint32_t, void>
{
template<>
struct data_type_traits<uint32_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::UInt32; }
static void read_value(attribute_reader &reader, const char *id, size_t index, uint32_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const uint32_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<uint64_t, void>
{
template<>
struct data_type_traits<uint64_t, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::UInt64; }
static void read_value(attribute_reader &reader, const char *id, size_t index, uint64_t &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const uint64_t &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<bool, void>
{
template<>
struct data_type_traits<bool, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Boolean; }
static void read_value(attribute_reader &reader, const char *id, size_t index, bool &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const bool &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<float, void>
{
template<>
struct data_type_traits<float, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Float; }
static void read_value(attribute_reader &reader, const char *id, size_t index, float &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const float &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<double, void>
{
template<>
struct data_type_traits<double, void> {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Double; }
static void read_value(attribute_reader &reader, const char *id, size_t index, double &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, const double &value, size_t /*size*/ = 0);
};
template <> struct data_type_traits<const char*, void>
{
template<>
struct data_type_traits<const char *, void> {
static basic_type type(const std::size_t size) { return size == 0 ? basic_type::Text : basic_type::Varchar; }
static void read_value(attribute_reader &reader, const char *id, size_t index, const char *value, size_t size);
static void bind_value(attribute_writer &binder, size_t index, const char *value, size_t size = 0);
};
template <> struct data_type_traits<char*, void>
{
template<>
struct data_type_traits<char *, void> {
static basic_type type(const std::size_t size) { return size == 0 ? basic_type::Text : basic_type::Varchar; }
static void read_value(attribute_reader &reader, const char *id, size_t index, char *value, size_t size);
static void bind_value(attribute_writer &binder, size_t index, const char *value, size_t size = 0);
};
template <> struct data_type_traits<char[], void>
{
template<>
struct data_type_traits<char[], void> {
static basic_type type(const std::size_t size) { return size == 0 ? basic_type::Text : basic_type::Varchar; }
template<int N>
static void read_value(attribute_reader &reader, const char *id, const size_t index, char (&value)[N], const size_t size) {
data_type_traits<const char *>::read_value(reader, id, index, value, size);
}
template<int N>
static void bind_value(attribute_writer &binder, const size_t index, char *value, const size_t size = 0) {
data_type_traits<const char *>::bind_value(binder, index, value, size);
}
};
template <> struct data_type_traits<std::string, void>
{
template<>
struct data_type_traits<std::string, void> {
static basic_type type(const std::size_t size) { return size == 0 ? basic_type::Text : basic_type::Varchar; }
static void read_value(attribute_reader &reader, const char *id, size_t index, std::string &value, size_t size);
static void bind_value(attribute_writer &binder, size_t index, std::string &value, size_t size = 0);
};
template <> struct data_type_traits<utils::blob, void>
{
template<>
struct data_type_traits<utils::blob, void> {
static basic_type type(std::size_t /*size*/) { return basic_type::Blob; }
static void read_value(attribute_reader &reader, const char *id, size_t index, utils::blob &value, size_t /*size*/ = 0);
static void bind_value(attribute_writer &binder, size_t index, utils::blob &value, size_t /*size*/ = 0);
};
//template <> struct data_type_traits<matador::date, void>
//{
// static basic_type type(std::size_t /*size*/) { return basic_type::type_date; }
// static void read_value(attribute_reader &reader, const char *id, size_t index, matador::date &value);
// static void bind_value(attribute_writer &binder, size_t index, matador::date &value);
//};
//
//template <> struct data_type_traits<matador::time, void>
//{
// static basic_type type(std::size_t /*size*/) { return basic_type::type_time; }
// static void read_value(attribute_reader &reader, const char *id, size_t index, matador::time &value);
// static void bind_value(attribute_writer &binder, size_t index, matador::time &value);
//};
template<>
struct data_type_traits<date_type_t, void> {
static basic_type type(std::size_t /*size*/) { return basic_type::Date; }
static void read_value(attribute_reader &reader, const char *id, size_t index, date_type_t &value);
static void bind_value(attribute_writer &binder, size_t index, date_type_t &value);
};
template<>
struct data_type_traits<time_type_t, void> {
static basic_type type(std::size_t /*size*/) { return basic_type::Time; }
static void read_value(attribute_reader &reader, const char *id, size_t index, time_type_t &value);
static void bind_value(attribute_writer &binder, size_t index, time_type_t &value);
};
template<typename EnumType>
struct data_type_traits<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>>
{
struct data_type_traits<EnumType, std::enable_if_t<std::is_enum_v<EnumType> > > {
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::Int32; }
static void read_value(attribute_reader &reader, const char *id, const size_t index, EnumType &value, const size_t size = 0) {
data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int &>(value), size);
}
static void bind_value(attribute_writer &binder, const size_t index, EnumType &value, const size_t size = 0) {
data_type_traits<int>::bind_value(binder, index, static_cast<int &>(value), size);
}
};
/// @endcond
/// @endcond
}
#endif //MATADOR_DEFAULT_TYPE_TRAITS_HPP

View File

@ -19,6 +19,8 @@ namespace matador::utils {
* @return Binary data as string
*/
MATADOR_UTILS_API std::string to_string(const blob &data);
MATADOR_UTILS_API std::string to_string(const date_type_t &data);
MATADOR_UTILS_API std::string to_string(const time_type_t &data);
/**
* Splits a string by a delimiter and

View File

@ -127,28 +127,24 @@ void data_type_traits<blob>::read_value(attribute_reader &reader, const char *id
reader.read_value(id, index, value);
}
void data_type_traits<blob>::bind_value(attribute_writer &binder, const size_t index, utils::blob &value, const size_t /*size*/) {
void data_type_traits<blob>::bind_value(attribute_writer &binder, const size_t index, blob &value, const size_t /*size*/) {
binder.write_value(index, value);
}
// void data_type_traits<matador::date>::read_value(attribute_reader &reader, const char *id, size_t index, date &value)
// {
// reader.read_value(id, index, value);
// }
//
// void data_type_traits<matador::date>::bind_value(attribute_writer &binder, size_t index, date &value)
// {
// binder.write_value(index, value);
// }
//
// void data_type_traits<matador::time>::read_value(attribute_reader &reader, const char *id, size_t index, time &value)
// {
// reader.read_value(id, index, value);
// }
//
// void data_type_traits<matador::time>::bind_value(attribute_writer &binder, size_t index, time &value)
// {
// binder.write_value(index, value);
// }
void data_type_traits<date_type_t>::read_value(attribute_reader &reader, const char *id, size_t index, date_type_t &value) {
reader.read_value(id, index, value);
}
void data_type_traits<date_type_t>::bind_value(attribute_writer &binder, const size_t index, date_type_t &value) {
binder.write_value(index, value);
}
void data_type_traits<time_type_t>::read_value(attribute_reader &reader, const char *id, size_t index, time_type_t &value) {
reader.read_value(id, index, value);
}
void data_type_traits<time_type_t>::bind_value(attribute_writer &binder, const size_t index, time_type_t &value) {
binder.write_value(index, value);
}
}

View File

@ -18,6 +18,24 @@ std::string to_string(const blob& data) {
return str;
}
std::string to_string(const date_type_t &data) {
char buf[11]; // "YYYY-MM-DD" + '\0'
std::snprintf(buf, sizeof(buf), "%04d-%02u-%02u",
data.year, static_cast<unsigned>(data.month), static_cast<unsigned>(data.day));
return buf;
}
std::string to_string(const time_type_t &data) {
char buf[16]; // "HH:MM:SS.ffffff" + '\0'
std::snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%06u",
static_cast<unsigned>(data.hour), static_cast<unsigned>(data.minute), static_cast<unsigned>(data.second), data.microsecond);
return buf;
}
size_t split(const std::string &str, char delim, std::vector<std::string> &values)
{
std::stringstream ss(str);

View File

@ -9,10 +9,12 @@
#include "matador/utils/string.hpp"
namespace matador::query {
attribute_string_writer::attribute_string_writer(const sql::dialect &d, const std::optional<std::reference_wrapper<const sql::connection_impl>> conn)
attribute_string_writer::attribute_string_writer(const sql::dialect &d,
const std::optional<std::reference_wrapper<const
sql::connection_impl> > conn)
: dialect_(d)
, conn_(conn) {}
, conn_(conn) {
}
const sql::dialect &attribute_string_writer::dialect() const {
return dialect_;
@ -67,12 +69,12 @@ void attribute_string_writer::write_value(size_t /*pos*/, const double& x ) {
}
}
void attribute_string_writer::write_value(size_t /*pos*/, const utils::date_type_t& /*x*/ ) {
// result_ = "'" + dialect_.prepare_literal(utils::to_string(x)) + "'";
void attribute_string_writer::write_value(size_t /*pos*/, const utils::date_type_t &x) {
result_ = "'" + dialect_.prepare_literal(utils::to_string(x)) + "'";
}
void attribute_string_writer::write_value(size_t /*pos*/, const utils::time_type_t& /*x*/ ) {
// result_ = "'" + dialect_.prepare_literal(utils::to_string(x, "%F %T.%f")) + "'";
void attribute_string_writer::write_value(size_t /*pos*/, const utils::time_type_t &x) {
result_ = "'" + dialect_.prepare_literal(utils::to_string(x)) + "'";
}
void attribute_string_writer::write_value(size_t /*pos*/, const utils::timestamp &/*x*/) {
@ -101,12 +103,14 @@ void attribute_string_writer::write_value(size_t /*pos*/, const utils::blob& x )
// MSSQL: 0x5468697320697320612062616E617279204461746120737472696E67
// Sqlite: X'5468697320697320612062616E617279204461746120737472696E67'
if (conn_.has_value()) {
result_ = dialect_.token_at(sql::dialect_token::BeginBinaryData) + conn_.value().get().to_escaped_string(x) + dialect_.token_at(sql::dialect_token::EndBinaryData);
result_ = dialect_.token_at(sql::dialect_token::BeginBinaryData) + conn_.value().get().to_escaped_string(x) +
dialect_.token_at(sql::dialect_token::EndBinaryData);
} else {
result_ = dialect_.token_at(sql::dialect_token::BeginBinaryData) + dialect_.to_escaped_string(x) + dialect_.token_at(sql::dialect_token::EndBinaryData);
result_ = dialect_.token_at(sql::dialect_token::BeginBinaryData) + dialect_.to_escaped_string(x) + dialect_.
token_at(sql::dialect_token::EndBinaryData);
}
}
void attribute_string_writer::write_value(size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {}
void attribute_string_writer::write_value(size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {
}
}

View File

@ -3,49 +3,47 @@
#include "matador/sql/interface/query_result_reader.hpp"
namespace matador::sql {
detail::pk_reader::pk_reader(query_result_reader &reader)
: reader_(reader) {}
: reader_(reader) {
}
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<object::attribute> &&prototype, const size_t column_index)
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader,
std::vector<object::attribute> &&prototype,
const size_t column_index)
: column_index_(column_index)
, prototype_(std::move(prototype))
, reader_(std::move(reader))
, pk_reader_(*reader_)
{}
, pk_reader_(*reader_) {
}
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, const std::vector<object::attribute> &prototype, const size_t column_index)
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader,
const std::vector<object::attribute> &prototype,
const size_t column_index)
: column_index_(column_index)
, prototype_(prototype)
, reader_(std::move(reader))
, pk_reader_(*reader_)
{}
, pk_reader_(*reader_) {
}
void query_result_impl::on_revision(const char *id, uint64_t &rev)
{
void query_result_impl::on_revision(const char *id, uint64_t &rev) {
utils::data_type_traits<uint64_t>::read_value(*reader_, id, column_index_++, rev);
reader_->read_value(id, column_index_++, rev);
}
void query_result_impl::on_attribute(const char *id, char *value, const utils::field_attributes &attr)
{
void query_result_impl::on_attribute(const char *id, char *value, const utils::field_attributes &attr) {
utils::data_type_traits<char *>::read_value(*reader_, id, column_index_++, value, attr.size());
}
void query_result_impl::on_attribute(const char *id, std::string &value, const utils::field_attributes &attr)
{
void query_result_impl::on_attribute(const char *id, std::string &value, const utils::field_attributes &attr) {
utils::data_type_traits<std::string>::read_value(*reader_, id, column_index_++, value, attr.size());
}
void
query_result_impl::on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr)
{
query_result_impl::on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr) {
reader_->read_value(id, column_index_++, val, attr.size());
}
const std::vector<object::attribute>& query_result_impl::prototype() const
{
const std::vector<object::attribute> &query_result_impl::prototype() const {
return prototype_;
}
}

View File

@ -61,15 +61,16 @@ void value_extractor::write_value(size_t /*pos*/, const double &x) {
values_.emplace_back(x);
}
void value_extractor::write_value(size_t /*pos*/, const utils::date_type_t &/*x*/) {
// values_.emplace_back(x);
void value_extractor::write_value(size_t /*pos*/, const utils::date_type_t &x) {
values_.emplace_back(x);
}
void value_extractor::write_value(size_t /*pos*/, const utils::time_type_t &/*x*/) {
// values_.emplace_back(x);
void value_extractor::write_value(size_t /*pos*/, const utils::time_type_t &x) {
values_.emplace_back(x);
}
void value_extractor::write_value(size_t /*pos*/, const utils::timestamp &/*x*/) {
void value_extractor::write_value(size_t /*pos*/, const utils::timestamp &x) {
values_.emplace_back(x);
}
void value_extractor::write_value(size_t /*pos*/, const char *x) {

View File

@ -6,7 +6,6 @@
#include "matador/utils/value.hpp"
namespace matador::sql {
const std::string &dialect::token_at(const dialect_token token) const {
return tokens_.at(token);
}
@ -29,8 +28,7 @@ std::string dialect::table_name( const std::string& table, const std::string& sc
return prepare_identifier_string(schema_name) + "." + prepare_identifier_string(table);
}
const std::string& dialect::to_string(const bool val) const
{
const std::string &dialect::to_string(const bool val) const {
return bool_strings_[static_cast<int>(val)];
}
@ -45,14 +43,12 @@ std::string dialect::to_sql_string(const utils::value &val) const {
return val.str();
}
void dialect::bool_strings(const std::string &true_string, const std::string &false_string)
{
void dialect::bool_strings(const std::string &true_string, const std::string &false_string) {
bool_strings_[0] = false_string;
bool_strings_[1] = true_string;
}
std::string dialect::prepare_identifier_string(const std::string &col) const
{
std::string dialect::prepare_identifier_string(const std::string &col) const {
auto parts = utils::split(col, '.');
for (auto &part: parts) {
@ -62,21 +58,18 @@ std::string dialect::prepare_identifier_string(const std::string &col) const
return utils::join(parts, ".");
}
std::string dialect::prepare_literal(const std::string &str) const
{
std::string dialect::prepare_literal(const std::string &str) const {
std::string result(str);
escape_quotes_in_literals(result);
return result;
}
void dialect::quote_identifier(std::string &str) const
{
void dialect::quote_identifier(std::string &str) const {
str.insert(0, token_at(dialect_token::StartQuote));
str += token_at(dialect_token::EndQuote);
}
void dialect::escape_quotes_in_identifier(std::string &str) const
{
void dialect::escape_quotes_in_identifier(std::string &str) const {
const std::string open_char(token_at(dialect_token::StartQuote));
const std::string close_char(token_at(dialect_token::EndQuote));
if (identifier_escape_type() == escape_identifier_t::ESCAPE_CLOSING_BRACKET) {
@ -86,8 +79,7 @@ void dialect::escape_quotes_in_identifier(std::string &str) const
}
}
void dialect::escape_quotes_in_literals(std::string &str) const
{
void dialect::escape_quotes_in_literals(std::string &str) const {
const std::string single_quote(token_at(dialect_token::StringQuote));
const std::string double_quote(token_at(dialect_token::StringQuote) + token_at(dialect_token::StringQuote));
utils::replace_all(str, single_quote, double_quote);
@ -101,13 +93,11 @@ void dialect::identifier_escape_type(escape_identifier_t escape_identifier) {
identifier_escape_type_ = escape_identifier;
}
std::string dialect::next_placeholder(const std::vector<std::string> &bind_vars) const
{
std::string dialect::next_placeholder(const std::vector<std::string> &bind_vars) const {
return placeholder_func_(bind_vars.size());
}
std::string dialect::to_escaped_string(const utils::blob &value, const connection_impl *conn) const
{
std::string dialect::to_escaped_string(const utils::blob &value, const connection_impl *conn) const {
if (conn != nullptr) {
return conn->to_escaped_string(value);
}
@ -115,8 +105,7 @@ std::string dialect::to_escaped_string(const utils::blob &value, const connectio
return to_escaped_string_func_(value);
}
std::string dialect::default_schema_name() const
{
std::string dialect::default_schema_name() const {
return default_schema_name_;
}

View File

@ -26,9 +26,6 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record
const table tab("types");
// auto r = query::create().table(tab).columns({
// column("id", basic_type::UInt32)
// });
auto res = query::create()
.table(tab)
.columns({
@ -46,8 +43,8 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record
column("val_double", basic_type::Double),
column("val_string", basic_type::Text),
column("val_varchar", basic_type::Varchar, 63),
// column("val_date", basic_type::type_date),
// column("val_time", basic_type::type_time),
column("val_date", basic_type::Date),
column("val_time", basic_type::Time),
column("val_blob", basic_type::Blob),
})
.constraints({
@ -66,7 +63,7 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record
"val_bool",
"val_float", "val_double",
"val_string", "val_varchar",
// "val_date", "val_time",
"val_date", "val_time",
"val_blob"};
const auto fields = db.describe("types");
@ -89,41 +86,43 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record
double d{2.71828};
std::string str{"long text"};
std::string varchar{"good day"};
// auto md{matador::date()};
// auto mt{matador::time::now()};
date_type_t md{2025, 11, 27};
time_type_t mt{12, 34, 56};
blob bin{0x01,0x02,0x03,0x04};
res = query::insert()
.into("types", cols)
.values({id, c, s, i, ll, uc, us, ui, ull, b, f, d, str, varchar, /*md, mt, */bin})
.values({id, c, s, i, ll, uc, us, ui, ull, b, f, d, str, varchar, md, mt, bin})
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(res.value() == 1);
auto row = query::select(cols)
auto result = query::select(cols)
.from("types")
.fetch_one(db);
REQUIRE(row.is_ok());
REQUIRE(row.value().has_value());
REQUIRE(result.is_ok());
REQUIRE(result.value().has_value());
REQUIRE(id == (*row)->at<uint32_t>("id"));
REQUIRE(c == (*row)->at<int8_t>("val_char"));
REQUIRE(s == (*row)->at<int16_t>("val_short"));
REQUIRE(i == (*row)->at<int32_t>("val_int"));
REQUIRE(ll == (*row)->at<int64_t>("val_long_long"));
REQUIRE(uc == (*row)->at<uint8_t>("val_uchar"));
REQUIRE(us == (*row)->at<unsigned short>("val_ushort"));
REQUIRE(ui == (*row)->at<unsigned int>("val_uint"));
REQUIRE(ull == (*row)->at<uint64_t>("val_ulong_long"));
REQUIRE((*row)->at<bool>("val_bool"));
REQUIRE(f == (*row)->at<float>("val_float"));
REQUIRE(d == (*row)->at<double>("val_double"));
REQUIRE(str == (*row)->at<std::string>("val_string"));
REQUIRE(varchar == (*row)->at<std::string>("val_varchar"));
// REQUIRE(md == (*row)->at<matador::date>("val_date"));
// REQUIRE(mt == (*row)->at<matador::time>("val_time"));
REQUIRE(bin == (*row)->at<blob>("val_blob"));
const auto &row = result.value().value();
REQUIRE(id == row.at<uint32_t>("id"));
REQUIRE(c == row.at<int8_t>("val_char"));
REQUIRE(s == row.at<int16_t>("val_short"));
REQUIRE(i == row.at<int32_t>("val_int"));
REQUIRE(ll == row.at<int64_t>("val_long_long"));
REQUIRE(uc == row.at<uint8_t>("val_uchar"));
REQUIRE(us == row.at<unsigned short>("val_ushort"));
REQUIRE(ui == row.at<unsigned int>("val_uint"));
REQUIRE(ull == row.at<uint64_t>("val_ulong_long"));
REQUIRE(row.at<bool>("val_bool"));
REQUIRE(f == row.at<float>("val_float"));
REQUIRE(d == row.at<double>("val_double"));
REQUIRE(str == row.at<std::string>("val_string"));
REQUIRE(varchar == row.at<std::string>("val_varchar"));
REQUIRE(md == row.at<date_type_t>("val_date"));
const auto mtres = row.at<time_type_t>("val_time");
REQUIRE(mt == row.at<time_type_t>("val_time"));
REQUIRE(bin == row.at<blob>("val_blob"));
}
TEST_CASE_METHOD(QueryFixture, "Create and drop table statement", "[query][record]")