Merge 'Allow multi-parameter user-defined aggregates' from Piotr Sarna
Due to an overzealous assertion put in the code (in one of the last iterations, by the way!) it was impossible to create an aggregate which accepts multiple arguments. The behavior is now fixed, and a test case is provided for it. Tests: unit(release) Closes #9211 * github.com:scylladb/scylla: cql-pytest: add test case for UDA with multiple args cql3: fix aggregates with > 1 argument
This commit is contained in:
@@ -501,7 +501,7 @@ static shared_ptr<aggregate_function> make_count_function() {
|
||||
// Drops the first arg type from the types declaration (which denotes the accumulator)
|
||||
// in order to compute the actual type of given user-defined-aggregate (UDA)
|
||||
static std::vector<data_type> state_arg_types_to_uda_arg_types(const std::vector<data_type>& arg_types) {
|
||||
if(arg_types.size() != 2) {
|
||||
if(arg_types.size() < 2) {
|
||||
on_internal_error(cql3::functions::log, "State function for user-defined aggregates needs at least two arguments");
|
||||
}
|
||||
std::vector<data_type> types;
|
||||
|
||||
@@ -40,6 +40,21 @@ def test_custom_avg(scylla_only, cql, test_keyspace):
|
||||
avg_res = [row for row in cql.execute(f"SELECT avg(id) AS result FROM {table}")]
|
||||
assert custom_res == avg_res
|
||||
|
||||
# Test that computing an aggregate which takes 2 parameters works fine.
|
||||
# In this case - it's a simple map literal builder.
|
||||
def test_map_literal_builder(scylla_only, cql, test_keyspace):
|
||||
schema = 'id int, k text, val int, primary key (id, k)'
|
||||
with new_test_table(cql, test_keyspace, schema) as table:
|
||||
for i in range(8):
|
||||
cql.execute(f"INSERT INTO {table} (id, k, val) VALUES (0, '{chr(ord('a') + i)}', {i})")
|
||||
map_literal_partial_body = "(state text, id text, val int) RETURNS NULL ON NULL INPUT RETURNS text LANGUAGE lua AS 'return state..id..\":\"..tostring(val)..\",\"'"
|
||||
finish_body = "(state text) CALLED ON NULL INPUT RETURNS text LANGUAGE lua AS 'return state..\"}\"'"
|
||||
with new_function(cql, test_keyspace, map_literal_partial_body) as map_literal_partial, new_function(cql, test_keyspace, finish_body) as finish_fun:
|
||||
map_literal_body = f"(text, int) SFUNC {map_literal_partial} STYPE text FINALFUNC {finish_fun} INITCOND '{{'"
|
||||
with new_aggregate(cql, test_keyspace, map_literal_body) as map_literal:
|
||||
map_res = [row for row in cql.execute(f"SELECT {test_keyspace}.{map_literal}(k, val) AS result FROM {table}")]
|
||||
assert len(map_res) == 1 and map_res[0].result == '{a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,}'
|
||||
|
||||
# Test that the state function and final function must exist and have correct signatures
|
||||
def test_wrong_sfunc_or_ffunc(scylla_only, cql, test_keyspace):
|
||||
avg_partial_body = "(state tuple<bigint, text>, val bigint) CALLED ON NULL INPUT RETURNS tuple<bigint, text> LANGUAGE lua AS 'return {state[1] + val, \"hello\"}'"
|
||||
|
||||
Reference in New Issue
Block a user