-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UDF do not allow passing constant values as params but only columns of a row #12607
Comments
functionArgs returns [std::vector<expression> a]
: '(' ')'
| '(' t1=term { a.push_back(std::move(t1)); }
( ',' tn=term { a.push_back(std::move(tn)); } )*
')'
;
term returns [expression term1]
: v=value { $term1 = std::move(v); }
| f=functionName args=functionArgs { $term1 = function_call{std::move(f), std::move(args)}; }
| '(' c=comparatorType ')' t=term { $term1 = cast{std::move(t), c}; }
; It seems that adding std::optional<expression>
prepare_function_call(const expr::function_call& fc, data_dictionary::database db, const sstring& keyspace, const schema* schema_opt, lw_shared_ptr<column_specification> receiver) {
if (!receiver) {
// TODO: It is possible to infer the type of a function call if there is only one overload, or if all overloads return the same type
return std::nullopt;
}
auto&& fun = std::visit(overloaded_functor{
[] (const shared_ptr<functions::function>& func) {
return func;
},
[&] (const functions::function_name& name) {
auto args = boost::copy_range<std::vector<::shared_ptr<assignment_testable>>>(fc.args | boost::adaptors::transformed(expr::as_assignment_testable));
auto fun = functions::functions::get(db, keyspace, name, args, receiver->ks_name, receiver->cf_name, receiver.get());
if (!fun) {
throw exceptions::invalid_request_exception(format("Unknown function {} called", name));
}
return fun;
},
}, fc.func); However, test_assignment() doesn't work for untyped_constant. |
BTW the UDF above is just simplified example , in my real UDF usage i pass timestamp strings like |
@cvybhu it's in your queue? |
Not really, it's somewhere in the backlog. Although I guess I could move it up in time if needed. |
I took a short look to see if this could be fixed quickly, and I think there are two major issues here. Here's how the grammar for calling a function inside SELECT looks like: unaliasedSelector returns [expression s]
@init { expression tmp; }
: ( c=cident { tmp = unresolved_identifier{std::move(c)}; }
| i=intValue { tmp = i; }
| K_COUNT '(' countArgument ')' { tmp = make_count_rows_function_expression(); }
| K_WRITETIME '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::writetime,
unresolved_identifier{std::move(c)}}; }
| K_TTL '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::ttl,
unresolved_identifier{std::move(c)}}; }
| f=functionName args=selectionFunctionArgs { tmp = function_call{std::move(f), std::move(args)}; }
| K_CAST '(' arg=unaliasedSelector K_AS t=native_type ')' { tmp = cast{std::move(arg), std::move(t)}; }
)
( '.' fi=cident { tmp = field_selection{std::move(tmp), std::move(fi)}; } )*
{ $s = tmp; }
;
selectionFunctionArgs returns [std::vector<expression> a]
: '(' ')'
| '(' s1=unaliasedSelector { a.push_back(std::move(s1)); }
( ',' sn=unaliasedSelector { a.push_back(std::move(sn)); } )*
')'
;
|
It's better to move to expressions and then fix it. I started the work, but don't have time to make meaningful progress. |
wrt. quoted strings, CQL uses single quotes for string literals and double quotes for case-sensitive identifiers. If CQL uses double quotes for literals, we should deprecate it (unfortunately with a flag). |
Ah right, maybe that's not the issue. I tried to add |
In that case it's probably a conflict between
|
Yes, ANTLR3 and its "LL(*)" is very sad, especially since good LR parsers have been around since the 1970s (e.g., Yacc. See https://en.wikipedia.org/wiki/LALR_parser). You can see an example in alternator/expressions.g, where I had to "work around" the need to support a common prefix and also operator precedence - something which is trivial to do in Yacc - in ANTLR3 by splitting one rule into a series of rules. But it least it is (or should be) doable.
Yes, that seems to be exactly what LL(*) doesn't support and you need to work around.
I think Cql.g already distinguishes between STRING_LITERAL (single quote) and QUOTED_NAME (double quote) and in most contexts, only one is allowed. |
antlr4 is supposed to be better here (not sure exactly how)
It's easy to work around.
|
In issue #14310 I re-discovered this issue. I noted that it's a general SELECT parser bug and not only about constant values passed to UDFs as the title of this issue suggests: Native functions are also affected and can't get constant parameters, and even more basically, selecting just a constant (I know it's silly, but it should be allowed) is a syntax error. Cassandra 4 allows these things, and Scylla doesn't. I mentioned that I tried the patch: +++ b/cql3/Cql.g
@@ -419,9 +419,16 @@ selector returns [shared_ptr<raw_selector> s]
: us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = ::make_shared<
raw_selector>(us, alias); }
;
+selectionLiteral returns [expression value]
+ : c=constant { $value = std::move(c); }
+ | K_NULL { $value = make_untyped_null(); }
+ | e=marker { $value = std::move(e); }
+ ;
+
unaliasedSelector returns [expression s]
@init { expression tmp; }
: ( c=cident { tmp = unresolved_identifier{std::move(c)}; }
+ | z=selectionLiteral { tmp = std::move(z); }
| K_COUNT '(' countArgument ')' { tmp = make_count_rows_function_expression(); }
| K_WRITETIME '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::writetime,
unresolved_identifier{std::move(c)}}; } (I used the name "selectionLiteral" that Cassandra's parser uses) This patch almost works - it does print an ANTLR warning which I don't understand and will have to be fixed, but the build does finish. The problem is that when actually used with a constant selector, e.g.,
So I guess this needs support also in the evaluate() code. A test case (passes on Cassandra, fails on Scylla): import pytest
from util import new_test_table, unique_key_int
@pytest.fixture(scope="module")
def table1(cql, test_keyspace):
with new_test_table(cql, test_keyspace, "p int, b blob, PRIMARY KEY (p)") as table:
yield table
def test_constant_function_parameter(cql, table1):
p = unique_key_int()
cql.execute(f"INSERT INTO {table1} (p, b) VALUES ({p}, 0x03)")
# This passes on Scylla today (constant function arguments in restriction)
assert [(p,)] == list(cql.execute(f"SELECT p FROM {table1} WHERE p={p} AND b=tinyintAsBlob(3) ALLOW FILTERING"))
# But this doesn't (constant function arguments in selector)
assert [(b'\x04',)] == list(cql.execute(f"SELECT tinyintAsBlob(4) FROM {table1} WHERE p={p}")) |
Code in functions.cc creates the different TYPEasblob() and blobasTYPE() functions for all type names TYPE. The functions for the "counter" type were skipped, supposedly because "counters are not supported yet". But counters are supported, so let's add the missing functions. The code fix is trivial, the tests that verify that the result behaves like Cassandra took more work. After this patch, unimplemented::cause::COUNTERS is no longer used anywhere in the code. I wanted to remove it, but noticed that unimplemented::cause is a graveyard of unused causes, so decided not to remove this one either. We should clean it up in a separate patch. Fixes scylladb#14742 Also includes tests for tangently-related issues: Refs scylladb#12607 Refs scylladb#14319 Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Code in functions.cc creates the different TYPEasblob() and blobasTYPE() functions for all type names TYPE. The functions for the "counter" type were skipped, supposedly because "counters are not supported yet". But counters are supported, so let's add the missing functions. The code fix is trivial, the tests that verify that the result behaves like Cassandra took more work. After this patch, unimplemented::cause::COUNTERS is no longer used anywhere in the code. I wanted to remove it, but noticed that unimplemented::cause is a graveyard of unused causes, so decided not to remove this one either. We should clean it up in a separate patch. Fixes scylladb#14742 Also includes tests for tangently-related issues: Refs scylladb#12607 Refs scylladb#14319 Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Installation details
Docker scylladb/scylla latest version
It does not seem to be possible to pass constant values to UDF for example given
give error like
line 1:18 no viable alternative at input '('
instead it only works with column params
i wonder how can i pass constant params into UDFs where these constants change between different invocations of the same query
The text was updated successfully, but these errors were encountered: