Merge "Support for MIN/MAX aggregation functions over date-types" from Dan

"Added support for min/max functions over date/timestamp/timeuuid.

There was one issue with Scylla's type system internals: no C++ type
was mapped to these types. So special "native_types" were added for them.
It required some changes to native functions because these types don't support
the same operations as their real native counterparts.

Fixes #3104."

* 'danfiala/3104-v1' of https://github.com/hagrid-the-developer/scylla:
  tests: Tests for min/max aggregate functions over date/timestamp and timeuuid.
  functions: Added min/max functions for date/timestamp/timeuuid.
  types: Added native types for timestamp and timeuuid.
  Advertise compatibility with CQL Version 3.3.2, since CAST functions are supported.
This commit is contained in:
Avi Kivity
2018-01-14 17:26:27 +02:00
6 changed files with 92 additions and 17 deletions

View File

@@ -227,9 +227,29 @@ make_avg_function() {
return make_shared<avg_function_for<Type>>();
}
template <typename T>
struct aggregate_type_for {
using type = T;
};
template<>
struct aggregate_type_for<simple_date_native_type> {
using type = simple_date_native_type::primary_type;
};
template<>
struct aggregate_type_for<timestamp_native_type> {
using type = timestamp_native_type::primary_type;
};
template<>
struct aggregate_type_for<timeuuid_native_type> {
using type = timeuuid_native_type::primary_type;
};
template <typename Type>
class impl_max_function_for final : public aggregate_function::aggregate {
std::experimental::optional<Type> _max{};
std::experimental::optional<typename aggregate_type_for<Type>::type> _max{};
public:
virtual void reset() override {
_max = {};
@@ -238,13 +258,13 @@ public:
if (!_max) {
return {};
}
return data_type_for<Type>()->decompose(*_max);
return data_type_for<Type>()->decompose(Type{*_max});
}
virtual void add_input(cql_serialization_format sf, const std::vector<opt_bytes>& values) override {
if (!values[0]) {
return;
}
auto val = value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
auto val = value_cast<typename aggregate_type_for<Type>::type>(data_type_for<Type>()->deserialize(*values[0]));
if (!_max) {
_max = val;
} else {
@@ -276,7 +296,7 @@ make_max_function() {
template <typename Type>
class impl_min_function_for final : public aggregate_function::aggregate {
std::experimental::optional<Type> _min{};
std::experimental::optional<typename aggregate_type_for<Type>::type> _min{};
public:
virtual void reset() override {
_min = {};
@@ -285,13 +305,13 @@ public:
if (!_min) {
return {};
}
return data_type_for<Type>()->decompose(*_min);
return data_type_for<Type>()->decompose(Type{*_min});
}
virtual void add_input(cql_serialization_format sf, const std::vector<opt_bytes>& values) override {
if (!values[0]) {
return;
}
auto val = value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
auto val = value_cast<typename aggregate_type_for<Type>::type>(data_type_for<Type>()->deserialize(*values[0]));
if (!_min) {
_min = val;
} else {

View File

@@ -95,6 +95,15 @@ functions::init() {
declare(aggregate_fcts::make_max_function<sstring>());
declare(aggregate_fcts::make_min_function<sstring>());
declare(aggregate_fcts::make_max_function<simple_date_native_type>());
declare(aggregate_fcts::make_min_function<simple_date_native_type>());
declare(aggregate_fcts::make_max_function<timestamp_native_type>());
declare(aggregate_fcts::make_min_function<timestamp_native_type>());
declare(aggregate_fcts::make_max_function<timeuuid_native_type>());
declare(aggregate_fcts::make_min_function<timeuuid_native_type>());
//FIXME:
//declare(aggregate_fcts::make_count_function<bytes>());
//declare(aggregate_fcts::make_max_function<bytes>());

View File

@@ -61,7 +61,7 @@ logging::logger prep_cache_log("prepared_statements_cache");
distributed<query_processor> _the_query_processor;
const sstring query_processor::CQL_VERSION = "3.3.1";
const sstring query_processor::CQL_VERSION = "3.3.2";
const std::chrono::minutes prepared_statements_cache::entry_expiry = std::chrono::minutes(60);

View File

@@ -51,10 +51,13 @@ void create_table(Env &e) {
" g_0 decimal,"
" g_2 decimal,"
" h varint, "
" t text)").get();
" t text,"
" dt date,"
" tm timestamp,"
" tu timeuuid)").get();
e.execute_cql("INSERT INTO test (a, b, c, d, e, f, g_0, g_2, h, t) VALUES (1, 1, 1, 1, 1, 1, 1, 1.00, 1, 'a')").get();
e.execute_cql("INSERT INTO test (a, b, c, d, e, f, g_0, g_2, h, t) VALUES (2, 2, 2, 2, 2, 2, 2, 2.00, 2, 'b')").get();
e.execute_cql("INSERT INTO test (a, b, c, d, e, f, g_0, g_2, h, t, dt, tm, tu) VALUES (1, 1, 1, 1, 1, 1, 1, 1.00, 1, 'a', '2017-12-02', '2017-12-02t03:00:00', b650cbe0-f914-11e7-8892-000000000004)").get();
e.execute_cql("INSERT INTO test (a, b, c, d, e, f, g_0, g_2, h, t, dt, tm, tu) VALUES (2, 2, 2, 2, 2, 2, 2, 2.00, 2, 'b', '2016-12-02', '2016-12-02t06:00:00', D2177dD0-EAa2-11de-a572-001B779C76e3)").get();
}
} /* anonymous namespace */
@@ -123,8 +126,11 @@ SEASTAR_TEST_CASE(test_aggregate_max) {
"max(f), "
"max(g_0), "
"max(g_2), "
"max(h),"
"max(t) FROM test").get0();
"max(h), "
"max(t), "
"max(dt), "
"max(tm), "
"max(tu) FROM test").get0();
assert_that(msg).is_rows().with_size(1).with_row({{byte_type->decompose(int8_t(2))},
{short_type->decompose(int16_t(2))},
@@ -135,7 +141,10 @@ SEASTAR_TEST_CASE(test_aggregate_max) {
{decimal_type->from_string("2")},
{decimal_type->from_string("2.00")},
{varint_type->from_string("2")},
{utf8_type->from_string("b")}});
{utf8_type->from_string("b")},
{simple_date_type->from_string("2017-12-02")},
{timestamp_type->from_string("2017-12-02t03:00:00")},
{timeuuid_type->from_string("D2177dD0-EAa2-11de-a572-001B779C76e3")}});
});
}
@@ -151,8 +160,11 @@ SEASTAR_TEST_CASE(test_aggregate_min) {
"min(f), "
"min(g_0), "
"min(g_2), "
"min(h),"
"min(t) FROM test").get0();
"min(h), "
"min(t), "
"min(dt), "
"min(tm), "
"min(tu) FROM test").get0();
assert_that(msg).is_rows().with_size(1).with_row({{byte_type->decompose(int8_t(1))},
{short_type->decompose(int16_t(1))},
@@ -163,7 +175,10 @@ SEASTAR_TEST_CASE(test_aggregate_min) {
{decimal_type->from_string("1")},
{decimal_type->from_string("1.00")},
{varint_type->from_string("1")},
{utf8_type->from_string("a")}});
{utf8_type->from_string("a")},
{simple_date_type->from_string("2016-12-02")},
{timestamp_type->from_string("2016-12-02t06:00:00")},
{timeuuid_type->from_string("b650cbe0-f914-11e7-8892-000000000004")}});
});
}

View File

@@ -3347,6 +3347,12 @@ data_value::data_value(net::ipv4_address v) : data_value(make_new(inet_addr_type
data_value::data_value(simple_date_native_type v) : data_value(make_new(simple_date_type, v.days)) {
}
data_value::data_value(timestamp_native_type v) : data_value(make_new(timestamp_type, v.tp)) {
}
data_value::data_value(timeuuid_native_type v) : data_value(make_new(timeuuid_type, v.uuid)) {
}
data_value::data_value(db_clock::time_point v) : data_value(make_new(date_type, v)) {
}

View File

@@ -321,7 +321,18 @@ class abstract_type;
class data_value;
struct simple_date_native_type {
uint32_t days;
using primary_type = uint32_t;
primary_type days;
};
struct timestamp_native_type {
using primary_type = db_clock::time_point;
primary_type tp;
};
struct timeuuid_native_type {
using primary_type = utils::UUID;
primary_type uuid;
};
using data_type = shared_ptr<const abstract_type>;
@@ -360,6 +371,8 @@ public:
data_value(double);
data_value(net::ipv4_address);
data_value(simple_date_native_type);
data_value(timestamp_native_type);
data_value(timeuuid_native_type);
data_value(db_clock::time_point);
data_value(boost::multiprecision::cpp_int);
data_value(big_decimal);
@@ -1237,6 +1250,18 @@ shared_ptr<const abstract_type> data_type_for<simple_date_native_type>() {
return simple_date_type;
}
template <>
inline
shared_ptr<const abstract_type> data_type_for<timestamp_native_type>() {
return timestamp_type;
}
template <>
inline
shared_ptr<const abstract_type> data_type_for<timeuuid_native_type>() {
return timeuuid_type;
}
template <>
inline
shared_ptr<const abstract_type> data_type_for<net::ipv4_address>() {