diff --git a/cql3/functions/functions.cc b/cql3/functions/functions.cc index 7a6451b4f4..1960f51fc0 100644 --- a/cql3/functions/functions.cc +++ b/cql3/functions/functions.cc @@ -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()) { diff --git a/cql3/functions/time_uuid_fcts.hh b/cql3/functions/time_uuid_fcts.hh index bf44a69f4f..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; @@ -129,6 +129,163 @@ 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()})}; + }); +} + +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))}; + }); +} + } } } 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)) + }}); + + }); +} 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() {