emqx_rule_sqlparser.erl 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_rule_sqlparser).
  17. -include("rule_engine.hrl").
  18. -export([parse/1]).
  19. -export([
  20. select_fields/1,
  21. select_is_foreach/1,
  22. select_doeach/1,
  23. select_incase/1,
  24. select_from/1,
  25. select_where/1
  26. ]).
  27. -import(proplists, [
  28. get_value/2,
  29. get_value/3
  30. ]).
  31. -record(select, {fields, from, where, is_foreach, doeach, incase}).
  32. -opaque select() :: #select{}.
  33. -type const() :: {const, number() | binary()}.
  34. -type variable() :: binary() | list(binary()).
  35. -type alias() :: binary() | list(binary()).
  36. %% TODO: So far the SQL function module names and function names are as binary(),
  37. %% binary_to_atom is called to convert to module and function name.
  38. %% For better performance, the function references
  39. %% can be converted to a fun Module:Function/N When compiling the SQL.
  40. -type ext_module_name() :: atom() | binary().
  41. -type func_name() :: atom() | binary().
  42. -type func_args() :: [field()].
  43. %% Functions defiend in emqx_rule_funcs
  44. -type builtin_func_ref() :: {var, func_name()}.
  45. %% Functions defined in other modules, reference syntax: Module.Function(Arg1, Arg2, ...)
  46. %% NOTE: it's '.' (Elixir style), but not ':' (Erlang style).
  47. %% Parsed as a two element path-list: [{key, Module}, {key, Func}].
  48. -type external_func_ref() :: {path, [{key, ext_module_name() | func_name()}]}.
  49. -type func_ref() :: builtin_func_ref() | external_func_ref().
  50. -type sql_func() :: {'fun', func_ref(), func_args()}.
  51. -type field() :: const() | variable() | {as, field(), alias()} | sql_func().
  52. -export_type([select/0]).
  53. %% Parse one select statement.
  54. -spec parse(string() | binary()) -> {ok, select()} | {error, term()}.
  55. parse(Sql) ->
  56. try
  57. case rulesql:parsetree(Sql) of
  58. {ok, {select, Clauses}} ->
  59. {ok, #select{
  60. is_foreach = false,
  61. fields = get_value(fields, Clauses),
  62. doeach = [],
  63. incase = {},
  64. from = get_value(from, Clauses),
  65. where = get_value(where, Clauses)
  66. }};
  67. {ok, {foreach, Clauses}} ->
  68. {ok, #select{
  69. is_foreach = true,
  70. fields = get_value(fields, Clauses),
  71. doeach = get_value(do, Clauses, []),
  72. incase = get_value(incase, Clauses, {}),
  73. from = get_value(from, Clauses),
  74. where = get_value(where, Clauses)
  75. }};
  76. Error ->
  77. {error, Error}
  78. end
  79. catch
  80. _Error:Reason:StackTrace ->
  81. {error, {Reason, StackTrace}}
  82. end.
  83. -spec select_fields(select()) -> list(field()).
  84. select_fields(#select{fields = Fields}) ->
  85. Fields.
  86. -spec select_is_foreach(select()) -> boolean().
  87. select_is_foreach(#select{is_foreach = IsForeach}) ->
  88. IsForeach.
  89. -spec select_doeach(select()) -> list(field()).
  90. select_doeach(#select{doeach = DoEach}) ->
  91. DoEach.
  92. -spec select_incase(select()) -> list(field()).
  93. select_incase(#select{incase = InCase}) ->
  94. InCase.
  95. -spec select_from(select()) -> list(binary()).
  96. select_from(#select{from = From}) ->
  97. From.
  98. -spec select_where(select()) -> tuple().
  99. select_where(#select{where = Where}) ->
  100. Where.