Просмотр исходного кода

fix(rule_engine): capture function_clause errors

Fixes https://emqx.atlassian.net/browse/EMQX-10798
Thales Macedo Garitezi 2 лет назад
Родитель
Сommit
66dec69d09

+ 14 - 5
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) ->

+ 60 - 0
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
 %%------------------------------------------------------------------------------

+ 1 - 0
changes/ce/fix-11480.en.md

@@ -0,0 +1 @@
+Return more user-friendly messages when rule functions are fed bad arguments.