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:
@@ -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 {
|
||||
|
||||
@@ -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>());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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")}});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
6
types.cc
6
types.cc
@@ -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)) {
|
||||
}
|
||||
|
||||
|
||||
27
types.hh
27
types.hh
@@ -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>() {
|
||||
|
||||
Reference in New Issue
Block a user