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:
Duarte Nunes
2018-06-14 12:31:39 +01:00
5 changed files with 224 additions and 2 deletions

View File

@@ -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()) {

View File

@@ -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))};
});
}
}
}
}

View File

@@ -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))
}});
});
}

View File

@@ -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)) {
}

View File

@@ -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>() {