mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-04 05:53:13 +00:00
Merge "Add support for datetime functions" from Piotr
" This series adds the following datetime functions to CQL: - currentTimestamp - currentDate - currentTime - currentTimeUUID - timeUUIDToDate - timestampToDate - timeUUIDToTimestamp - dateToTimestamp - timeUUIDToUnixTimestamp - timestampToUnixTimestamp - dateToUnixTimestamp It also comes with datetime conversions test added to cql_query_test. Note: issue #2949 also mentioned queries like: $ SELECT * FROM myTable WHERE date >= currentDate() - 2d; but it's a broader topic of supporting arithmetic operations in general, so it's moved to #3499. Tests: unit (release) " * 'support_datetime_functions_3' of https://github.com/psarna/scylla: tests: add datetime conversions to cql_query_tests cql3: add time conversion functions cql3: add current* time functions types: add time_native_type
This commit is contained in:
@@ -42,7 +42,18 @@ functions::init() {
|
||||
declare(time_uuid_fcts::make_min_timeuuid_fct());
|
||||
declare(time_uuid_fcts::make_max_timeuuid_fct());
|
||||
declare(time_uuid_fcts::make_date_of_fct());
|
||||
declare(time_uuid_fcts::make_unix_timestamp_of_fcf());
|
||||
declare(time_uuid_fcts::make_unix_timestamp_of_fct());
|
||||
declare(time_uuid_fcts::make_currenttimestamp_fct());
|
||||
declare(time_uuid_fcts::make_currentdate_fct());
|
||||
declare(time_uuid_fcts::make_currenttime_fct());
|
||||
declare(time_uuid_fcts::make_currenttimeuuid_fct());
|
||||
declare(time_uuid_fcts::make_timeuuidtodate_fct());
|
||||
declare(time_uuid_fcts::make_timestamptodate_fct());
|
||||
declare(time_uuid_fcts::make_timeuuidtotimestamp_fct());
|
||||
declare(time_uuid_fcts::make_datetotimestamp_fct());
|
||||
declare(time_uuid_fcts::make_timeuuidtounixtimestamp_fct());
|
||||
declare(time_uuid_fcts::make_timestamptounixtimestamp_fct());
|
||||
declare(time_uuid_fcts::make_datetounixtimestamp_fct());
|
||||
declare(make_uuid_fct());
|
||||
|
||||
for (auto&& type : cql3_type::values()) {
|
||||
|
||||
@@ -117,7 +117,7 @@ make_date_of_fct() {
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_unix_timestamp_of_fcf() {
|
||||
make_unix_timestamp_of_fct() {
|
||||
return make_native_scalar_function<true>("unixtimestampof", long_type, { timeuuid_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
@@ -129,6 +129,163 @@ make_unix_timestamp_of_fcf() {
|
||||
});
|
||||
}
|
||||
|
||||
inline shared_ptr<function>
|
||||
make_currenttimestamp_fct() {
|
||||
return make_native_scalar_function<true>("currenttimestamp", timestamp_type, {},
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
return {timestamp_type->decompose(timestamp_native_type{db_clock::now()})};
|
||||
});
|
||||
}
|
||||
|
||||
inline shared_ptr<function>
|
||||
make_currenttime_fct() {
|
||||
return make_native_scalar_function<true>("currenttime", time_type, {},
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
constexpr int64_t milliseconds_in_day = 3600 * 24 * 1000;
|
||||
int64_t milliseconds_since_epoch = std::chrono::duration_cast<std::chrono::milliseconds>(db_clock::now().time_since_epoch()).count();
|
||||
int64_t nanoseconds_today = (milliseconds_since_epoch % milliseconds_in_day) * 1000 * 1000;
|
||||
return {time_type->decompose(time_native_type{nanoseconds_today})};
|
||||
});
|
||||
}
|
||||
|
||||
inline shared_ptr<function>
|
||||
make_currentdate_fct() {
|
||||
return make_native_scalar_function<true>("currentdate", simple_date_type, {},
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
auto to_simple_date = get_castas_fctn(simple_date_type, timestamp_type);
|
||||
return {simple_date_type->decompose(to_simple_date(timestamp_native_type{db_clock::now()}))};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_currenttimeuuid_fct() {
|
||||
return make_native_scalar_function<true>("currenttimeuuid", timeuuid_type, {},
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
return {timeuuid_type->decompose(timeuuid_native_type{utils::UUID_gen::get_time_UUID()})};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_timeuuidtodate_fct() {
|
||||
return make_native_scalar_function<true>("todate", simple_date_type, { timeuuid_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto ts = db_clock::time_point(db_clock::duration(UUID_gen::unix_timestamp(UUID_gen::get_UUID(*bb))));
|
||||
auto to_simple_date = get_castas_fctn(simple_date_type, timestamp_type);
|
||||
return {simple_date_type->decompose(to_simple_date(ts))};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_timestamptodate_fct() {
|
||||
return make_native_scalar_function<true>("todate", simple_date_type, { timestamp_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto ts_obj = timestamp_type->deserialize(*bb);
|
||||
if (ts_obj.is_null()) {
|
||||
return {};
|
||||
}
|
||||
auto to_simple_date = get_castas_fctn(simple_date_type, timestamp_type);
|
||||
return {simple_date_type->decompose(to_simple_date(ts_obj))};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_timeuuidtotimestamp_fct() {
|
||||
return make_native_scalar_function<true>("totimestamp", timestamp_type, { timeuuid_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto ts = db_clock::time_point(db_clock::duration(UUID_gen::unix_timestamp(UUID_gen::get_UUID(*bb))));
|
||||
return {timestamp_type->decompose(ts)};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_datetotimestamp_fct() {
|
||||
return make_native_scalar_function<true>("totimestamp", timestamp_type, { simple_date_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto simple_date_obj = simple_date_type->deserialize(*bb);
|
||||
if (simple_date_obj.is_null()) {
|
||||
return {};
|
||||
}
|
||||
auto from_simple_date = get_castas_fctn(timestamp_type, simple_date_type);
|
||||
return {timestamp_type->decompose(from_simple_date(simple_date_obj))};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_timeuuidtounixtimestamp_fct() {
|
||||
return make_native_scalar_function<true>("tounixtimestamp", long_type, { timeuuid_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
return {long_type->decompose(UUID_gen::unix_timestamp(UUID_gen::get_UUID(*bb)))};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_timestamptounixtimestamp_fct() {
|
||||
return make_native_scalar_function<true>("tounixtimestamp", long_type, { timestamp_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto ts_obj = timestamp_type->deserialize(*bb);
|
||||
if (ts_obj.is_null()) {
|
||||
return {};
|
||||
}
|
||||
return {long_type->decompose(ts_obj)};
|
||||
});
|
||||
}
|
||||
|
||||
inline
|
||||
shared_ptr<function>
|
||||
make_datetounixtimestamp_fct() {
|
||||
return make_native_scalar_function<true>("tounixtimestamp", long_type, { simple_date_type },
|
||||
[] (cql_serialization_format sf, const std::vector<bytes_opt>& values) -> bytes_opt {
|
||||
using namespace utils;
|
||||
auto& bb = values[0];
|
||||
if (!bb) {
|
||||
return {};
|
||||
}
|
||||
auto simple_date_obj = simple_date_type->deserialize(*bb);
|
||||
if (simple_date_obj.is_null()) {
|
||||
return {};
|
||||
}
|
||||
auto from_simple_date = get_castas_fctn(timestamp_type, simple_date_type);
|
||||
return {long_type->decompose(from_simple_date(simple_date_obj))};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2950,3 +2950,42 @@ SEASTAR_TEST_CASE(test_long_text_value) {
|
||||
assert_that(msg).is_rows().with_rows({{utf8_type->decompose(bigger_one), utf8_type->decompose(bigger_one)}});
|
||||
});
|
||||
}
|
||||
|
||||
SEASTAR_TEST_CASE(test_time_conversions) {
|
||||
return do_with_cql_env_thread([] (cql_test_env& e) {
|
||||
auto prepared = e.execute_cql(
|
||||
"CREATE TABLE time_data (id timeuuid PRIMARY KEY, d date, ts timestamp);").get();
|
||||
e.require_table_exists("ks", "time_data").get();
|
||||
|
||||
e.execute_cql("INSERT INTO time_data (id, d, ts) VALUES (f4e30f80-6958-11e8-96d6-000000000000, '2017-06-11', '2018-06-05 00:00:00+0000');").get();
|
||||
|
||||
struct tm t = { 0 };
|
||||
t.tm_year = 2018 - 1900;
|
||||
t.tm_mon = 6 - 1;
|
||||
t.tm_mday = 6;
|
||||
t.tm_hour = 7;
|
||||
t.tm_min = 12;
|
||||
t.tm_sec = 22;
|
||||
auto tp1 = db_clock::from_time_t(timegm(&t)) + std::chrono::milliseconds(136);
|
||||
t.tm_year = 2017 - 1900;
|
||||
t.tm_mday = 11;
|
||||
t.tm_hour = 0;
|
||||
t.tm_min = 0;
|
||||
t.tm_sec = 0;
|
||||
auto tp2 = db_clock::from_time_t(timegm(&t));
|
||||
|
||||
auto msg = e.execute_cql("select todate(id), todate(ts), totimestamp(id), totimestamp(d), tounixtimestamp(id),"
|
||||
"tounixtimestamp(ts), tounixtimestamp(d), tounixtimestamp(totimestamp(todate(totimestamp(todate(id))))) from time_data;").get0();
|
||||
assert_that(msg).is_rows().with_rows({{
|
||||
simple_date_type->decompose(int32_t(0x80004518)),
|
||||
simple_date_type->decompose(int32_t(0x80004517)),
|
||||
timestamp_type->decompose(tp1),
|
||||
timestamp_type->decompose(tp2),
|
||||
long_type->decompose(int64_t(1528269142136)),
|
||||
long_type->decompose(int64_t(1528156800000)),
|
||||
long_type->decompose(int64_t(1497139200000)),
|
||||
long_type->decompose(int64_t(1528243200000))
|
||||
}});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
3
types.cc
3
types.cc
@@ -3720,6 +3720,9 @@ data_value::data_value(simple_date_native_type v) : data_value(make_new(simple_d
|
||||
data_value::data_value(timestamp_native_type v) : data_value(make_new(timestamp_type, v.tp)) {
|
||||
}
|
||||
|
||||
data_value::data_value(time_native_type v) : data_value(make_new(time_type, v.nanoseconds)) {
|
||||
}
|
||||
|
||||
data_value::data_value(timeuuid_native_type v) : data_value(make_new(timeuuid_type, v.uuid)) {
|
||||
}
|
||||
|
||||
|
||||
12
types.hh
12
types.hh
@@ -328,6 +328,11 @@ struct timestamp_native_type {
|
||||
primary_type tp;
|
||||
};
|
||||
|
||||
struct time_native_type {
|
||||
using primary_type = int64_t;
|
||||
primary_type nanoseconds;
|
||||
};
|
||||
|
||||
struct timeuuid_native_type {
|
||||
using primary_type = utils::UUID;
|
||||
primary_type uuid;
|
||||
@@ -371,6 +376,7 @@ public:
|
||||
data_value(seastar::net::inet_address);
|
||||
data_value(simple_date_native_type);
|
||||
data_value(timestamp_native_type);
|
||||
data_value(time_native_type);
|
||||
data_value(timeuuid_native_type);
|
||||
data_value(db_clock::time_point);
|
||||
data_value(boost::multiprecision::cpp_int);
|
||||
@@ -1285,6 +1291,12 @@ shared_ptr<const abstract_type> data_type_for<timestamp_native_type>() {
|
||||
return timestamp_type;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
shared_ptr<const abstract_type> data_type_for<time_native_type>() {
|
||||
return time_type;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
shared_ptr<const abstract_type> data_type_for<timeuuid_native_type>() {
|
||||
|
||||
Reference in New Issue
Block a user