diff --git a/apps/emqx_rule_engine/src/emqx_rule_runtime.erl b/apps/emqx_rule_engine/src/emqx_rule_runtime.erl index f047e2047..74396dbc8 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_runtime.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_runtime.erl @@ -493,11 +493,20 @@ apply_func(Other, _, _) -> }). do_apply_func(Module, Name, Args, Columns) -> - case erlang:apply(Module, Name, Args) of - Func when is_function(Func) -> - erlang:apply(Func, [Columns]); - Result -> - Result + try + case erlang:apply(Module, Name, Args) of + Func when is_function(Func) -> + erlang:apply(Func, [Columns]); + Result -> + Result + end + catch + error:function_clause -> + ?RAISE_BAD_SQL(#{ + reason => bad_sql_function_argument, + arguments => Args, + function_name => Name + }) end. add_metadata(Columns, Metadata) when is_map(Columns), is_map(Metadata) -> diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl index 8c3bd0ebb..ae4bf43f6 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl @@ -293,6 +293,66 @@ t_kv_store(_) -> emqx_rule_funcs:kv_store_del(<<"abc">>), undefined = emqx_rule_funcs:kv_store_get(<<"abc">>). +t_function_clause_errors(_Config) -> + SQL0 = <<"select upper(xxxx) from \"t/a\"">>, + Payload = <<"{}">>, + ?assertMatch( + {error, + {select_and_transform_error, + {throw, + #{ + arguments := [undefined], + reason := bad_sql_function_argument, + function_name := upper + }, + _Stack}}}, + emqx_rule_sqltester:test( + #{ + sql => SQL0, + context => #{payload => Payload, topic => <<"t/a">>} + } + ) + ), + SQL1 = <<"foreach xs as x do upper(xxxx) from \"t/a\"">>, + ?assertMatch( + {error, { + {doeach_error, + {throw, + #{ + arguments := [undefined], + reason := bad_sql_function_argument, + function_name := upper + }, + _Stack0}}, + _Stack1 + }}, + emqx_rule_sqltester:test( + #{ + sql => SQL1, + context => #{payload => Payload, xs => [1, 2, 3], topic => <<"t/a">>} + } + ) + ), + SQL2 = <<"foreach upper(xxxx) as x from \"t/a\"">>, + ?assertMatch( + {error, + {select_and_collect_error, + {throw, + #{ + arguments := [undefined], + reason := bad_sql_function_argument, + function_name := upper + }, + _Stack}}}, + emqx_rule_sqltester:test( + #{ + sql => SQL2, + context => #{payload => Payload, topic => <<"t/a">>} + } + ) + ), + ok. + %%------------------------------------------------------------------------------ %% Test cases for rule registry %%------------------------------------------------------------------------------ diff --git a/changes/ce/fix-11480.en.md b/changes/ce/fix-11480.en.md new file mode 100644 index 000000000..f3440f59e --- /dev/null +++ b/changes/ce/fix-11480.en.md @@ -0,0 +1 @@ +Return more user-friendly messages when rule functions are fed bad arguments.