From 90d323a5222f2cd3a64d1f94df325693d01bba37 Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Thu, 14 Jun 2018 11:11:41 +0200 Subject: [PATCH 1/4] types: add time_native_type CQL3's time_type didn't have any suitable native type, so time_native_type is introduced to serve that purpose. --- types.cc | 3 +++ types.hh | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/types.cc b/types.cc index aca7c56341..61c6ec7231 100644 --- a/types.cc +++ b/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)) { } diff --git a/types.hh b/types.hh index 45c78561be..5a8bb64389 100644 --- a/types.hh +++ b/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 data_type_for() { return timestamp_type; } +template <> +inline +shared_ptr data_type_for() { + return time_type; +} + template <> inline shared_ptr data_type_for() { From 087998b76879b00d515267cc8b17cd5c24b5956b Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Tue, 5 Jun 2018 12:48:59 +0200 Subject: [PATCH 2/4] cql3: add current* time functions Following date/time-related functions are added: - currentTimestamp - currentDate - currentTime - currentTimeUUID --- cql3/functions/functions.cc | 4 ++++ cql3/functions/time_uuid_fcts.hh | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/cql3/functions/functions.cc b/cql3/functions/functions.cc index 7a6451b4f4..8516f0c651 100644 --- a/cql3/functions/functions.cc +++ b/cql3/functions/functions.cc @@ -43,6 +43,10 @@ functions::init() { 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_currenttimestamp_fct()); + declare(time_uuid_fcts::make_currentdate_fct()); + declare(time_uuid_fcts::make_currenttime_fct()); + declare(time_uuid_fcts::make_currenttimeuuid_fct()); declare(make_uuid_fct()); for (auto&& type : cql3_type::values()) { diff --git a/cql3/functions/time_uuid_fcts.hh b/cql3/functions/time_uuid_fcts.hh index bf44a69f4f..dbd2edefc7 100644 --- a/cql3/functions/time_uuid_fcts.hh +++ b/cql3/functions/time_uuid_fcts.hh @@ -129,6 +129,43 @@ make_unix_timestamp_of_fcf() { }); } +inline shared_ptr +make_currenttimestamp_fct() { + return make_native_scalar_function("currenttimestamp", timestamp_type, {}, + [] (cql_serialization_format sf, const std::vector& values) -> bytes_opt { + return {timestamp_type->decompose(timestamp_native_type{db_clock::now()})}; + }); +} + +inline shared_ptr +make_currenttime_fct() { + return make_native_scalar_function("currenttime", time_type, {}, + [] (cql_serialization_format sf, const std::vector& values) -> bytes_opt { + constexpr int64_t milliseconds_in_day = 3600 * 24 * 1000; + int64_t milliseconds_since_epoch = std::chrono::duration_cast(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 +make_currentdate_fct() { + return make_native_scalar_function("currentdate", simple_date_type, {}, + [] (cql_serialization_format sf, const std::vector& 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 +make_currenttimeuuid_fct() { + return make_native_scalar_function("currenttimeuuid", timeuuid_type, {}, + [] (cql_serialization_format sf, const std::vector& values) -> bytes_opt { + return {timeuuid_type->decompose(timeuuid_native_type{utils::UUID_gen::get_time_UUID()})}; + }); +} + } } } From 695015a27ecf08b27497a1610f6084be277fa8ad Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Tue, 5 Jun 2018 13:22:01 +0200 Subject: [PATCH 3/4] cql3: add time conversion functions Following functions are added: - timeuuidtodate - timestamptodate - timeuuidtotimestamp - datetotimestamp - timeuuidtounixtimestamp - timestamptounixtimestamp - datetounixtimestamp Fixes #2949 --- cql3/functions/functions.cc | 9 ++- cql3/functions/time_uuid_fcts.hh | 122 ++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/cql3/functions/functions.cc b/cql3/functions/functions.cc index 8516f0c651..1960f51fc0 100644 --- a/cql3/functions/functions.cc +++ b/cql3/functions/functions.cc @@ -42,11 +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()) { diff --git a/cql3/functions/time_uuid_fcts.hh b/cql3/functions/time_uuid_fcts.hh index dbd2edefc7..14ec7be84d 100644 --- a/cql3/functions/time_uuid_fcts.hh +++ b/cql3/functions/time_uuid_fcts.hh @@ -117,7 +117,7 @@ make_date_of_fct() { inline shared_ptr -make_unix_timestamp_of_fcf() { +make_unix_timestamp_of_fct() { return make_native_scalar_function("unixtimestampof", long_type, { timeuuid_type }, [] (cql_serialization_format sf, const std::vector& values) -> bytes_opt { using namespace utils; @@ -166,6 +166,126 @@ make_currenttimeuuid_fct() { }); } +inline +shared_ptr +make_timeuuidtodate_fct() { + return make_native_scalar_function("todate", simple_date_type, { timeuuid_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_timestamptodate_fct() { + return make_native_scalar_function("todate", simple_date_type, { timestamp_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_timeuuidtotimestamp_fct() { + return make_native_scalar_function("totimestamp", timestamp_type, { timeuuid_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_datetotimestamp_fct() { + return make_native_scalar_function("totimestamp", timestamp_type, { simple_date_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_timeuuidtounixtimestamp_fct() { + return make_native_scalar_function("tounixtimestamp", long_type, { timeuuid_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_timestamptounixtimestamp_fct() { + return make_native_scalar_function("tounixtimestamp", long_type, { timestamp_type }, + [] (cql_serialization_format sf, const std::vector& 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 +make_datetounixtimestamp_fct() { + return make_native_scalar_function("tounixtimestamp", long_type, { simple_date_type }, + [] (cql_serialization_format sf, const std::vector& 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))}; + }); +} + } } } From 5900e7f55f4e3b3b0da2d8f85edace57de488d26 Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Wed, 6 Jun 2018 08:26:21 +0200 Subject: [PATCH 4/4] tests: add datetime conversions to cql_query_tests Test case related to datetime converting functions is added to cql_query_tests suite. --- tests/cql_query_test.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/cql_query_test.cc b/tests/cql_query_test.cc index 0a8151547a..5fb78135f3 100644 --- a/tests/cql_query_test.cc +++ b/tests/cql_query_test.cc @@ -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)) + }}); + + }); +}