0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Add support for TIME columns in postgresql

This commit is contained in:
Jürgen Hunold 2022-02-07 20:45:39 +01:00 committed by Roland Bock
parent b2166c636b
commit f7f2060c44
4 changed files with 204 additions and 13 deletions

View File

@ -104,6 +104,7 @@ namespace sqlpp
void _bind_text_result(size_t index, const char** value, size_t* len); void _bind_text_result(size_t index, const char** value, size_t* len);
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null); void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null);
void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null); void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null);
void _bind_time_of_day_result(size_t index, ::std::chrono::microseconds* value, bool* is_null);
void _bind_blob_result(size_t index, const uint8_t** value, size_t* len); void _bind_blob_result(size_t index, const uint8_t** value, size_t* len);
int size() const; int size() const;
@ -401,6 +402,54 @@ namespace sqlpp
} }
} }
// always returns local time for time with time zone
inline void bind_result_t::_bind_time_of_day_result(size_t _index, ::std::chrono::microseconds* value, bool* is_null)
{
auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding time result at index: " << index << std::endl;
}
*is_null = _handle->result.isNull(_handle->count, index);
if (!(*is_null))
{
const auto time_string = _handle->result.getCharPtrValue(_handle->count, index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: got time string: " << time_string << std::endl;
}
if (detail::check_time_digits(time_string))
{
*value += std::chrono::hours(std::atoi(time_string)) + std::chrono::minutes(std::atoi(time_string + 3)) +
std::chrono::seconds(std::atoi(time_string + 6));
}
else
{
return;
}
if (std::strlen(time_string) <= 9)
return;
auto us_string = time_string + 9; // hh:mm:ss.
int usec = 0;
for (size_t i = 0u; i < 6u; ++i)
{
if (std::isdigit(us_string[0]))
{
usec = 10 * usec + (us_string[0] - '0');
++us_string;
}
else
usec *= 10;
}
*value += ::std::chrono::microseconds(usec);
}
}
inline void bind_result_t::_bind_blob_result(size_t _index, const uint8_t** value, size_t* len) inline void bind_result_t::_bind_blob_result(size_t _index, const uint8_t** value, size_t* len)
{ {

View File

@ -78,6 +78,7 @@ namespace sqlpp
void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null); void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null);
void _bind_text_parameter(size_t index, const std::string* value, bool is_null); void _bind_text_parameter(size_t index, const std::string* value, bool is_null);
void _bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null); void _bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null);
void _bind_time_of_day_parameter(size_t index, const ::std::chrono::microseconds* value, bool is_null);
void _bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null); void _bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null);
void _bind_blob_parameter(size_t index, const std::vector<unsigned char>* value, bool is_null); void _bind_blob_parameter(size_t index, const std::vector<unsigned char>* value, bool is_null);
}; };
@ -187,6 +188,30 @@ namespace sqlpp
} }
} }
inline void prepared_statement_t::_bind_time_of_day_parameter(size_t index, const ::std::chrono::microseconds* value, bool is_null)
{
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding time parameter at index "
<< index << ", being " << (is_null ? "" : "not ") << "null" << std::endl;
}
_handle->nullValues[index] = is_null;
if (not is_null)
{
const auto time = ::date::make_time(*value) ;
// Timezone handling - always treat the value as UTC.
// It is assumed that the database timezone is set to UTC, too.
std::ostringstream os;
os << time;
_handle->paramValues[index] = os.str();
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding time parameter string: " << _handle->paramValues[index] << std::endl;
}
}
}
inline void prepared_statement_t::_bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null) inline void prepared_statement_t::_bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null)
{ {
if (_handle->debug()) if (_handle->debug())

View File

@ -31,7 +31,7 @@
#include <sqlpp11/postgresql/postgresql.h> #include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include "TabFoo.h" #include "TabDateTime.h"
#include "make_test_connection.h" #include "make_test_connection.h"
namespace namespace
@ -39,6 +39,7 @@ namespace
const auto now = ::date::floor<::std::chrono::microseconds>(std::chrono::system_clock::now()); const auto now = ::date::floor<::std::chrono::microseconds>(std::chrono::system_clock::now());
const auto today = ::date::floor<::sqlpp::chrono::days>(now); const auto today = ::date::floor<::sqlpp::chrono::days>(now);
const auto yesterday = today - ::sqlpp::chrono::days{1}; const auto yesterday = today - ::sqlpp::chrono::days{1};
const auto current = now - today;
template <typename L, typename R> template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void auto require_equal(int line, const L& l, const R& r) -> void
@ -60,18 +61,15 @@ int DateTime(int, char*[])
sql::connection db = sql::make_test_connection(); sql::connection db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)"); db.execute(R"(DROP TABLE IF EXISTS tabdatetime;)");
db.execute(R"(CREATE TABLE tabfoo db.execute(R"(CREATE TABLE tabdatetime
( (
alpha bigserial NOT NULL,
beta smallint,
gamma text,
c_bool boolean,
c_timepoint timestamp with time zone, c_timepoint timestamp with time zone,
c_time time with time zone,
c_day date c_day date
))"); ))");
model::TabFoo tab = {}; model::TabDateTime tab = {};
try try
{ {
db(insert_into(tab).default_values()); db(insert_into(tab).default_values());
@ -79,15 +77,18 @@ int DateTime(int, char*[])
{ {
require_equal(__LINE__, row.c_day.is_null(), true); require_equal(__LINE__, row.c_day.is_null(), true);
require_equal(__LINE__, row.c_day.value(), ::sqlpp::chrono::day_point{}); require_equal(__LINE__, row.c_day.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.c_time.is_null(), true);
require_equal(__LINE__, row.c_time.value(), ::std::chrono::microseconds{});
require_equal(__LINE__, row.c_timepoint.is_null(), true); require_equal(__LINE__, row.c_timepoint.is_null(), true);
require_equal(__LINE__, row.c_timepoint.value(), ::sqlpp::chrono::microsecond_point{}); require_equal(__LINE__, row.c_timepoint.value(), ::sqlpp::chrono::microsecond_point{});
} }
db(update(tab).set(tab.c_day = today, tab.c_timepoint = now).unconditionally()); db(update(tab).set(tab.c_day = today, tab.c_time = current, tab.c_timepoint = now).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{ {
require_equal(__LINE__, row.c_day.value(), today); require_equal(__LINE__, row.c_day.value(), today);
require_equal(__LINE__, row.c_time.value(), current);
require_equal(__LINE__, row.c_timepoint.value(), now); require_equal(__LINE__, row.c_timepoint.value(), now);
} }
@ -96,14 +97,17 @@ int DateTime(int, char*[])
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{ {
require_equal(__LINE__, row.c_day.value(), yesterday); require_equal(__LINE__, row.c_day.value(), yesterday);
require_equal(__LINE__, row.c_time.value(), current);
require_equal(__LINE__, row.c_timepoint.value(), today); require_equal(__LINE__, row.c_timepoint.value(), today);
} }
auto prepared_update = auto prepared_update = db.prepare(update(tab)
db.prepare(update(tab) .set(tab.c_day = parameter(tab.c_day),
.set(tab.c_day = parameter(tab.c_day), tab.c_timepoint = parameter(tab.c_timepoint)) tab.c_time = parameter(tab.c_time),
tab.c_timepoint = parameter(tab.c_timepoint))
.unconditionally()); .unconditionally());
prepared_update.params.c_day = today; prepared_update.params.c_day = today;
prepared_update.params.c_time = current;
prepared_update.params.c_timepoint = now; prepared_update.params.c_timepoint = now;
std::cout << "---- running prepared update ----" << std::endl; std::cout << "---- running prepared update ----" << std::endl;
db(prepared_update); db(prepared_update);
@ -111,6 +115,7 @@ int DateTime(int, char*[])
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{ {
require_equal(__LINE__, row.c_day.value(), today); require_equal(__LINE__, row.c_day.value(), today);
require_equal(__LINE__, row.c_time.value(), current);
require_equal(__LINE__, row.c_timepoint.value(), now); require_equal(__LINE__, row.c_timepoint.value(), now);
} }
} }

View File

@ -0,0 +1,112 @@
#ifndef MODEL_TABDATETIME_H
#define MODEL_TABDATETIME_H
#include <sqlpp11/table.h>
#include <sqlpp11/char_sequence.h>
#include <sqlpp11/column_types.h>
namespace model
{
namespace TabDateTime_
{
struct C_timepoint
{
struct _alias_t
{
static constexpr const char _literal[] = "c_timepoint";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_timepoint;
T& operator()()
{
return c_timepoint;
}
const T& operator()() const
{
return c_timepoint;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::time_point, sqlpp::tag::can_be_null>;
};
struct C_day
{
struct _alias_t
{
static constexpr const char _literal[] = "c_day";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_day;
T& operator()()
{
return c_day;
}
const T& operator()() const
{
return c_day;
}
};
};
using _traits = ::sqlpp::make_traits<::sqlpp::day_point, sqlpp::tag::can_be_null>;
};
struct C_time
{
struct _alias_t
{
static constexpr const char _literal[] = "c_time";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T c_time;
T& operator()()
{
return c_time;
}
const T& operator()() const
{
return c_time;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::time_of_day, sqlpp::tag::can_be_null>;
};
} // namespace TabDatetime_
struct TabDateTime : sqlpp::table_t<TabDateTime,
TabDateTime_::C_time,
TabDateTime_::C_day,
TabDateTime_::C_timepoint>
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
{
static constexpr const char _literal[] = "TabDatetime";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T TabDateTime;
T& operator()()
{
return TabDateTime;
}
const T& operator()() const
{
return TabDateTime;
}
};
};
};
}
#endif