| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- %%--------------------------------------------------------------------
- %% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%--------------------------------------------------------------------
- -module(emqx_rule_sqlparser).
- -include("rule_engine.hrl").
- -export([parse/1]).
- -export([
- select_fields/1,
- select_is_foreach/1,
- select_doeach/1,
- select_incase/1,
- select_from/1,
- select_where/1
- ]).
- -import(proplists, [
- get_value/2,
- get_value/3
- ]).
- -record(select, {fields, from, where, is_foreach, doeach, incase}).
- -opaque select() :: #select{}.
- -type const() :: {const, number() | binary()}.
- -type variable() :: binary() | list(binary()).
- -type alias() :: binary() | list(binary()).
- %% TODO: So far the SQL function module names and function names are as binary(),
- %% binary_to_atom is called to convert to module and function name.
- %% For better performance, the function references
- %% can be converted to a fun Module:Function/N When compiling the SQL.
- -type ext_module_name() :: atom() | binary().
- -type func_name() :: atom() | binary().
- -type func_args() :: [field()].
- %% Functions defiend in emqx_rule_funcs
- -type builtin_func_ref() :: {var, func_name()}.
- %% Functions defined in other modules, reference syntax: Module.Function(Arg1, Arg2, ...)
- %% NOTE: it's '.' (Elixir style), but not ':' (Erlang style).
- %% Parsed as a two element path-list: [{key, Module}, {key, Func}].
- -type external_func_ref() :: {path, [{key, ext_module_name() | func_name()}]}.
- -type func_ref() :: builtin_func_ref() | external_func_ref().
- -type sql_func() :: {'fun', func_ref(), func_args()}.
- -type field() :: const() | variable() | {as, field(), alias()} | sql_func().
- -export_type([select/0]).
- %% Parse one select statement.
- -spec parse(string() | binary()) -> {ok, select()} | {error, term()}.
- parse(Sql) ->
- try
- case rulesql:parsetree(Sql) of
- {ok, {select, Clauses}} ->
- {ok, #select{
- is_foreach = false,
- fields = get_value(fields, Clauses),
- doeach = [],
- incase = {},
- from = get_value(from, Clauses),
- where = get_value(where, Clauses)
- }};
- {ok, {foreach, Clauses}} ->
- {ok, #select{
- is_foreach = true,
- fields = get_value(fields, Clauses),
- doeach = get_value(do, Clauses, []),
- incase = get_value(incase, Clauses, {}),
- from = get_value(from, Clauses),
- where = get_value(where, Clauses)
- }};
- Error ->
- {error, Error}
- end
- catch
- _Error:Reason:StackTrace ->
- {error, {Reason, StackTrace}}
- end.
- -spec select_fields(select()) -> list(field()).
- select_fields(#select{fields = Fields}) ->
- Fields.
- -spec select_is_foreach(select()) -> boolean().
- select_is_foreach(#select{is_foreach = IsForeach}) ->
- IsForeach.
- -spec select_doeach(select()) -> list(field()).
- select_doeach(#select{doeach = DoEach}) ->
- DoEach.
- -spec select_incase(select()) -> list(field()).
- select_incase(#select{incase = InCase}) ->
- InCase.
- -spec select_from(select()) -> list(binary()).
- select_from(#select{from = From}) ->
- From.
- -spec select_where(select()) -> tuple().
- select_where(#select{where = Where}) ->
- Where.
|