From 905b120101f6ca8e746a1d9b468fa2eb8fe8dd78 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Tue, 1 Apr 2025 17:55:15 -0400 Subject: [PATCH] Add generated lexer and parser --- .iex.exs | 1 + lib/adapters/ansi.ex | 105 ++ lib/adapters/mysql.ex | 14 + lib/adapters/postgres.ex | 17 + lib/adapters/tds.ex | 15 + lib/bnf.ex | 103 ++ lib/compiler.ex | 50 - lib/lexer.ex | 2069 +++++++++++++++++++++++++++++++ lib/mix/tasks/sql.gen.parser.ex | 579 +++++++++ lib/parser.ex | 523 ++++---- lib/sql.ex | 51 +- lib/string.ex | 106 +- lib/token.ex | 21 + test/adapters/ansi_test.exs | 302 +++++ test/adapters/mysql_test.exs | 302 +++++ test/adapters/postgres_test.exs | 302 +++++ test/adapters/tds_test.exs | 302 +++++ test/bnf_test.exs | 13 + test/compiler_test.exs | 14 - test/formatter_test.exs | 2 +- test/parser_test.exs | 68 - test/sql_test.exs | 183 +-- test/string_test.exs | 22 +- 23 files changed, 4578 insertions(+), 586 deletions(-) create mode 100644 lib/adapters/ansi.ex create mode 100644 lib/adapters/mysql.ex create mode 100644 lib/adapters/postgres.ex create mode 100644 lib/adapters/tds.ex create mode 100644 lib/bnf.ex delete mode 100644 lib/compiler.ex create mode 100644 lib/lexer.ex create mode 100644 lib/mix/tasks/sql.gen.parser.ex create mode 100644 lib/token.ex create mode 100644 test/adapters/ansi_test.exs create mode 100644 test/adapters/mysql_test.exs create mode 100644 test/adapters/postgres_test.exs create mode 100644 test/adapters/tds_test.exs create mode 100644 test/bnf_test.exs delete mode 100644 test/compiler_test.exs delete mode 100644 test/parser_test.exs diff --git a/.iex.exs b/.iex.exs index 56b11a2..d0c291e 100644 --- a/.iex.exs +++ b/.iex.exs @@ -8,3 +8,4 @@ Application.put_env(:sql, :ecto_repos, [SQL.Repo]) Application.put_env(:sql, SQL.Repo, username: "postgres", password: "postgres", hostname: "localhost", database: "sql_test#{System.get_env("MIX_TEST_PARTITION")}", pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10) Mix.Tasks.Ecto.Create.run(["-r", "SQL.Repo"]) SQL.Repo.start_link() +import SQL diff --git a/lib/adapters/ansi.ex b/lib/adapters/ansi.ex new file mode 100644 index 0000000..854c272 --- /dev/null +++ b/lib/adapters/ansi.ex @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.ANSI do + @moduledoc """ + A SQL adapter for [ANSI](https://blog.ansi.org/sql-standard-iso-iec-9075-2023-ansi-x3-135/). + """ + @moduledoc since: "0.2.0" + + use SQL.Token + + def token_to_string(value, mod \\ __MODULE__) + def token_to_string(value, mod) when is_struct(value) do + to_string(%{value | module: mod}) + end + + def token_to_string({tag, _, [{:parens, _, _} = value]}, mod) when tag in ~w[integer float update]a do + "#{mod.token_to_string(tag)}#{mod.token_to_string(value)}" + end + def token_to_string({tag, _, value}, _mod) when tag in ~w[ident integer float]a do + "#{value}" + end + def token_to_string({tag, _}, mod) do + mod.token_to_string(tag) + end + def token_to_string({:comment, _, value}, _mod) do + "-- #{value}" + end + def token_to_string({:comments, _, value}, _mod) do + "\\* #{value} *\\" + end + def token_to_string({:double_quote, _, value}, _mod) do + "\"#{value}\"" + end + def token_to_string({:quote, _, value}, _mod) do + "'#{value}'" + end + def token_to_string({:parens, _, value}, mod) do + "(#{mod.token_to_string(value)})" + end + def token_to_string({:colon, _, value}, mod) do + "; #{mod.token_to_string(value)}" + end + def token_to_string({:comma, _, value}, mod) do + ", #{mod.token_to_string(value)}" + end + def token_to_string({tag, _, []}, mod) do + mod.token_to_string(tag) + end + def token_to_string({tag, _, [[_ | _] = left, right]}, mod) when tag in ~w[join]a do + "#{mod.token_to_string(left)} #{mod.token_to_string(tag)} #{mod.token_to_string(right)}" + end + def token_to_string({tag, _, [{:with = t, _, [left, right]}]}, mod) when tag in ~w[to]a do + "#{mod.token_to_string(tag)} #{mod.token_to_string(left)} #{mod.token_to_string(t)} #{mod.token_to_string(right)}" + end + def token_to_string({tag, _, value}, mod) when tag in ~w[select from fetch limit where order offset group having with join by distinct create type drop insert alter table add into delete update start grant revoke set declare open close commit rollback references recursive]a do + "#{mod.token_to_string(tag)} #{mod.token_to_string(value)}" + end + def token_to_string({:on = tag, _, [source, as, value]}, mod) do + "#{mod.token_to_string(source)} #{mod.token_to_string(as)} #{mod.token_to_string(tag)} #{mod.token_to_string(value)}" + end + def token_to_string({tag, _, [left, [{:all = t, _, right}]]}, mod) when tag in ~w[union except intersect]a do + "#{mod.token_to_string(left)} #{mod.token_to_string(tag)} #{mod.token_to_string(t)} #{mod.token_to_string(right)}" + end + def token_to_string({:between = tag, _, [{:not = t, _, right}, left]}, mod) do + "#{mod.token_to_string(right)} #{mod.token_to_string(t)} #{mod.token_to_string(tag)} #{mod.token_to_string(left)}" + end + def token_to_string({tag, _, [left, right]}, mod) when tag in ~w[:: [\] <> <= >= != || + - ^ * / % < > = like ilike as union except intersect between and or on is not in cursor for to]a do + "#{mod.token_to_string(left)} #{mod.token_to_string(tag)} #{mod.token_to_string(right)}" + end + def token_to_string({tag, _, [{:parens, _, _} = value]}, mod) when tag not in ~w[in on]a do + "#{mod.token_to_string(tag)}#{mod.token_to_string(value)}" + end + def token_to_string({tag, _, values}, mod) when tag in ~w[not all between symmetric absolute relative forward backward on in for without]a do + "#{mod.token_to_string(tag)} #{mod.token_to_string(values)}" + end + def token_to_string({tag, _, [left, right]}, mod) when tag in ~w[.]a do + "#{mod.token_to_string(left)}.#{mod.token_to_string(right)}" + end + def token_to_string({tag, _, [left]}, mod) when tag in ~w[not]a do + "#{mod.token_to_string(left)} #{mod.token_to_string(tag)}" + end + def token_to_string({tag, _, [left]}, mod) when tag in ~w[asc desc isnull notnull]a do + "#{mod.token_to_string(left)} #{mod.token_to_string(tag)}" + end + def token_to_string({:binding, _, [idx]}, _mod) when is_integer(idx) do + "?" + end + def token_to_string({:binding, _, value}, _mod) do + "{{#{value}}}" + end + def token_to_string(:asterisk, _mod) do + "*" + end + def token_to_string(value, _mod) when is_atom(value) do + "#{value}" + end + def token_to_string(values, mod) when is_list(values) do + Enum.reduce(values, "", fn + token, "" -> mod.token_to_string(token) + {:comma, _, _} = token, acc -> acc <> mod.token_to_string(token) + token, acc -> acc <> " " <> mod.token_to_string(token) + end) + end +end diff --git a/lib/adapters/mysql.ex b/lib/adapters/mysql.ex new file mode 100644 index 0000000..150fc7d --- /dev/null +++ b/lib/adapters/mysql.ex @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.MySQL do + @moduledoc """ + A SQL adapter for [MySQL](https://www.mysql.com). + """ + @moduledoc since: "0.2.0" + + use SQL.Token + + def token_to_string(value, mod \\ __MODULE__) + def token_to_string(token, mod), do: SQL.Adapters.ANSI.token_to_string(token, mod) +end diff --git a/lib/adapters/postgres.ex b/lib/adapters/postgres.ex new file mode 100644 index 0000000..c91bfcb --- /dev/null +++ b/lib/adapters/postgres.ex @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.Postgres do + @moduledoc """ + A SQL adapter for [PostgreSQL](https://www.postgresql.org). + """ + @moduledoc since: "0.2.0" + + use SQL.Token + + def token_to_string(value, mod \\ __MODULE__) + def token_to_string({:not, _, [left, {:in, _, [{:binding, _, _} = right]}]}, mod), do: "#{mod.token_to_string(left)} != ANY(#{mod.token_to_string(right)})" + def token_to_string({:in, _, [left, {:binding, _, _} = right]}, mod), do: "#{mod.token_to_string(left)} = ANY(#{mod.token_to_string(right)})" + def token_to_string({:binding, _, [idx]}, _mod) when is_integer(idx), do: "$#{idx}" + def token_to_string(token, mod), do: SQL.Adapters.ANSI.token_to_string(token, mod) +end diff --git a/lib/adapters/tds.ex b/lib/adapters/tds.ex new file mode 100644 index 0000000..cb4fd2e --- /dev/null +++ b/lib/adapters/tds.ex @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.TDS do + @moduledoc """ + A SQL adapter for [TDS](https://www.microsoft.com/en-ca/sql-server). + """ + @moduledoc since: "0.2.0" + + use SQL.Token + + def token_to_string(value, mod \\ __MODULE__) + def token_to_string({:binding, _, [idx]}, _mod) when is_integer(idx), do: "@#{idx}" + def token_to_string(token, mod), do: SQL.Adapters.ANSI.token_to_string(token, mod) +end diff --git a/lib/bnf.ex b/lib/bnf.ex new file mode 100644 index 0000000..549ae09 --- /dev/null +++ b/lib/bnf.ex @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor +# https://standards.iso.org/iso-iec/9075/-2/ed-6/en/ +# https://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_9075-1_2023_ed_6_-_id_76583_Publication_PDF_(en).zip +# 0. \w(?![^<]*>) +# 1. <[^>]*>\.{3} repeat non-terminal rule +# 2. ({.+}...) repeat group +# 3. <[^>]*> - non-terminal +# 4. \[[^\]]*] - optional +# 5. \|(?![^\[]*\]) - or + +defmodule SQL.BNF do + @moduledoc false + + def parse() do + File.cwd!() + |> Path.join("standard/ISO_IEC_9075-2(E)_Foundation.bnf.txt") + |> File.read!() + |> parse() + end + + def parse(binary) do + Map.new(parse(binary, :symbol, [], [], [], [], [])) + end + + defp parse(<<>>, _type, data, acc, symbol, expr, rules) do + merge(rules, symbol, expr ++ merge(acc, data)) + end + defp parse(<>, :symbol = type, symbol, _acc, _data, _expr, rules) do + parse(rest, type, [], [], symbol, [], rules) + end + defp parse(<>, _type, data, acc, symbol, expr, rules) do + parse(<>, :symbol, [], [], [], [], merge(rules, symbol, expr ++ merge(acc, data))) + end + defp parse(<>, _type, data, acc, symbol, expr, rules) do + parse(rest, :expr, [], [], String.trim("#{data}"), [], merge(rules, symbol, expr ++ acc)) + end + defp parse(<>, type, [?!, ?! | _] = data, acc, symbol, expr, rules) do + parse(rest, type, [], merge(acc, "#{data ++ [?.]}"), symbol, expr, rules) + end + defp parse(<>, type, data, acc, symbol, expr, rules) do + parse(rest, type, data ++ [?., ?., ?.], acc, symbol, expr, rules) + end + defp parse(<>, type, data, acc, symbol, expr, rules) do + parse(rest, type, data ++ [?|], acc, symbol, expr, rules) + end + defp parse(<>, type, [] = data, acc, symbol, expr, rules) when b in [?\s, ?\t, ?\r, ?\n, ?\f] do + parse(rest, type, data, acc, symbol, expr, rules) + end + defp parse(<>, type, data, acc, symbol, expr, rules) when b in [?\n] do + parse(rest, type, data, acc, symbol, expr, rules) + end + defp parse(<>, type, data, acc, symbol, expr, rules) do + parse(rest, type, data ++ [b], acc, symbol, expr, rules) + end + + defp merge([], []), do: [] + defp merge(rules, []), do: rules + defp merge(rules, data), do: rules ++ [data] + defp merge(rules, [], []), do: rules + defp merge(rules, rule, expr) when is_list(rule), do: merge(rules, "#{rule}", expr) + defp merge(rules, rule, expr) when is_list(expr), do: merge(rules, rule, "#{expr}") + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, ["\u0020"]}] # 32 \u0020 + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] # "Lu", "Ll", "Lt", "Lm", "Lo", or "Nl" Unicode.Set.match?(<>, "[[:Lu:], [:Ll:], [:Lt:], [:Lm:], [:Lo:], [:Nl:]]") + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] # 183 \u00B7 or "Mn", "Mc", "Nd", "Pc", or "Cf" Unicode.Set.match?(<>, "[[:Mn:], [:Mc:], [:Nd:], [:Pc:], [:Cf:]]") + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, ["\\u"]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, ["\u0009", "\u000D", "\u00A0", "\u00A0", "\u1680", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200A", "\u202F", "\u205F", "\u3000", "\u180E", "\u200B", "\u200C", "\u200D", "\u2060", "\uFEFF"]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, _expr), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, ["\u000A", "\u000B", "\u000C", "\u000D", "\u0085", "\u2028", "\u2029"]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, _expr), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, _expr), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(rules, "" = symbol, "!! See the Syntax Rules."), do: rules ++ [{symbol, [:ignore]}] + defp merge(_rules, symbol, "!! See the Syntax Rules."), do: raise "Please apply rules for #{symbol} by referencing the PDF or https://github.com/ronsavage/SQL/blob/master/Syntax.rules.txt" + defp merge(rules, symbol, expr), do: rules ++ [{symbol, expr}] +end diff --git a/lib/compiler.ex b/lib/compiler.ex deleted file mode 100644 index 3e4c214..0000000 --- a/lib/compiler.ex +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2025 DBVisor - -defmodule SQL.Compiler do - @moduledoc false - - @doc false - def generate(keyword, opts \\ [next: [?\s, ?\t, ?\r, ?\n, ?\f, 194, 160], eos: false]) do - keyword = String.downcase(keyword) - {to_match(keyword, opts), to_guard(keyword, opts), to_rest(opts), byte_size(keyword), :"#{keyword}"} - end - - defp to_rest(opts) do - if opts[:next] do - to_node(:<<>>, [to_var(:next)]) - else - to_var(:rest) - end - end - - defp to_match(keyword, opts) do - if is_list(opts[:next]) do - to_node(:<<>>, to_vars(keyword) ++ [to_var(:next)]) - else - to_node(:<<>>, to_vars(keyword)) - end - end - - defp to_guard(keyword, opts) do - {value, _n} = to_guard(keyword) - cond do - opts[:eos] == true -> to_node(:and, value, to_node(:==, to_var(:rest), "")) - opts[:next] -> to_node(:and, value, to_node(:in, to_var(:next), opts[:next])) - true -> value - end - end - - defp to_guard(keyword) do - for <>, reduce: {[], 1} do - {[], n} -> {to_in(<>, n), n+1} - {left, n} -> {to_node(:and, left, to_in(<>, n)), n+1} - end - end - - defp to_vars(keyword), do: (for n <- 1..byte_size(keyword), do: to_var(:"b#{n}")) - defp to_var(tag), do: {tag, [], Elixir} - defp to_in(k, n), do: to_node(:in, to_var(:"b#{n}"), ~c"#{k}#{String.upcase(k)}") - defp to_node(:<<>> = tag, left), do: {tag, [], left ++ [{:"::", [], [to_var(:rest), to_var(:binary)]}]} - defp to_node(tag, left, right), do: {tag, [context: Elixir, imports: [{2, Kernel}]], [left, right]} -end diff --git a/lib/lexer.ex b/lib/lexer.ex new file mode 100644 index 0000000..9b37800 --- /dev/null +++ b/lib/lexer.ex @@ -0,0 +1,2069 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Lexer do + @moduledoc false + + defguard is_data_type(node) when elem(node, 0) in ~w[integer float ident quote double_quote backtick bracket parens .]a + defguard is_newline(b) when b in [10, 11, 12, 13, 133, 8232, 8233] + defguard is_space(b) when b in ~c" " + defguard is_whitespace(b) when b in [9, 13, 160, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 6158, 8203, 8204, 8205, 8288, 65279] + + def opening_delimiter(:parens), do: :"(" + def opening_delimiter(:bracket), do: :"[" + def opening_delimiter(:double_quote), do: :"\"" + def opening_delimiter(:quote), do: :"'" + def opening_delimiter(:backtick), do: :"`" + def opening_delimiter(type) when type in ~w[var code braces]a, do: :"{" + + def expected_delimiter(:parens), do: :")" + def expected_delimiter(:bracket), do: :"]" + def expected_delimiter(:double_quote), do: :"\"" + def expected_delimiter(:quote), do: :"'" + def expected_delimiter(:backtick), do: :"`" + def expected_delimiter(type) when type in ~w[var code braces]a, do: :"}" + + def lex(binary, binding, _meta, params \\ [], opts \\ [metadata: true]) do + case lex(binary, binary, [binding: binding, params: params] ++ opts, 0, 0, nil, [], [], 0) do + {"", _binary, opts, line, column, nil = type, [] = data, acc, _n} -> + {:ok, opts, line, column, type, data, acc} + + {"", binary, _opts, end_line, end_column, type, _data, [{_, [line: line, column: column, file: file], _}|_], _n} when type in ~w[parens bracket double_quote quote backtick var code]a -> + raise TokenMissingError, file: "#{file}", snippet: binary, end_line: end_line, end_column: end_column, line: line, column: column, opening_delimiter: opening_delimiter(type), expected_delimiter: expected_delimiter(type) + + {"", _binary, opts, line, column, type, data, acc, _n} -> + {:ok, opts, line, column, type, data, insert_node(node(ident(type, data), line, column, data, opts), acc)} + end + end + def lex("" = rest, binary, opts, line, column, type, data, acc, n) do + {rest, binary, opts, line, column, type, data, acc, n} + end + def lex(<>, binary, opts, line, column, type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :comment, [], insert_node(type, line, column, data, opts, acc), n) + end + def lex(<>, binary, opts, line, column, _type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :comments, data, acc, n) + end + def lex(<>, binary, opts, line, column, :comments, data, acc, n) do + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:comments, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :comments, data, acc, n) do + lex(rest, binary, opts, line, column+1, :comments, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, _type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :var, data, acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, 0 = n) when type in ~w[code var]a do + if opts[:binding] do + opts = if type == :var do + update_in(opts, [:params], &(&1 ++ [opts[:binding][List.to_atom(data)]])) + else + update_in(opts, [:params], &(&1 ++ [elem(Code.eval_string(to_string(data), opts[:binding]), 0)])) + end + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:binding, line, column, length(opts[:params]), opts), acc), n) + else + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:binding, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, :code = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, type, data ++ [?}], acc, n-1) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[var code]a and b in [?{] do + lex(rest, binary, opts, line, column+1, :code, data ++ [b], acc, n+1) + end + def lex(<>, binary, opts, line, column, :var = type, data, acc, n) when b in ?0..?9 and data != [] do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, :var = type, data, acc, n) when b in ?a..?z or b in ?A..?Z or (b == ?_ and data != []) do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[var code]a do + lex(rest, binary, opts, line, column+1, :code, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?(, ?[] do + acc = case ident(type, data) do + nil -> acc + :ident -> insert_node(node(type, line, column, data, opts), acc) + tag -> insert_node(node(tag, line, column, [], opts), acc) + end + case lex(rest, binary, opts, line, column+1, nil, [], [], n) do + {rest, opts, line, column, value} -> + lex(rest, binary, opts, line, column, nil, [], insert_node(node(ident(type, [b]), line, column, value, opts), acc), n) + {rest, binary, o, l, c, t, d, a, _n} -> + value = if t, do: insert_node(node(t, l, c, d, o), a), else: a + lex(rest, binary, opts, l, c, (if b == ?(, do: :parens, else: :bracket), [], insert_node(node(ident(type, [b]), line, column, value, opts), acc), n) + end + end + def lex(<>, _binary, opts, line, column, type, data, acc, _n) when b in [?), ?]] do + acc = if type, do: insert_node(node(type, line, column, data, opts), acc), else: acc + {rest, opts, line, column+1, acc} + end + def lex(<>, binary, opts, line, column, :double_quote = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :backtick = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :quote = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[double_quote quote backtick]a do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_newline(b) do + if data == [] do + lex(rest, binary, opts, line+1, column, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line+1, column, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_space(b) do + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_whitespace(b) do + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?,, ?;] do + acc = if type, do: insert_node(node(ident(type, data), line, column, data, opts), acc), else: acc + lex(rest, binary, opts, line, column, nil, [], insert_node(node(type(b), line, column+1, [], opts), acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in ~w[^-= |*= <=>] do + node = node(String.to_atom(b), line, column+3, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+3, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+3, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in ~w[:: <> != !< !> <= >= += -= *= /= %= &= ||] do + node = node(String.to_atom(b), line, column+2, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+2, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[integer float]a and b in [?E, ?e] and (e in [?-, ?+] or e in ?0..?9) do + type = :float + lex(rest, binary, opts, line, column+2, type, merge(merge(data, b, type), e, type), acc, n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b == ?. and e in ?0..?9 do + lex(rest, binary, opts, line, column+2, :float, [b, e], acc, n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b in [?-, ?+] and e == ?. do + lex(rest, binary, opts, line, column+2, :float, [b,e], acc, n) + end + def lex(<>, binary, opts, line, column, :integer, data, acc, n) when b == ?. do + type = :float + lex(rest, binary, opts, line, column+1, type, merge(data, b, type), acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b == ?. do + node = node(List.to_atom([b]), line, column+1, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, _type, [] = data, [node | _] = acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] and is_data_type(node) do + node = node(List.to_atom([b]), line, column+1, data, opts) + lex(rest, binary, opts, line, column+1, nil, data, insert_node(node, acc), n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b in [?+, ?-] and c in ?0..?9 do + lex(rest, binary, opts, line, column+2, :integer, [b, c], acc, n) + end + def lex(<>, binary, opts, line, column, nil = type, data, acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] do + node = node(List.to_atom([b]), line, column+1, data, opts) + lex(rest, binary, opts, line, column+1, type, data, insert_node(node, acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] and type in ~w[integer float ident quote double_quote backtick bracket parens nil]a do + node = node(List.to_atom([b]), line, column+1, [], opts) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) do + type = type(b, type) + lex(rest, binary, opts, line, column+1, type, merge(data, b, type), acc, n) + end + + def insert_node(nil, _line, _column, _data, _opts, acc) do + acc + end + def insert_node(type, line, column, data, opts, acc) do + insert_node(node(type, line, column, data, opts), acc) + end + def insert_node(right, [{:. = tag, m, a}, {:., _, [_, _]} = left | acc]) do + [{tag, m, [left, right | a]} | acc] + end + def insert_node(right, [{:. = tag, meta, [left]} | acc]) do + [{tag, meta, [left, right]} | acc] + end + def insert_node({:., _, _} = node, [right, {:. = tag, m, []}, left | acc]) do + [node, {tag, m, [left, right]} | acc] + end + def insert_node({:. = t, m, a}, [left | acc]) do + [{t, m, [left|a]} | acc] + end + def insert_node({:join = t, m, a} = node, acc) do + case join(acc) do + {qualified, rest} -> [{t, m, [qualified|a]} | rest] + rest -> [node | rest] + end + end + def insert_node(node, acc) do + [node | acc] + end + + def join([{:outer, _} = r, {tag, _} = l, {:natural, _} = n | rest]) when tag in ~w[left right full]a do + {[n, l, r], rest} + end + def join([{:outer, _} = r, {tag, _} = l | rest]) when tag in ~w[left right full]a do + {[l, r], rest} + end + def join([{:inner, _} = r, {:natural, _} = l| rest]) do + {[l, r], rest} + end + def join([{tag, _} = l | rest]) when tag in ~w[inner left right full natural cross]a do + {[l], rest} + end + def join(acc) do + acc + end + + def merge([] = data, _b, type) when type in ~w[double_quote quote backtick]a, do: data + def merge(data, b, _type), do: data ++ [b] + + def type(?;), do: :colon + def type(?,), do: :comma + def type(?"), do: :double_quote + def type(?'), do: :quote + def type(?`), do: :backtick + def type(?(), do: :left_paren + def type(?)), do: :right_paren + def type(?[), do: :left_bracket + def type(?]), do: :right_bracket + + def type(%param{}), do: param + def type(param) when is_float(param), do: :float + def type(param) when is_integer(param), do: :integer + def type(param) when is_map(param), do: :map + def type(param) when is_list(param), do: {:list, Enum.uniq(Enum.map(param, &type/1))} + def type(param) when is_binary(param), do: :string + def type(_param), do: nil + + def type(_, type) when type in ~w[double_quote quote backtick comment comments]a, do: type + def type(?", _type), do: :double_quote + def type(?', _type), do: :quote + def type(?`, _type), do: :backtick + def type(b, type) when b in ?0..?9 and type in ~w[nil integer float]a, do: type || :integer + def type(?., :integer), do: :float + def type(_b, _type), do: :ident + + def meta(line, column, opts) do + if opts[:metadata], do: [line: line, column: column, file: opts[:file]], else: [] + end + + def node(:binding = tag, line, column, [idx], [{:binding, false}|_] = opts) do + {tag, meta(line, column, opts), Enum.at(opts[:params], idx)} + end + def node(tag, line, column, data, opts) when tag in ~w[ident float integer double_quote quote backtick binding parens bracket . comment comments]a do + data = case data do + [] -> data + [{_, _, _} | _] -> data + _ -> [data] + end + {tag, meta(line, column, opts), data} + end + def node(tag, line, column, _data, opts) when tag in ~w[asterisk inner left right full natural cross outer]a do + {tag, meta(line, column, opts)} + end + def node(tag, line, column, _data, opts) do + {tag, meta(line, column, opts), []} + end + + def ident(_type, [?*]), do: :asterisk + def ident(_type, [?(]), do: :parens + def ident(_type, [?[]), do: :bracket + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"bB" and b3 in ~c"sS", do: :abs + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"aA" and b2 in ~c"bB" and b3 in ~c"sS" and b4 in ~c"eE" and b5 in ~c"nN" and b6 in ~c"tT", do: :absent + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"aA" and b2 in ~c"cC" and b3 in ~c"oO" and b4 in ~c"sS", do: :acos + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"lL" and b3 in ~c"lL", do: :all + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"aA" and b2 in ~c"lL" and b3 in ~c"lL" and b4 in ~c"oO" and b5 in ~c"cC" and b6 in ~c"aA" and + b7 in ~c"tT" and b8 in ~c"eE", do: :allocate + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"aA" and b2 in ~c"lL" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR", do: :alter + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"nN" and b3 in ~c"dD", do: :and + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"nN" and b3 in ~c"yY", do: :any + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"aA" and b2 in ~c"nN" and b3 in ~c"yY" and b4 in ~c"_" and b5 in ~c"vV" and b6 in ~c"aA" and + b7 in ~c"lL" and b8 in ~c"uU" and b9 in ~c"eE", do: :any_value + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"rR" and b3 in ~c"eE", do: :are + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"aA" and b2 in ~c"rR" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"yY", do: :array + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"aA" and b2 in ~c"rR" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"yY" and b6 in ~c"_" and + b7 in ~c"aA" and b8 in ~c"gG" and b9 in ~c"gG", do: :array_agg + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21]) when b1 in ~c"aA" and b2 in ~c"rR" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"yY" and b6 in ~c"_" and + b7 in ~c"mM" and b8 in ~c"aA" and b9 in ~c"xX" and b10 in ~c"_" and b11 in ~c"cC" and + b12 in ~c"aA" and b13 in ~c"rR" and b14 in ~c"dD" and b15 in ~c"iI" and b16 in ~c"nN" and + b17 in ~c"aA" and b18 in ~c"lL" and b19 in ~c"iI" and b20 in ~c"tT" and b21 in ~c"yY", do: :array_max_cardinality + + def ident(:ident, [b1,b2]) when b1 in ~c"aA" and b2 in ~c"sS", do: :as + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"iI" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"vV" and b10 in ~c"eE", do: :asensitive + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"iI" and b4 in ~c"nN", do: :asin + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"yY" and b4 in ~c"mM" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"rR" and b9 in ~c"iI" and b10 in ~c"cC", do: :asymmetric + + def ident(:ident, [b1,b2]) when b1 in ~c"aA" and b2 in ~c"tT", do: :at + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"aA" and b2 in ~c"tT" and b3 in ~c"aA" and b4 in ~c"nN", do: :atan + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"aA" and b2 in ~c"tT" and b3 in ~c"oO" and b4 in ~c"mM" and b5 in ~c"iI" and b6 in ~c"cC", do: :atomic + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"aA" and b2 in ~c"uU" and b3 in ~c"tT" and b4 in ~c"hH" and b5 in ~c"oO" and b6 in ~c"rR" and + b7 in ~c"iI" and b8 in ~c"zZ" and b9 in ~c"aA" and b10 in ~c"tT" and b11 in ~c"iI" and + b12 in ~c"oO" and b13 in ~c"nN", do: :authorization + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"vV" and b3 in ~c"gG", do: :avg + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"iI" and b5 in ~c"nN", do: :begin + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"_" and + b7 in ~c"fF" and b8 in ~c"rR" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"eE", do: :begin_frame + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"_" and + b7 in ~c"pP" and b8 in ~c"aA" and b9 in ~c"rR" and b10 in ~c"tT" and b11 in ~c"iI" and + b12 in ~c"tT" and b13 in ~c"iI" and b14 in ~c"oO" and b15 in ~c"nN", do: :begin_partition + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"wW" and b5 in ~c"eE" and b6 in ~c"eE" and + b7 in ~c"nN", do: :between + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"bB" and b2 in ~c"iI" and b3 in ~c"gG" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"tT", do: :bigint + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"bB" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"rR" and b6 in ~c"yY", do: :binary + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"bB" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"bB", do: :blob + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"bB" and b2 in ~c"oO" and b3 in ~c"oO" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"aA" and + b7 in ~c"nN", do: :boolean + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"bB" and b2 in ~c"oO" and b3 in ~c"tT" and b4 in ~c"hH", do: :both + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"bB" and b2 in ~c"tT" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"mM", do: :btrim + + def ident(:ident, [b1,b2]) when b1 in ~c"bB" and b2 in ~c"yY", do: :by + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"lL", do: :call + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"dD", do: :called + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"dD" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"aA" and b8 in ~c"lL" and b9 in ~c"iI" and b10 in ~c"tT" and b11 in ~c"yY", do: :cardinality + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"aA" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"dD", do: :cascaded + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"eE", do: :case + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"tT", do: :cast + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"eE" and b3 in ~c"iI" and b4 in ~c"lL", do: :ceil + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"eE" and b3 in ~c"iI" and b4 in ~c"lL" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :ceiling + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR", do: :char + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"lL" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"gG" and b10 in ~c"tT" and b11 in ~c"hH", do: :char_length + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR", do: :character + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"lL" and + b12 in ~c"eE" and b13 in ~c"nN" and b14 in ~c"gG" and b15 in ~c"tT" and b16 in ~c"hH", do: :character_length + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"kK", do: :check + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"cC" and b2 in ~c"lL" and b3 in ~c"aA" and b4 in ~c"sS" and b5 in ~c"sS" and b6 in ~c"iI" and + b7 in ~c"fF" and b8 in ~c"iI" and b9 in ~c"eE" and b10 in ~c"rR", do: :classifier + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"bB", do: :clob + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"sS" and b5 in ~c"eE", do: :close + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"aA" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"sS" and + b7 in ~c"cC" and b8 in ~c"eE", do: :coalesce + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"eE", do: :collate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"cC" and + b7 in ~c"tT", do: :collect + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"mM" and b6 in ~c"nN", do: :column + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"mM" and b5 in ~c"iI" and b6 in ~c"tT", do: :commit + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"dD" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :condition + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"nN" and b5 in ~c"eE" and b6 in ~c"cC" and + b7 in ~c"tT", do: :connect + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"tT", do: :constraint + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"tT" and b5 in ~c"aA" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"sS", do: :contains + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"vV" and b5 in ~c"eE" and b6 in ~c"rR" and + b7 in ~c"tT", do: :convert + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"pP" and b4 in ~c"yY", do: :copy + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"rR", do: :corr + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"sS" and + b7 in ~c"pP" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"dD" and b11 in ~c"iI" and + b12 in ~c"nN" and b13 in ~c"gG", do: :corresponding + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"sS", do: :cos + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"sS" and b4 in ~c"hH", do: :cosh + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"nN" and b5 in ~c"tT", do: :count + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"vV" and b4 in ~c"aA" and b5 in ~c"rR" and b6 in ~c"_" and + b7 in ~c"pP" and b8 in ~c"oO" and b9 in ~c"pP", do: :covar_pop + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"vV" and b4 in ~c"aA" and b5 in ~c"rR" and b6 in ~c"_" and + b7 in ~c"sS" and b8 in ~c"aA" and b9 in ~c"mM" and b10 in ~c"pP", do: :covar_samp + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"cC" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"eE", do: :create + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"sS" and b5 in ~c"sS", do: :cross + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"eE", do: :cube + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"sS" and b9 in ~c"tT", do: :cume_dist + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT", do: :current + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"cC" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"aA" and b13 in ~c"lL" and b14 in ~c"oO" and b15 in ~c"gG", do: :current_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"dD" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"eE", do: :current_date + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25,b26,b27,b28,b29,b30,b31]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"dD" and b10 in ~c"eE" and b11 in ~c"fF" and + b12 in ~c"aA" and b13 in ~c"uU" and b14 in ~c"lL" and b15 in ~c"tT" and b16 in ~c"_" and + b17 in ~c"tT" and b18 in ~c"rR" and b19 in ~c"aA" and b20 in ~c"nN" and b21 in ~c"sS" and + b22 in ~c"fF" and b23 in ~c"oO" and b24 in ~c"rR" and b25 in ~c"mM" and b26 in ~c"_" and + b27 in ~c"gG" and b28 in ~c"rR" and b29 in ~c"oO" and b30 in ~c"uU" and b31 in ~c"pP", do: :current_default_transform_group + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"pP" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"hH", do: :current_path + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"rR" and b10 in ~c"oO" and b11 in ~c"lL" and + b12 in ~c"eE", do: :current_role + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"rR" and b10 in ~c"oO" and b11 in ~c"wW", do: :current_row + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"sS" and b10 in ~c"cC" and b11 in ~c"hH" and + b12 in ~c"eE" and b13 in ~c"mM" and b14 in ~c"aA", do: :current_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"tT" and b10 in ~c"iI" and b11 in ~c"mM" and + b12 in ~c"eE", do: :current_time + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"tT" and b10 in ~c"iI" and b11 in ~c"mM" and + b12 in ~c"eE" and b13 in ~c"sS" and b14 in ~c"tT" and b15 in ~c"aA" and b16 in ~c"mM" and + b17 in ~c"pP", do: :current_timestamp + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25,b26,b27,b28,b29,b30,b31,b32]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"tT" and b10 in ~c"rR" and b11 in ~c"aA" and + b12 in ~c"nN" and b13 in ~c"sS" and b14 in ~c"fF" and b15 in ~c"oO" and b16 in ~c"rR" and + b17 in ~c"mM" and b18 in ~c"_" and b19 in ~c"gG" and b20 in ~c"rR" and b21 in ~c"oO" and + b22 in ~c"uU" and b23 in ~c"pP" and b24 in ~c"_" and b25 in ~c"fF" and b26 in ~c"oO" and + b27 in ~c"rR" and b28 in ~c"_" and b29 in ~c"tT" and b30 in ~c"yY" and b31 in ~c"pP" and + b32 in ~c"eE", do: :current_transform_group_for_type + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"uU" and b10 in ~c"sS" and b11 in ~c"eE" and + b12 in ~c"rR", do: :current_user + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"sS" and b5 in ~c"oO" and b6 in ~c"rR", do: :cursor + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"yY" and b3 in ~c"cC" and b4 in ~c"lL" and b5 in ~c"eE", do: :cycle + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"dD" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"eE", do: :date + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"dD" and b2 in ~c"aA" and b3 in ~c"yY", do: :day + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"lL" and b5 in ~c"lL" and b6 in ~c"oO" and + b7 in ~c"cC" and b8 in ~c"aA" and b9 in ~c"tT" and b10 in ~c"eE", do: :deallocate + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"cC", do: :dec + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"fF" and b5 in ~c"lL" and b6 in ~c"oO" and + b7 in ~c"aA" and b8 in ~c"tT", do: :decfloat + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"iI" and b5 in ~c"mM" and b6 in ~c"aA" and + b7 in ~c"lL", do: :decimal + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"eE", do: :declare + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"aA" and b5 in ~c"uU" and b6 in ~c"lL" and + b7 in ~c"tT", do: :default + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"eE", do: :define + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"lL" and b4 in ~c"eE" and b5 in ~c"tT" and b6 in ~c"eE", do: :delete + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"rR" and b8 in ~c"aA" and b9 in ~c"nN" and b10 in ~c"kK", do: :dense_rank + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"eE" and b5 in ~c"fF", do: :deref + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"bB" and b8 in ~c"eE", do: :describe + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"mM" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"iI" and b10 in ~c"sS" and b11 in ~c"tT" and + b12 in ~c"iI" and b13 in ~c"cC", do: :deterministic + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"dD" and b2 in ~c"iI" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"oO" and b6 in ~c"nN" and + b7 in ~c"nN" and b8 in ~c"eE" and b9 in ~c"cC" and b10 in ~c"tT", do: :disconnect + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"iI" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"cC" and b8 in ~c"tT", do: :distinct + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"dD" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"bB" and b5 in ~c"lL" and b6 in ~c"eE", do: :double + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"dD" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"pP", do: :drop + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"yY" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"iI" and + b7 in ~c"cC", do: :dynamic + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"eE" and b2 in ~c"aA" and b3 in ~c"cC" and b4 in ~c"hH", do: :each + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"eE" and b2 in ~c"lL" and b3 in ~c"eE" and b4 in ~c"mM" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT", do: :element + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"eE" and b2 in ~c"lL" and b3 in ~c"sS" and b4 in ~c"eE", do: :else + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"eE" and b2 in ~c"mM" and b3 in ~c"pP" and b4 in ~c"tT" and b5 in ~c"yY", do: :empty + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"dD", do: :end + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"dD" and b4 in ~c"_" and b5 in ~c"fF" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"mM" and b9 in ~c"eE", do: :end_frame + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"dD" and b4 in ~c"_" and b5 in ~c"pP" and b6 in ~c"aA" and + b7 in ~c"rR" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"tT" and b11 in ~c"iI" and + b12 in ~c"oO" and b13 in ~c"nN", do: :end_partition + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"dD" and b4 in ~c"-" and b5 in ~c"eE" and b6 in ~c"xX" and + b7 in ~c"eE" and b8 in ~c"cC", do: :"end-exec" + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"eE" and b2 in ~c"qQ" and b3 in ~c"uU" and b4 in ~c"aA" and b5 in ~c"lL" and b6 in ~c"sS", do: :equals + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"eE" and b2 in ~c"sS" and b3 in ~c"cC" and b4 in ~c"aA" and b5 in ~c"pP" and b6 in ~c"eE", do: :escape + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"eE" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"yY", do: :every + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"cC" and b4 in ~c"eE" and b5 in ~c"pP" and b6 in ~c"tT", do: :except + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"eE" and b4 in ~c"cC", do: :exec + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"uU" and b6 in ~c"tT" and + b7 in ~c"eE", do: :execute + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"iI" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"sS", do: :exists + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"pP", do: :exp + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"aA" and b8 in ~c"lL", do: :external + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"tT" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT", do: :extract + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"sS" and b5 in ~c"eE", do: false + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH", do: :fetch + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"fF" and b2 in ~c"iI" and b3 in ~c"lL" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"rR", do: :filter + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"fF" and b2 in ~c"iI" and b3 in ~c"rR" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"_" and + b7 in ~c"vV" and b8 in ~c"aA" and b9 in ~c"lL" and b10 in ~c"uU" and b11 in ~c"eE", do: :first_value + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"aA" and b5 in ~c"tT", do: :float + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"oO" and b5 in ~c"rR", do: :floor + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"rR", do: :for + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"eE" and b5 in ~c"iI" and b6 in ~c"gG" and + b7 in ~c"nN", do: :foreign + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"fF" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"mM" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"rR" and b8 in ~c"oO" and b9 in ~c"wW", do: :frame_row + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"fF" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"eE", do: :free + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"fF" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"mM", do: :from + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"fF" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL", do: :full + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"fF" and b2 in ~c"uU" and b3 in ~c"nN" and b4 in ~c"cC" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"oO" and b8 in ~c"nN", do: :function + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"fF" and b2 in ~c"uU" and b3 in ~c"sS" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"nN", do: :fusion + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"gG" and b2 in ~c"eE" and b3 in ~c"tT", do: :get + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"gG" and b2 in ~c"lL" and b3 in ~c"oO" and b4 in ~c"bB" and b5 in ~c"aA" and b6 in ~c"lL", do: :global + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"tT", do: :grant + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"eE" and + b7 in ~c"sS" and b8 in ~c"tT", do: :greatest + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"uU" and b5 in ~c"pP", do: :group + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"uU" and b5 in ~c"pP" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"gG", do: :grouping + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"uU" and b5 in ~c"pP" and b6 in ~c"sS", do: :groups + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"hH" and b2 in ~c"aA" and b3 in ~c"vV" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"gG", do: :having + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"hH" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"dD", do: :hold + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"hH" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"rR", do: :hour + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"iI" and b2 in ~c"dD" and b3 in ~c"eE" and b4 in ~c"nN" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"tT" and b8 in ~c"yY", do: :identity + + def ident(:ident, [b1,b2]) when b1 in ~c"iI" and b2 in ~c"nN", do: :in + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"dD" and b4 in ~c"iI" and b5 in ~c"cC" and b6 in ~c"aA" and + b7 in ~c"tT" and b8 in ~c"oO" and b9 in ~c"rR", do: :indicator + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"iI" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"aA" and + b7 in ~c"lL", do: :initial + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"nN" and b4 in ~c"eE" and b5 in ~c"rR", do: :inner + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"oO" and b4 in ~c"uU" and b5 in ~c"tT", do: :inout + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"sS" and b4 in ~c"eE" and b5 in ~c"nN" and b6 in ~c"sS" and + b7 in ~c"iI" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"vV" and b11 in ~c"eE", do: :insensitive + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"sS" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"tT", do: :insert + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT", do: :int + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"gG" and b6 in ~c"eE" and + b7 in ~c"rR", do: :integer + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"sS" and + b7 in ~c"eE" and b8 in ~c"cC" and b9 in ~c"tT", do: :intersect + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"sS" and + b7 in ~c"eE" and b8 in ~c"cC" and b9 in ~c"tT" and b10 in ~c"iI" and b11 in ~c"oO" and + b12 in ~c"nN", do: :intersection + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"vV" and + b7 in ~c"aA" and b8 in ~c"lL", do: :interval + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"tT" and b4 in ~c"oO", do: :into + + def ident(:ident, [b1,b2]) when b1 in ~c"iI" and b2 in ~c"sS", do: :is + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"jJ" and b2 in ~c"oO" and b3 in ~c"iI" and b4 in ~c"nN", do: :join + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN", do: :json + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"aA" and + b7 in ~c"rR" and b8 in ~c"rR" and b9 in ~c"aA" and b10 in ~c"yY", do: :json_array + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"aA" and + b7 in ~c"rR" and b8 in ~c"rR" and b9 in ~c"aA" and b10 in ~c"yY" and b11 in ~c"aA" and + b12 in ~c"gG" and b13 in ~c"gG", do: :json_arrayagg + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"eE" and + b7 in ~c"xX" and b8 in ~c"iI" and b9 in ~c"sS" and b10 in ~c"tT" and b11 in ~c"sS", do: :json_exists + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"oO" and + b7 in ~c"bB" and b8 in ~c"jJ" and b9 in ~c"eE" and b10 in ~c"cC" and b11 in ~c"tT", do: :json_object + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"oO" and + b7 in ~c"bB" and b8 in ~c"jJ" and b9 in ~c"eE" and b10 in ~c"cC" and b11 in ~c"tT" and + b12 in ~c"aA" and b13 in ~c"gG" and b14 in ~c"gG", do: :json_objectagg + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"qQ" and + b7 in ~c"uU" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"yY", do: :json_query + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"cC" and b8 in ~c"aA" and b9 in ~c"lL" and b10 in ~c"aA" and b11 in ~c"rR", do: :json_scalar + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"eE" and b8 in ~c"rR" and b9 in ~c"iI" and b10 in ~c"aA" and b11 in ~c"lL" and + b12 in ~c"iI" and b13 in ~c"zZ" and b14 in ~c"eE", do: :json_serialize + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"tT" and + b7 in ~c"aA" and b8 in ~c"bB" and b9 in ~c"lL" and b10 in ~c"eE", do: :json_table + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"tT" and + b7 in ~c"aA" and b8 in ~c"bB" and b9 in ~c"lL" and b10 in ~c"eE" and b11 in ~c"_" and + b12 in ~c"pP" and b13 in ~c"rR" and b14 in ~c"iI" and b15 in ~c"mM" and b16 in ~c"iI" and + b17 in ~c"tT" and b18 in ~c"iI" and b19 in ~c"vV" and b20 in ~c"eE", do: :json_table_primitive + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"jJ" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"nN" and b5 in ~c"_" and b6 in ~c"vV" and + b7 in ~c"aA" and b8 in ~c"lL" and b9 in ~c"uU" and b10 in ~c"eE", do: :json_value + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"gG", do: :lag + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"nN" and b4 in ~c"gG" and b5 in ~c"uU" and b6 in ~c"aA" and + b7 in ~c"gG" and b8 in ~c"eE", do: :language + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"gG" and b5 in ~c"eE", do: :large + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"_" and b6 in ~c"vV" and + b7 in ~c"aA" and b8 in ~c"lL" and b9 in ~c"uU" and b10 in ~c"eE", do: :last_value + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"aA" and + b7 in ~c"lL", do: :lateral + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"dD", do: :lead + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"dD" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :leading + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"sS" and b5 in ~c"tT", do: :least + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"tT", do: :left + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"lL" and b2 in ~c"iI" and b3 in ~c"kK" and b4 in ~c"eE", do: :like + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"lL" and b2 in ~c"iI" and b3 in ~c"kK" and b4 in ~c"eE" and b5 in ~c"_" and b6 in ~c"rR" and + b7 in ~c"eE" and b8 in ~c"gG" and b9 in ~c"eE" and b10 in ~c"xX", do: :like_regex + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"lL" and b2 in ~c"iI" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"aA" and b6 in ~c"gG" and + b7 in ~c"gG", do: :listagg + + def ident(:ident, [b1,b2]) when b1 in ~c"lL" and b2 in ~c"nN", do: :ln + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"cC" and b4 in ~c"aA" and b5 in ~c"lL", do: :local + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"cC" and b4 in ~c"aA" and b5 in ~c"lL" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"mM" and b9 in ~c"eE", do: :localtime + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"cC" and b4 in ~c"aA" and b5 in ~c"lL" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"mM" and b9 in ~c"eE" and b10 in ~c"sS" and b11 in ~c"tT" and + b12 in ~c"aA" and b13 in ~c"mM" and b14 in ~c"pP", do: :localtimestamp + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"gG", do: :log + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"gG" and b4 in ~c"1" and b5 in ~c"0", do: :log10 + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"wW" and b4 in ~c"eE" and b5 in ~c"rR", do: :lower + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"lL" and b2 in ~c"pP" and b3 in ~c"aA" and b4 in ~c"dD", do: :lpad + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"tT" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"mM", do: :ltrim + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH", do: :match + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH" and b6 in ~c"_" and + b7 in ~c"nN" and b8 in ~c"uU" and b9 in ~c"mM" and b10 in ~c"bB" and b11 in ~c"eE" and + b12 in ~c"rR", do: :match_number + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH" and b6 in ~c"_" and + b7 in ~c"rR" and b8 in ~c"eE" and b9 in ~c"cC" and b10 in ~c"oO" and b11 in ~c"gG" and + b12 in ~c"nN" and b13 in ~c"iI" and b14 in ~c"zZ" and b15 in ~c"eE", do: :match_recognize + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH" and b6 in ~c"eE" and + b7 in ~c"sS", do: :matches + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"xX", do: :max + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"mM" and b4 in ~c"bB" and b5 in ~c"eE" and b6 in ~c"rR", do: :member + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"gG" and b5 in ~c"eE", do: :merge + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"hH" and b5 in ~c"oO" and b6 in ~c"dD", do: :method + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"mM" and b2 in ~c"iI" and b3 in ~c"nN", do: :min + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"mM" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"uU" and b5 in ~c"tT" and b6 in ~c"eE", do: :minute + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"mM" and b2 in ~c"oO" and b3 in ~c"dD", do: :mod + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"mM" and b2 in ~c"oO" and b3 in ~c"dD" and b4 in ~c"iI" and b5 in ~c"fF" and b6 in ~c"iI" and + b7 in ~c"eE" and b8 in ~c"sS", do: :modifies + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"mM" and b2 in ~c"oO" and b3 in ~c"dD" and b4 in ~c"uU" and b5 in ~c"lL" and b6 in ~c"eE", do: :module + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"mM" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"tT" and b5 in ~c"hH", do: :month + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"mM" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"sS" and + b7 in ~c"eE" and b8 in ~c"tT", do: :multiset + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"nN" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"nN" and + b7 in ~c"aA" and b8 in ~c"lL", do: :national + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"nN" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"aA" and + b7 in ~c"lL", do: :natural + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"nN" and b2 in ~c"cC" and b3 in ~c"hH" and b4 in ~c"aA" and b5 in ~c"rR", do: :nchar + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"nN" and b2 in ~c"cC" and b3 in ~c"lL" and b4 in ~c"oO" and b5 in ~c"bB", do: :nclob + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"nN" and b2 in ~c"eE" and b3 in ~c"wW", do: :new + + def ident(:ident, [b1,b2]) when b1 in ~c"nN" and b2 in ~c"oO", do: :no + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"eE", do: :none + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"nN" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"lL" and + b7 in ~c"iI" and b8 in ~c"zZ" and b9 in ~c"eE", do: :normalize + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"nN" and b2 in ~c"oO" and b3 in ~c"tT", do: :not + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"nN" and b2 in ~c"tT" and b3 in ~c"hH" and b4 in ~c"_" and b5 in ~c"vV" and b6 in ~c"aA" and + b7 in ~c"lL" and b8 in ~c"uU" and b9 in ~c"eE", do: :nth_value + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"nN" and b2 in ~c"tT" and b3 in ~c"iI" and b4 in ~c"lL" and b5 in ~c"eE", do: :ntile + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL", do: :null + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"iI" and b6 in ~c"fF", do: :nullif + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"cC", do: :numeric + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17]) when b1 in ~c"oO" and b2 in ~c"cC" and b3 in ~c"cC" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"rR" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"cC" and b10 in ~c"eE" and b11 in ~c"sS" and + b12 in ~c"_" and b13 in ~c"rR" and b14 in ~c"eE" and b15 in ~c"gG" and b16 in ~c"eE" and + b17 in ~c"xX", do: :occurrences_regex + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"oO" and b2 in ~c"cC" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"tT" and b6 in ~c"_" and + b7 in ~c"lL" and b8 in ~c"eE" and b9 in ~c"nN" and b10 in ~c"gG" and b11 in ~c"tT" and + b12 in ~c"hH", do: :octet_length + + def ident(:ident, [b1,b2]) when b1 in ~c"oO" and b2 in ~c"fF", do: :of + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"fF" and b3 in ~c"fF" and b4 in ~c"sS" and b5 in ~c"eE" and b6 in ~c"tT", do: :offset + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"oO" and b2 in ~c"lL" and b3 in ~c"dD", do: :old + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"oO" and b2 in ~c"mM" and b3 in ~c"iI" and b4 in ~c"tT", do: :omit + + def ident(:ident, [b1,b2]) when b1 in ~c"oO" and b2 in ~c"nN", do: :on + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"oO" and b2 in ~c"nN" and b3 in ~c"eE", do: :one + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"oO" and b2 in ~c"nN" and b3 in ~c"lL" and b4 in ~c"yY", do: :only + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"oO" and b2 in ~c"pP" and b3 in ~c"eE" and b4 in ~c"nN", do: :open + + def ident(:ident, [b1,b2]) when b1 in ~c"oO" and b2 in ~c"rR", do: :or + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"oO" and b2 in ~c"rR" and b3 in ~c"dD" and b4 in ~c"eE" and b5 in ~c"rR", do: :order + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"oO" and b2 in ~c"uU" and b3 in ~c"tT", do: :out + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"oO" and b2 in ~c"uU" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR", do: :outer + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"oO" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR", do: :over + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"oO" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"lL" and b6 in ~c"aA" and + b7 in ~c"pP" and b8 in ~c"sS", do: :overlaps + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"oO" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"lL" and b6 in ~c"aA" and + b7 in ~c"yY", do: :overlay + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR", do: :parameter + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :partition + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"rR" and + b7 in ~c"nN", do: :pattern + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR", do: :per + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT", do: :percent + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"_" and b9 in ~c"rR" and b10 in ~c"aA" and b11 in ~c"nN" and + b12 in ~c"kK", do: :percent_rank + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"lL" and b10 in ~c"eE" and b11 in ~c"_" and + b12 in ~c"cC" and b13 in ~c"oO" and b14 in ~c"nN" and b15 in ~c"tT", do: :percentile_cont + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"lL" and b10 in ~c"eE" and b11 in ~c"_" and + b12 in ~c"dD" and b13 in ~c"iI" and b14 in ~c"sS" and b15 in ~c"cC", do: :percentile_disc + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"dD", do: :period + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"oO" and + b7 in ~c"nN", do: :portion + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"pP" and b2 in ~c"oO" and b3 in ~c"sS" and b4 in ~c"iI" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"oO" and b8 in ~c"nN", do: :position + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"pP" and b2 in ~c"oO" and b3 in ~c"sS" and b4 in ~c"iI" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"oO" and b8 in ~c"nN" and b9 in ~c"_" and b10 in ~c"rR" and b11 in ~c"eE" and + b12 in ~c"gG" and b13 in ~c"eE" and b14 in ~c"xX", do: :position_regex + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"pP" and b2 in ~c"oO" and b3 in ~c"wW" and b4 in ~c"eE" and b5 in ~c"rR", do: :power + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"sS", do: :precedes + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"iI" and b6 in ~c"sS" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :precision + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"pP" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"eE", do: :prepare + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"yY", do: :primary + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"oO" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"dD" and + b7 in ~c"uU" and b8 in ~c"rR" and b9 in ~c"eE", do: :procedure + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"pP" and b2 in ~c"tT" and b3 in ~c"fF", do: :ptf + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"rR" and b2 in ~c"aA" and b3 in ~c"nN" and b4 in ~c"gG" and b5 in ~c"eE", do: :range + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"aA" and b3 in ~c"nN" and b4 in ~c"kK", do: :rank + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"dD" and b5 in ~c"sS", do: :reads + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"lL", do: :real + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"sS" and + b7 in ~c"iI" and b8 in ~c"vV" and b9 in ~c"eE", do: :recursive + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"fF", do: :ref + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"eE" and + b7 in ~c"nN" and b8 in ~c"cC" and b9 in ~c"eE" and b10 in ~c"sS", do: :references + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"eE" and + b7 in ~c"nN" and b8 in ~c"cC" and b9 in ~c"iI" and b10 in ~c"nN" and b11 in ~c"gG", do: :referencing + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"aA" and + b7 in ~c"vV" and b8 in ~c"gG" and b9 in ~c"xX", do: :regr_avgx + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"aA" and + b7 in ~c"vV" and b8 in ~c"gG" and b9 in ~c"yY", do: :regr_avgy + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"cC" and + b7 in ~c"oO" and b8 in ~c"uU" and b9 in ~c"nN" and b10 in ~c"tT", do: :regr_count + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"tT" and b9 in ~c"eE" and b10 in ~c"rR" and b11 in ~c"cC" and + b12 in ~c"eE" and b13 in ~c"pP" and b14 in ~c"tT", do: :regr_intercept + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"rR" and + b7 in ~c"2", do: :regr_r2 + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"lL" and b8 in ~c"oO" and b9 in ~c"pP" and b10 in ~c"eE", do: :regr_slope + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"xX" and b8 in ~c"xX", do: :regr_sxx + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"xX" and b8 in ~c"yY", do: :regr_sxy + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"sS" and + b7 in ~c"yY" and b8 in ~c"yY", do: :regr_syy + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"lL" and b4 in ~c"eE" and b5 in ~c"aA" and b6 in ~c"sS" and + b7 in ~c"eE", do: :release + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"uU" and b5 in ~c"lL" and b6 in ~c"tT", do: :result + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN", do: :return + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"sS", do: :returns + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"vV" and b4 in ~c"oO" and b5 in ~c"kK" and b6 in ~c"eE", do: :revoke + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"rR" and b2 in ~c"iI" and b3 in ~c"gG" and b4 in ~c"hH" and b5 in ~c"tT", do: :right + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"bB" and b6 in ~c"aA" and + b7 in ~c"cC" and b8 in ~c"kK", do: :rollback + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"uU" and b6 in ~c"pP", do: :rollup + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"wW", do: :row + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"wW" and b4 in ~c"_" and b5 in ~c"nN" and b6 in ~c"uU" and + b7 in ~c"mM" and b8 in ~c"bB" and b9 in ~c"eE" and b10 in ~c"rR", do: :row_number + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"wW" and b4 in ~c"sS", do: :rows + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"pP" and b3 in ~c"aA" and b4 in ~c"dD", do: :rpad + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"rR" and b2 in ~c"tT" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"mM", do: :rtrim + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"uU" and b3 in ~c"nN" and b4 in ~c"nN" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :running + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"aA" and b3 in ~c"vV" and b4 in ~c"eE" and b5 in ~c"pP" and b6 in ~c"oO" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"tT", do: :savepoint + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"oO" and b4 in ~c"pP" and b5 in ~c"eE", do: :scope + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"rR" and b4 in ~c"oO" and b5 in ~c"lL" and b6 in ~c"lL", do: :scroll + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"cC" and b6 in ~c"hH", do: :search + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"oO" and b5 in ~c"nN" and b6 in ~c"dD", do: :second + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"eE" and b4 in ~c"kK", do: :seek + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"lL" and b4 in ~c"eE" and b5 in ~c"cC" and b6 in ~c"tT", do: :select + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"vV" and b9 in ~c"eE", do: :sensitive + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"iI" and b6 in ~c"oO" and + b7 in ~c"nN" and b8 in ~c"_" and b9 in ~c"uU" and b10 in ~c"sS" and b11 in ~c"eE" and + b12 in ~c"rR", do: :session_user + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"tT", do: :set + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"hH" and b3 in ~c"oO" and b4 in ~c"wW", do: :show + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"sS" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"iI" and b5 in ~c"lL" and b6 in ~c"aA" and + b7 in ~c"rR", do: :similar + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"sS" and b2 in ~c"iI" and b3 in ~c"nN", do: :sin + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"hH", do: :sinh + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"kK" and b3 in ~c"iI" and b4 in ~c"pP", do: :skip + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"mM" and b3 in ~c"aA" and b4 in ~c"lL" and b5 in ~c"lL" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"tT", do: :smallint + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"eE", do: :some + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"pP" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"iI" and b6 in ~c"fF" and + b7 in ~c"iI" and b8 in ~c"cC", do: :specific + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"sS" and b2 in ~c"pP" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"iI" and b6 in ~c"fF" and + b7 in ~c"iI" and b8 in ~c"cC" and b9 in ~c"tT" and b10 in ~c"yY" and b11 in ~c"pP" and + b12 in ~c"eE", do: :specifictype + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"sS" and b2 in ~c"qQ" and b3 in ~c"lL", do: :sql + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"sS" and b2 in ~c"qQ" and b3 in ~c"lL" and b4 in ~c"eE" and b5 in ~c"xX" and b6 in ~c"cC" and + b7 in ~c"eE" and b8 in ~c"pP" and b9 in ~c"tT" and b10 in ~c"iI" and b11 in ~c"oO" and + b12 in ~c"nN", do: :sqlexception + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"qQ" and b3 in ~c"lL" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"aA" and + b7 in ~c"tT" and b8 in ~c"eE", do: :sqlstate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"sS" and b2 in ~c"qQ" and b3 in ~c"lL" and b4 in ~c"wW" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"nN" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"gG", do: :sqlwarning + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"qQ" and b3 in ~c"rR" and b4 in ~c"tT", do: :sqrt + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"tT", do: :start + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"aA" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"cC", do: :static + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"dD" and b4 in ~c"dD" and b5 in ~c"eE" and b6 in ~c"vV" and + b7 in ~c"_" and b8 in ~c"pP" and b9 in ~c"oO" and b10 in ~c"pP", do: :stddev_pop + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"dD" and b4 in ~c"dD" and b5 in ~c"eE" and b6 in ~c"vV" and + b7 in ~c"_" and b8 in ~c"sS" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"pP", do: :stddev_samp + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"mM" and b5 in ~c"uU" and b6 in ~c"lL" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"sS" and b10 in ~c"eE" and b11 in ~c"tT", do: :submultiset + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"sS" and b5 in ~c"eE" and b6 in ~c"tT", do: :subset + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :substring + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG" and b10 in ~c"_" and b11 in ~c"rR" and + b12 in ~c"eE" and b13 in ~c"gG" and b14 in ~c"eE" and b15 in ~c"xX", do: :substring_regex + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"cC" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"eE" and + b7 in ~c"dD" and b8 in ~c"sS", do: :succeeds + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"mM", do: :sum + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"yY" and b3 in ~c"mM" and b4 in ~c"mM" and b5 in ~c"eE" and b6 in ~c"tT" and + b7 in ~c"rR" and b8 in ~c"iI" and b9 in ~c"cC", do: :symmetric + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"yY" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"mM", do: :system + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"yY" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"mM" and + b7 in ~c"_" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"mM" and b11 in ~c"eE", do: :system_time + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"yY" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"mM" and + b7 in ~c"_" and b8 in ~c"uU" and b9 in ~c"sS" and b10 in ~c"eE" and b11 in ~c"rR", do: :system_user + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"tT" and b2 in ~c"aA" and b3 in ~c"bB" and b4 in ~c"lL" and b5 in ~c"eE", do: :table + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"tT" and b2 in ~c"aA" and b3 in ~c"bB" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"sS" and + b7 in ~c"aA" and b8 in ~c"mM" and b9 in ~c"pP" and b10 in ~c"lL" and b11 in ~c"eE", do: :tablesample + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"tT" and b2 in ~c"aA" and b3 in ~c"nN", do: :tan + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"aA" and b3 in ~c"nN" and b4 in ~c"hH", do: :tanh + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"hH" and b3 in ~c"eE" and b4 in ~c"nN", do: :then + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"eE", do: :time + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"tT" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"sS" and b6 in ~c"tT" and + b7 in ~c"aA" and b8 in ~c"mM" and b9 in ~c"pP", do: :timestamp + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"tT" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"zZ" and b6 in ~c"oO" and + b7 in ~c"nN" and b8 in ~c"eE" and b9 in ~c"_" and b10 in ~c"hH" and b11 in ~c"oO" and + b12 in ~c"uU" and b13 in ~c"rR", do: :timezone_hour + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"tT" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"zZ" and b6 in ~c"oO" and + b7 in ~c"nN" and b8 in ~c"eE" and b9 in ~c"_" and b10 in ~c"mM" and b11 in ~c"iI" and + b12 in ~c"nN" and b13 in ~c"uU" and b14 in ~c"tT" and b15 in ~c"eE", do: :timezone_minute + + def ident(:ident, [b1,b2]) when b1 in ~c"tT" and b2 in ~c"oO", do: :to + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"iI" and b5 in ~c"lL" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"gG", do: :trailing + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"lL" and + b7 in ~c"aA" and b8 in ~c"tT" and b9 in ~c"eE", do: :translate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"lL" and + b7 in ~c"aA" and b8 in ~c"tT" and b9 in ~c"eE" and b10 in ~c"_" and b11 in ~c"rR" and + b12 in ~c"eE" and b13 in ~c"gG" and b14 in ~c"eE" and b15 in ~c"xX", do: :translate_regex + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"lL" and + b7 in ~c"aA" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN", do: :translation + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"aA" and b5 in ~c"tT", do: :treat + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"gG" and b5 in ~c"gG" and b6 in ~c"eE" and + b7 in ~c"rR", do: :trigger + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"mM", do: :trim + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"mM" and b5 in ~c"_" and b6 in ~c"aA" and + b7 in ~c"rR" and b8 in ~c"rR" and b9 in ~c"aA" and b10 in ~c"yY", do: :trim_array + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"uU" and b4 in ~c"eE", do: true + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"uU" and b4 in ~c"nN" and b5 in ~c"cC" and b6 in ~c"aA" and + b7 in ~c"tT" and b8 in ~c"eE", do: :truncate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"uU" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"aA" and b6 in ~c"pP" and + b7 in ~c"eE", do: :uescape + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"iI" and b4 in ~c"oO" and b5 in ~c"nN", do: :union + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"iI" and b4 in ~c"qQ" and b5 in ~c"uU" and b6 in ~c"eE", do: :unique + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"kK" and b4 in ~c"nN" and b5 in ~c"oO" and b6 in ~c"wW" and + b7 in ~c"nN", do: :unknown + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"nN" and b4 in ~c"eE" and b5 in ~c"sS" and b6 in ~c"tT", do: :unnest + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"uU" and b2 in ~c"pP" and b3 in ~c"dD" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"eE", do: :update + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"pP" and b3 in ~c"pP" and b4 in ~c"eE" and b5 in ~c"rR", do: :upper + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"rR", do: :user + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"iI" and b4 in ~c"nN" and b5 in ~c"gG", do: :using + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"eE", do: :value + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"eE" and b6 in ~c"sS", do: :values + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"oO" and b8 in ~c"fF", do: :value_of + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"_" and b5 in ~c"pP" and b6 in ~c"oO" and + b7 in ~c"pP", do: :var_pop + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"_" and b5 in ~c"sS" and b6 in ~c"aA" and + b7 in ~c"mM" and b8 in ~c"pP", do: :var_samp + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"bB" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"aA" and b8 in ~c"rR" and b9 in ~c"yY", do: :varbinary + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"cC" and b5 in ~c"hH" and b6 in ~c"aA" and + b7 in ~c"rR", do: :varchar + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"vV" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"yY" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :varying + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"vV" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"sS" and b5 in ~c"iI" and b6 in ~c"oO" and + b7 in ~c"nN" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"gG", do: :versioning + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"wW" and b2 in ~c"hH" and b3 in ~c"eE" and b4 in ~c"nN", do: :when + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"wW" and b2 in ~c"hH" and b3 in ~c"eE" and b4 in ~c"nN" and b5 in ~c"eE" and b6 in ~c"vV" and + b7 in ~c"eE" and b8 in ~c"rR", do: :whenever + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"wW" and b2 in ~c"hH" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"eE", do: :where + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"wW" and b2 in ~c"iI" and b3 in ~c"dD" and b4 in ~c"tT" and b5 in ~c"hH" and b6 in ~c"_" and + b7 in ~c"bB" and b8 in ~c"uU" and b9 in ~c"cC" and b10 in ~c"kK" and b11 in ~c"eE" and + b12 in ~c"tT", do: :width_bucket + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"wW" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"dD" and b5 in ~c"oO" and b6 in ~c"wW", do: :window + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"wW" and b2 in ~c"iI" and b3 in ~c"tT" and b4 in ~c"hH", do: :with + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"wW" and b2 in ~c"iI" and b3 in ~c"tT" and b4 in ~c"hH" and b5 in ~c"iI" and b6 in ~c"nN", do: :within + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"wW" and b2 in ~c"iI" and b3 in ~c"tT" and b4 in ~c"hH" and b5 in ~c"oO" and b6 in ~c"uU" and + b7 in ~c"tT", do: :without + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"yY" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"rR", do: :year + + def ident(:ident, [b1]) when b1 in ~c"aA", do: :a + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"aA" and b2 in ~c"bB" and b3 in ~c"sS" and b4 in ~c"oO" and b5 in ~c"lL" and b6 in ~c"uU" and + b7 in ~c"tT" and b8 in ~c"eE", do: :absolute + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"aA" and b2 in ~c"cC" and b3 in ~c"tT" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"nN", do: :action + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"dD" and b3 in ~c"aA", do: :ada + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"dD" and b3 in ~c"dD", do: :add + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"aA" and b2 in ~c"dD" and b3 in ~c"mM" and b4 in ~c"iI" and b5 in ~c"nN", do: :admin + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"aA" and b2 in ~c"fF" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"rR", do: :after + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"aA" and b2 in ~c"lL" and b3 in ~c"wW" and b4 in ~c"aA" and b5 in ~c"yY" and b6 in ~c"sS", do: :always + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"cC", do: :asc + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"sS" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :assertion + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"aA" and b2 in ~c"sS" and b3 in ~c"sS" and b4 in ~c"iI" and b5 in ~c"gG" and b6 in ~c"nN" and + b7 in ~c"mM" and b8 in ~c"eE" and b9 in ~c"nN" and b10 in ~c"tT", do: :assignment + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"aA" and b2 in ~c"tT" and b3 in ~c"tT" and b4 in ~c"rR" and b5 in ~c"iI" and b6 in ~c"bB" and + b7 in ~c"uU" and b8 in ~c"tT" and b9 in ~c"eE", do: :attribute + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"aA" and b2 in ~c"tT" and b3 in ~c"tT" and b4 in ~c"rR" and b5 in ~c"iI" and b6 in ~c"bB" and + b7 in ~c"uU" and b8 in ~c"tT" and b9 in ~c"eE" and b10 in ~c"sS", do: :attributes + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"oO" and b5 in ~c"rR" and b6 in ~c"eE", do: :before + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"bB" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"nN" and b5 in ~c"oO" and b6 in ~c"uU" and + b7 in ~c"lL" and b8 in ~c"lL" and b9 in ~c"iI", do: :bernoulli + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"bB" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"aA" and b5 in ~c"dD" and b6 in ~c"tT" and + b7 in ~c"hH", do: :breadth + + def ident(:ident, [b1]) when b1 in ~c"cC", do: :c + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"aA" and b6 in ~c"dD" and + b7 in ~c"eE", do: :cascade + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"aA" and b5 in ~c"lL" and b6 in ~c"oO" and + b7 in ~c"gG", do: :catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"aA" and b5 in ~c"lL" and b6 in ~c"oO" and + b7 in ~c"gG" and b8 in ~c"_" and b9 in ~c"nN" and b10 in ~c"aA" and b11 in ~c"mM" and + b12 in ~c"eE", do: :catalog_name + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"iI" and b5 in ~c"nN", do: :chain + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"gG", do: :chaining + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"eE" and b13 in ~c"tT" and b14 in ~c"_" and b15 in ~c"cC" and b16 in ~c"aA" and + b17 in ~c"tT" and b18 in ~c"aA" and b19 in ~c"lL" and b20 in ~c"oO" and b21 in ~c"gG", do: :character_set_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"eE" and b13 in ~c"tT" and b14 in ~c"_" and b15 in ~c"nN" and b16 in ~c"aA" and + b17 in ~c"mM" and b18 in ~c"eE", do: :character_set_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"eE" and b13 in ~c"tT" and b14 in ~c"_" and b15 in ~c"sS" and b16 in ~c"cC" and + b17 in ~c"hH" and b18 in ~c"eE" and b19 in ~c"mM" and b20 in ~c"aA", do: :character_set_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"iI" and b11 in ~c"sS" and + b12 in ~c"tT" and b13 in ~c"iI" and b14 in ~c"cC" and b15 in ~c"sS", do: :characteristics + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"cC" and b2 in ~c"hH" and b3 in ~c"aA" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"sS", do: :characters + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"cC" and b2 in ~c"lL" and b3 in ~c"aA" and b4 in ~c"sS" and b5 in ~c"sS" and b6 in ~c"_" and + b7 in ~c"oO" and b8 in ~c"rR" and b9 in ~c"iI" and b10 in ~c"gG" and b11 in ~c"iI" and + b12 in ~c"nN", do: :class_origin + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"bB" and b4 in ~c"oO" and b5 in ~c"lL", do: :cobol + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :collation + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"_" and b11 in ~c"cC" and + b12 in ~c"aA" and b13 in ~c"tT" and b14 in ~c"aA" and b15 in ~c"lL" and b16 in ~c"oO" and + b17 in ~c"gG", do: :collation_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"_" and b11 in ~c"nN" and + b12 in ~c"aA" and b13 in ~c"mM" and b14 in ~c"eE", do: :collation_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"cC" and b13 in ~c"hH" and b14 in ~c"eE" and b15 in ~c"mM" and b16 in ~c"aA", do: :collation_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"mM" and b6 in ~c"nN" and + b7 in ~c"sS", do: :columns + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"uU" and b5 in ~c"mM" and b6 in ~c"nN" and + b7 in ~c"_" and b8 in ~c"nN" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"eE", do: :column_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"nN" and + b7 in ~c"dD" and b8 in ~c"_" and b9 in ~c"fF" and b10 in ~c"uU" and b11 in ~c"nN" and + b12 in ~c"cC" and b13 in ~c"tT" and b14 in ~c"iI" and b15 in ~c"oO" and b16 in ~c"nN", do: :command_function + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"nN" and + b7 in ~c"dD" and b8 in ~c"_" and b9 in ~c"fF" and b10 in ~c"uU" and b11 in ~c"nN" and + b12 in ~c"cC" and b13 in ~c"tT" and b14 in ~c"iI" and b15 in ~c"oO" and b16 in ~c"nN" and + b17 in ~c"_" and b18 in ~c"cC" and b19 in ~c"oO" and b20 in ~c"dD" and b21 in ~c"eE", do: :command_function_code + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"mM" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"dD", do: :committed + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"dD" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"aA" and b11 in ~c"lL", do: :conditional + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"dD" and b5 in ~c"iI" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN" and b10 in ~c"_" and b11 in ~c"nN" and + b12 in ~c"uU" and b13 in ~c"mM" and b14 in ~c"bB" and b15 in ~c"eE" and b16 in ~c"rR", do: :condition_number + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"nN" and b5 in ~c"eE" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"oO" and b10 in ~c"nN", do: :connection + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"nN" and b5 in ~c"eE" and b6 in ~c"cC" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"oO" and b10 in ~c"nN" and b11 in ~c"_" and + b12 in ~c"nN" and b13 in ~c"aA" and b14 in ~c"mM" and b15 in ~c"eE", do: :connection_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"tT" and b11 in ~c"_" and + b12 in ~c"cC" and b13 in ~c"aA" and b14 in ~c"tT" and b15 in ~c"aA" and b16 in ~c"lL" and + b17 in ~c"oO" and b18 in ~c"gG", do: :constraint_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"tT" and b11 in ~c"_" and + b12 in ~c"nN" and b13 in ~c"aA" and b14 in ~c"mM" and b15 in ~c"eE", do: :constraint_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"tT" and b11 in ~c"_" and + b12 in ~c"sS" and b13 in ~c"cC" and b14 in ~c"hH" and b15 in ~c"eE" and b16 in ~c"mM" and + b17 in ~c"aA", do: :constraint_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"tT" and b11 in ~c"sS", do: :constraints + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"sS" and b5 in ~c"tT" and b6 in ~c"rR" and + b7 in ~c"uU" and b8 in ~c"cC" and b9 in ~c"tT" and b10 in ~c"oO" and b11 in ~c"rR", do: :constructor + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"uU" and b8 in ~c"eE", do: :continue + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"oO" and b3 in ~c"pP" and b4 in ~c"aA" and b5 in ~c"rR" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN", do: :copartition + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"cC" and b2 in ~c"uU" and b3 in ~c"rR" and b4 in ~c"sS" and b5 in ~c"oO" and b6 in ~c"rR" and + b7 in ~c"_" and b8 in ~c"nN" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"eE", do: :cursor_name + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"dD" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"aA", do: :data + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22]) when b1 in ~c"dD" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"mM" and b8 in ~c"eE" and b9 in ~c"_" and b10 in ~c"iI" and b11 in ~c"nN" and + b12 in ~c"tT" and b13 in ~c"eE" and b14 in ~c"rR" and b15 in ~c"vV" and b16 in ~c"aA" and + b17 in ~c"lL" and b18 in ~c"_" and b19 in ~c"cC" and b20 in ~c"oO" and b21 in ~c"dD" and + b22 in ~c"eE", do: :datetime_interval_code + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25,b26,b27]) when b1 in ~c"dD" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"mM" and b8 in ~c"eE" and b9 in ~c"_" and b10 in ~c"iI" and b11 in ~c"nN" and + b12 in ~c"tT" and b13 in ~c"eE" and b14 in ~c"rR" and b15 in ~c"vV" and b16 in ~c"aA" and + b17 in ~c"lL" and b18 in ~c"_" and b19 in ~c"pP" and b20 in ~c"rR" and b21 in ~c"eE" and + b22 in ~c"cC" and b23 in ~c"iI" and b24 in ~c"sS" and b25 in ~c"iI" and b26 in ~c"oO" and + b27 in ~c"nN", do: :datetime_interval_precision + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"aA" and b5 in ~c"uU" and b6 in ~c"lL" and + b7 in ~c"tT" and b8 in ~c"sS", do: :defaults + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"bB" and b9 in ~c"lL" and b10 in ~c"eE", do: :deferrable + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"rR" and + b7 in ~c"eE" and b8 in ~c"dD", do: :deferred + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"eE" and + b7 in ~c"dD", do: :defined + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"fF" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"eE" and + b7 in ~c"rR", do: :definer + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"gG" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"eE", do: :degree + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"pP" and b4 in ~c"tT" and b5 in ~c"hH", do: :depth + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"vV" and b6 in ~c"eE" and + b7 in ~c"dD", do: :derived + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"cC", do: :desc + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"dD" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"pP" and b8 in ~c"tT" and b9 in ~c"oO" and b10 in ~c"rR", do: :descriptor + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"dD" and b2 in ~c"iI" and b3 in ~c"aA" and b4 in ~c"gG" and b5 in ~c"nN" and b6 in ~c"oO" and + b7 in ~c"sS" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"cC" and b11 in ~c"sS", do: :diagnostics + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"dD" and b2 in ~c"iI" and b3 in ~c"sS" and b4 in ~c"pP" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"cC" and b8 in ~c"hH", do: :dispatch + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"dD" and b2 in ~c"oO" and b3 in ~c"mM" and b4 in ~c"aA" and b5 in ~c"iI" and b6 in ~c"nN", do: :domain + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16]) when b1 in ~c"dD" and b2 in ~c"yY" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"iI" and + b7 in ~c"cC" and b8 in ~c"_" and b9 in ~c"fF" and b10 in ~c"uU" and b11 in ~c"nN" and + b12 in ~c"cC" and b13 in ~c"tT" and b14 in ~c"iI" and b15 in ~c"oO" and b16 in ~c"nN", do: :dynamic_function + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21]) when b1 in ~c"dD" and b2 in ~c"yY" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"iI" and + b7 in ~c"cC" and b8 in ~c"_" and b9 in ~c"fF" and b10 in ~c"uU" and b11 in ~c"nN" and + b12 in ~c"cC" and b13 in ~c"tT" and b14 in ~c"iI" and b15 in ~c"oO" and b16 in ~c"nN" and + b17 in ~c"_" and b18 in ~c"cC" and b19 in ~c"oO" and b20 in ~c"dD" and b21 in ~c"eE", do: :dynamic_function_code + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"cC" and b4 in ~c"oO" and b5 in ~c"dD" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"gG", do: :encoding + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"eE" and b2 in ~c"nN" and b3 in ~c"fF" and b4 in ~c"oO" and b5 in ~c"rR" and b6 in ~c"cC" and + b7 in ~c"eE" and b8 in ~c"dD", do: :enforced + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"eE" and b2 in ~c"rR" and b3 in ~c"rR" and b4 in ~c"oO" and b5 in ~c"rR", do: :error + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"cC" and b4 in ~c"lL" and b5 in ~c"uU" and b6 in ~c"dD" and + b7 in ~c"eE", do: :exclude + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"cC" and b4 in ~c"lL" and b5 in ~c"uU" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :excluding + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"eE" and b2 in ~c"xX" and b3 in ~c"pP" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"sS" and + b7 in ~c"sS" and b8 in ~c"iI" and b9 in ~c"oO" and b10 in ~c"nN", do: :expression + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"lL", do: :final + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"fF" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"iI" and b5 in ~c"sS" and b6 in ~c"hH", do: :finish + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"iI" and b3 in ~c"rR" and b4 in ~c"sS" and b5 in ~c"tT", do: :first + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"fF" and b2 in ~c"lL" and b3 in ~c"aA" and b4 in ~c"gG", do: :flag + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"oO" and b6 in ~c"wW" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :following + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"tT", do: :format + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"tT" and b5 in ~c"rR" and b6 in ~c"aA" and + b7 in ~c"nN", do: :fortran + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"nN" and b5 in ~c"dD", do: :found + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"fF" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"fF" and b5 in ~c"iI" and b6 in ~c"lL" and + b7 in ~c"lL", do: :fulfill + + def ident(:ident, [b1]) when b1 in ~c"gG", do: :g + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"gG" and b2 in ~c"eE" and b3 in ~c"nN" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"aA" and + b7 in ~c"lL", do: :general + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"gG" and b2 in ~c"eE" and b3 in ~c"nN" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"aA" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"dD", do: :generated + + def ident(:ident, [b1,b2]) when b1 in ~c"gG" and b2 in ~c"oO", do: :go + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"gG" and b2 in ~c"oO" and b3 in ~c"tT" and b4 in ~c"oO", do: :goto + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"gG" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"tT" and b6 in ~c"eE" and + b7 in ~c"dD", do: :granted + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"hH" and b2 in ~c"iI" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"cC" and b8 in ~c"hH" and b9 in ~c"yY", do: :hierarchy + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"iI" and b2 in ~c"gG" and b3 in ~c"nN" and b4 in ~c"oO" and b5 in ~c"rR" and b6 in ~c"eE", do: :ignore + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"mM" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"dD" and b6 in ~c"iI" and + b7 in ~c"aA" and b8 in ~c"tT" and b9 in ~c"eE", do: :immediate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"iI" and b2 in ~c"mM" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"dD" and b6 in ~c"iI" and + b7 in ~c"aA" and b8 in ~c"tT" and b9 in ~c"eE" and b10 in ~c"lL" and b11 in ~c"yY", do: :immediately + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"iI" and b2 in ~c"mM" and b3 in ~c"pP" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"mM" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"tT" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"iI" and b13 in ~c"oO" and b14 in ~c"nN", do: :implementation + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"cC" and b4 in ~c"lL" and b5 in ~c"uU" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :including + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"cC" and b4 in ~c"rR" and b5 in ~c"eE" and b6 in ~c"mM" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"tT", do: :increment + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"iI" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"aA" and + b7 in ~c"lL" and b8 in ~c"lL" and b9 in ~c"yY", do: :initially + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"pP" and b4 in ~c"uU" and b5 in ~c"tT", do: :input + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"aA" and b6 in ~c"nN" and + b7 in ~c"cC" and b8 in ~c"eE", do: :instance + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"aA" and b6 in ~c"nN" and + b7 in ~c"tT" and b8 in ~c"iI" and b9 in ~c"aA" and b10 in ~c"bB" and b11 in ~c"lL" and + b12 in ~c"eE", do: :instantiable + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"aA" and + b7 in ~c"dD", do: :instead + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"iI" and b2 in ~c"nN" and b3 in ~c"vV" and b4 in ~c"oO" and b5 in ~c"kK" and b6 in ~c"eE" and + b7 in ~c"rR", do: :invoker + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"iI" and b2 in ~c"sS" and b3 in ~c"oO" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"oO" and b9 in ~c"nN", do: :isolation + + def ident(:ident, [b1]) when b1 in ~c"kK", do: :k + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"kK" and b2 in ~c"eE" and b3 in ~c"eE" and b4 in ~c"pP", do: :keep + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"kK" and b2 in ~c"eE" and b3 in ~c"yY", do: :key + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"kK" and b2 in ~c"eE" and b3 in ~c"yY" and b4 in ~c"sS", do: :keys + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"kK" and b2 in ~c"eE" and b3 in ~c"yY" and b4 in ~c"_" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"mM" and b8 in ~c"bB" and b9 in ~c"eE" and b10 in ~c"rR", do: :key_member + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"kK" and b2 in ~c"eE" and b3 in ~c"yY" and b4 in ~c"_" and b5 in ~c"tT" and b6 in ~c"yY" and + b7 in ~c"pP" and b8 in ~c"eE", do: :key_type + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"lL" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"tT", do: :last + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"nN" and b4 in ~c"gG" and b5 in ~c"tT" and b6 in ~c"hH", do: :length + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"eE" and b3 in ~c"vV" and b4 in ~c"eE" and b5 in ~c"lL", do: :level + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"lL" and b2 in ~c"oO" and b3 in ~c"cC" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"oO" and + b7 in ~c"rR", do: :locator + + def ident(:ident, [b1]) when b1 in ~c"mM", do: :m + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"pP", do: :map + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"cC" and b5 in ~c"hH" and b6 in ~c"eE" and + b7 in ~c"dD", do: :matched + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"mM" and b2 in ~c"aA" and b3 in ~c"xX" and b4 in ~c"vV" and b5 in ~c"aA" and b6 in ~c"lL" and + b7 in ~c"uU" and b8 in ~c"eE", do: :maxvalue + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"sS" and b5 in ~c"uU" and b6 in ~c"rR" and + b7 in ~c"eE" and b8 in ~c"sS", do: :measures + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"aA" and b6 in ~c"gG" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"lL" and b10 in ~c"eE" and b11 in ~c"nN" and + b12 in ~c"gG" and b13 in ~c"tT" and b14 in ~c"hH", do: :message_length + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"aA" and b6 in ~c"gG" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"oO" and b10 in ~c"cC" and b11 in ~c"tT" and + b12 in ~c"eE" and b13 in ~c"tT" and b14 in ~c"_" and b15 in ~c"lL" and b16 in ~c"eE" and + b17 in ~c"nN" and b18 in ~c"gG" and b19 in ~c"tT" and b20 in ~c"hH", do: :message_octet_length + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"mM" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"aA" and b6 in ~c"gG" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"tT" and b10 in ~c"eE" and b11 in ~c"xX" and + b12 in ~c"tT", do: :message_text + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"mM" and b2 in ~c"iI" and b3 in ~c"nN" and b4 in ~c"vV" and b5 in ~c"aA" and b6 in ~c"lL" and + b7 in ~c"uU" and b8 in ~c"eE", do: :minvalue + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"mM" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"eE", do: :more + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"mM" and b2 in ~c"uU" and b3 in ~c"mM" and b4 in ~c"pP" and b5 in ~c"sS", do: :mumps + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"aA" and b3 in ~c"mM" and b4 in ~c"eE", do: :name + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"nN" and b2 in ~c"aA" and b3 in ~c"mM" and b4 in ~c"eE" and b5 in ~c"sS", do: :names + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"nN" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"dD", do: :nested + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"nN" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :nesting + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"eE" and b3 in ~c"xX" and b4 in ~c"tT", do: :next + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"nN" and b2 in ~c"fF" and b3 in ~c"cC", do: :nfc + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"nN" and b2 in ~c"fF" and b3 in ~c"dD", do: :nfd + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"fF" and b3 in ~c"kK" and b4 in ~c"cC", do: :nfkc + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"nN" and b2 in ~c"fF" and b3 in ~c"kK" and b4 in ~c"dD", do: :nfkd + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"nN" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"mM" and b5 in ~c"aA" and b6 in ~c"lL" and + b7 in ~c"iI" and b8 in ~c"zZ" and b9 in ~c"eE" and b10 in ~c"dD", do: :normalized + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"_" and b6 in ~c"oO" and + b7 in ~c"rR" and b8 in ~c"dD" and b9 in ~c"eE" and b10 in ~c"rR" and b11 in ~c"iI" and + b12 in ~c"nN" and b13 in ~c"gG", do: :null_ordering + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"bB" and + b7 in ~c"lL" and b8 in ~c"eE", do: :nullable + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"lL" and b4 in ~c"lL" and b5 in ~c"sS", do: :nulls + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"nN" and b2 in ~c"uU" and b3 in ~c"mM" and b4 in ~c"bB" and b5 in ~c"eE" and b6 in ~c"rR", do: :number + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"bB" and b3 in ~c"jJ" and b4 in ~c"eE" and b5 in ~c"cC" and b6 in ~c"tT", do: :object + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"oO" and b2 in ~c"cC" and b3 in ~c"cC" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"rR" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"cC" and b10 in ~c"eE", do: :occurrence + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"cC" and b3 in ~c"tT" and b4 in ~c"eE" and b5 in ~c"tT" and b6 in ~c"sS", do: :octets + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"pP" and b3 in ~c"tT" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"nN", do: :option + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"oO" and b2 in ~c"pP" and b3 in ~c"tT" and b4 in ~c"iI" and b5 in ~c"oO" and b6 in ~c"nN" and + b7 in ~c"sS", do: :options + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"oO" and b2 in ~c"rR" and b3 in ~c"dD" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"nN" and b8 in ~c"gG", do: :ordering + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"oO" and b2 in ~c"rR" and b3 in ~c"dD" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"aA" and + b7 in ~c"lL" and b8 in ~c"iI" and b9 in ~c"tT" and b10 in ~c"yY", do: :ordinality + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"tT" and b3 in ~c"hH" and b4 in ~c"eE" and b5 in ~c"rR" and b6 in ~c"sS", do: :others + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"oO" and b2 in ~c"uU" and b3 in ~c"tT" and b4 in ~c"pP" and b5 in ~c"uU" and b6 in ~c"tT", do: :output + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"oO" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"fF" and b6 in ~c"lL" and + b7 in ~c"oO" and b8 in ~c"wW", do: :overflow + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"oO" and b2 in ~c"vV" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"dD" and b8 in ~c"iI" and b9 in ~c"nN" and b10 in ~c"gG", do: :overriding + + def ident(:ident, [b1]) when b1 in ~c"pP", do: :p + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"dD", do: :pad + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"mM" and + b12 in ~c"oO" and b13 in ~c"dD" and b14 in ~c"eE", do: :parameter_mode + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"nN" and + b12 in ~c"aA" and b13 in ~c"mM" and b14 in ~c"eE", do: :parameter_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25,b26]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"oO" and + b12 in ~c"rR" and b13 in ~c"dD" and b14 in ~c"iI" and b15 in ~c"nN" and b16 in ~c"aA" and + b17 in ~c"lL" and b18 in ~c"_" and b19 in ~c"pP" and b20 in ~c"oO" and b21 in ~c"sS" and + b22 in ~c"iI" and b23 in ~c"tT" and b24 in ~c"iI" and b25 in ~c"oO" and b26 in ~c"nN", do: :parameter_ordinal_position + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25,b26]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"pP" and b13 in ~c"eE" and b14 in ~c"cC" and b15 in ~c"iI" and b16 in ~c"fF" and + b17 in ~c"iI" and b18 in ~c"cC" and b19 in ~c"_" and b20 in ~c"cC" and b21 in ~c"aA" and + b22 in ~c"tT" and b23 in ~c"aA" and b24 in ~c"lL" and b25 in ~c"oO" and b26 in ~c"gG", do: :parameter_specific_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"pP" and b13 in ~c"eE" and b14 in ~c"cC" and b15 in ~c"iI" and b16 in ~c"fF" and + b17 in ~c"iI" and b18 in ~c"cC" and b19 in ~c"_" and b20 in ~c"nN" and b21 in ~c"aA" and + b22 in ~c"mM" and b23 in ~c"eE", do: :parameter_specific_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"tT" and b8 in ~c"eE" and b9 in ~c"rR" and b10 in ~c"_" and b11 in ~c"sS" and + b12 in ~c"pP" and b13 in ~c"eE" and b14 in ~c"cC" and b15 in ~c"iI" and b16 in ~c"fF" and + b17 in ~c"iI" and b18 in ~c"cC" and b19 in ~c"_" and b20 in ~c"sS" and b21 in ~c"cC" and + b22 in ~c"hH" and b23 in ~c"eE" and b24 in ~c"mM" and b25 in ~c"aA", do: :parameter_specific_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"rR" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"aA" and + b7 in ~c"lL", do: :partial + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"cC" and b5 in ~c"aA" and b6 in ~c"lL", do: :pascal + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"sS", do: :pass + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :passing + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"sS" and b4 in ~c"tT", do: :past + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"aA" and b3 in ~c"tT" and b4 in ~c"hH", do: :path + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"mM" and b5 in ~c"uU" and b6 in ~c"tT" and + b7 in ~c"eE", do: :permute + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"iI" and b3 in ~c"pP" and b4 in ~c"eE", do: :pipe + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"lL" and b3 in ~c"aA" and b4 in ~c"cC" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"gG", do: :placing + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"lL" and b3 in ~c"aA" and b4 in ~c"nN", do: :plan + + def ident(:ident, [b1,b2,b3]) when b1 in ~c"pP" and b2 in ~c"lL" and b3 in ~c"iI", do: :pli + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"eE" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :preceding + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"sS" and b5 in ~c"eE" and b6 in ~c"rR" and + b7 in ~c"vV" and b8 in ~c"eE", do: :preserve + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"eE" and b4 in ~c"vV", do: :prev + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"oO" and b5 in ~c"rR", do: :prior + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"vV" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"eE", do: :private + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"vV" and b5 in ~c"iI" and b6 in ~c"lL" and + b7 in ~c"eE" and b8 in ~c"gG" and b9 in ~c"eE" and b10 in ~c"sS", do: :privileges + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"pP" and b2 in ~c"rR" and b3 in ~c"uU" and b4 in ~c"nN" and b5 in ~c"eE", do: :prune + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"pP" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"lL" and b5 in ~c"iI" and b6 in ~c"cC", do: :public + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"qQ" and b2 in ~c"uU" and b3 in ~c"oO" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"sS", do: :quotes + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"aA" and b4 in ~c"dD", do: :read + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"lL" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"iI" and + b7 in ~c"vV" and b8 in ~c"eE", do: :relative + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"pP" and b4 in ~c"eE" and b5 in ~c"aA" and b6 in ~c"tT" and + b7 in ~c"aA" and b8 in ~c"bB" and b9 in ~c"lL" and b10 in ~c"eE", do: :repeatable + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"pP" and b5 in ~c"eE" and b6 in ~c"cC" and + b7 in ~c"tT", do: :respect + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"tT", do: :restart + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"tT" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"cC" and b8 in ~c"tT", do: :restrict + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"dD" and b9 in ~c"_" and b10 in ~c"cC" and b11 in ~c"aA" and + b12 in ~c"rR" and b13 in ~c"dD" and b14 in ~c"iI" and b15 in ~c"nN" and b16 in ~c"aA" and + b17 in ~c"lL" and b18 in ~c"iI" and b19 in ~c"tT" and b20 in ~c"yY", do: :returned_cardinality + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"dD" and b9 in ~c"_" and b10 in ~c"lL" and b11 in ~c"eE" and + b12 in ~c"nN" and b13 in ~c"gG" and b14 in ~c"tT" and b15 in ~c"hH", do: :returned_length + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"dD" and b9 in ~c"_" and b10 in ~c"oO" and b11 in ~c"cC" and + b12 in ~c"tT" and b13 in ~c"eE" and b14 in ~c"tT" and b15 in ~c"_" and b16 in ~c"lL" and + b17 in ~c"eE" and b18 in ~c"nN" and b19 in ~c"gG" and b20 in ~c"tT" and b21 in ~c"hH", do: :returned_octet_length + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"dD" and b9 in ~c"_" and b10 in ~c"sS" and b11 in ~c"qQ" and + b12 in ~c"lL" and b13 in ~c"sS" and b14 in ~c"tT" and b15 in ~c"aA" and b16 in ~c"tT" and + b17 in ~c"eE", do: :returned_sqlstate + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"rR" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"nN" and + b7 in ~c"iI" and b8 in ~c"nN" and b9 in ~c"gG", do: :returning + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"lL" and b4 in ~c"eE", do: :role + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"eE", do: :routine + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"cC" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"aA" and b13 in ~c"lL" and b14 in ~c"oO" and b15 in ~c"gG", do: :routine_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"nN" and b10 in ~c"aA" and b11 in ~c"mM" and + b12 in ~c"eE", do: :routine_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"nN" and + b7 in ~c"eE" and b8 in ~c"_" and b9 in ~c"sS" and b10 in ~c"cC" and b11 in ~c"hH" and + b12 in ~c"eE" and b13 in ~c"mM" and b14 in ~c"aA", do: :routine_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"rR" and b2 in ~c"oO" and b3 in ~c"wW" and b4 in ~c"_" and b5 in ~c"cC" and b6 in ~c"oO" and + b7 in ~c"uU" and b8 in ~c"nN" and b9 in ~c"tT", do: :row_count + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"aA" and b4 in ~c"lL" and b5 in ~c"aA" and b6 in ~c"rR", do: :scalar + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"aA" and b4 in ~c"lL" and b5 in ~c"eE", do: :scale + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"hH" and b4 in ~c"eE" and b5 in ~c"mM" and b6 in ~c"aA", do: :schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"hH" and b4 in ~c"eE" and b5 in ~c"mM" and b6 in ~c"aA" and + b7 in ~c"_" and b8 in ~c"nN" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"eE", do: :schema_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"oO" and b4 in ~c"pP" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"cC" and b8 in ~c"aA" and b9 in ~c"tT" and b10 in ~c"aA" and b11 in ~c"lL" and + b12 in ~c"oO" and b13 in ~c"gG", do: :scope_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"oO" and b4 in ~c"pP" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"nN" and b8 in ~c"aA" and b9 in ~c"mM" and b10 in ~c"eE", do: :scope_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"sS" and b2 in ~c"cC" and b3 in ~c"oO" and b4 in ~c"pP" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"sS" and b8 in ~c"cC" and b9 in ~c"hH" and b10 in ~c"eE" and b11 in ~c"mM" and + b12 in ~c"aA", do: :scope_schema + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"tT" and b5 in ~c"iI" and b6 in ~c"oO" and + b7 in ~c"nN", do: :section + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"cC" and b4 in ~c"uU" and b5 in ~c"rR" and b6 in ~c"iI" and + b7 in ~c"tT" and b8 in ~c"yY", do: :security + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"lL" and b4 in ~c"fF", do: :self + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"mM" and b4 in ~c"aA" and b5 in ~c"nN" and b6 in ~c"tT" and + b7 in ~c"iI" and b8 in ~c"cC" and b9 in ~c"sS", do: :semantics + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"qQ" and b4 in ~c"uU" and b5 in ~c"eE" and b6 in ~c"nN" and + b7 in ~c"cC" and b8 in ~c"eE", do: :sequence + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"aA" and b6 in ~c"lL" and + b7 in ~c"iI" and b8 in ~c"zZ" and b9 in ~c"aA" and b10 in ~c"bB" and b11 in ~c"lL" and + b12 in ~c"eE", do: :serializable + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"rR" and b4 in ~c"vV" and b5 in ~c"eE" and b6 in ~c"rR" and + b7 in ~c"_" and b8 in ~c"nN" and b9 in ~c"aA" and b10 in ~c"mM" and b11 in ~c"eE", do: :server_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"sS" and b4 in ~c"sS" and b5 in ~c"iI" and b6 in ~c"oO" and + b7 in ~c"nN", do: :session + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"eE" and b3 in ~c"tT" and b4 in ~c"sS", do: :sets + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"pP" and b5 in ~c"lL" and b6 in ~c"eE", do: :simple + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"sS" and b2 in ~c"iI" and b3 in ~c"zZ" and b4 in ~c"eE", do: :size + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"sS" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"tT" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"rR" and b9 in ~c"eE" and b10 in ~c"cC" and b11 in ~c"tT" and + b12 in ~c"iI" and b13 in ~c"oO" and b14 in ~c"nN", do: :sort_direction + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"oO" and b3 in ~c"uU" and b4 in ~c"rR" and b5 in ~c"cC" and b6 in ~c"eE", do: :source + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"pP" and b3 in ~c"aA" and b4 in ~c"cC" and b5 in ~c"eE", do: :space + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"sS" and b2 in ~c"pP" and b3 in ~c"eE" and b4 in ~c"cC" and b5 in ~c"iI" and b6 in ~c"fF" and + b7 in ~c"iI" and b8 in ~c"cC" and b9 in ~c"_" and b10 in ~c"nN" and b11 in ~c"aA" and + b12 in ~c"mM" and b13 in ~c"eE", do: :specific_name + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"aA" and b4 in ~c"tT" and b5 in ~c"eE", do: :state + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"aA" and b4 in ~c"tT" and b5 in ~c"eE" and b6 in ~c"mM" and + b7 in ~c"eE" and b8 in ~c"nN" and b9 in ~c"tT", do: :statement + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"rR" and b4 in ~c"iI" and b5 in ~c"nN" and b6 in ~c"gG", do: :string + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"rR" and b4 in ~c"uU" and b5 in ~c"cC" and b6 in ~c"tT" and + b7 in ~c"uU" and b8 in ~c"rR" and b9 in ~c"eE", do: :structure + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"sS" and b2 in ~c"tT" and b3 in ~c"yY" and b4 in ~c"lL" and b5 in ~c"eE", do: :style + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"sS" and b2 in ~c"uU" and b3 in ~c"bB" and b4 in ~c"cC" and b5 in ~c"lL" and b6 in ~c"aA" and + b7 in ~c"sS" and b8 in ~c"sS" and b9 in ~c"_" and b10 in ~c"oO" and b11 in ~c"rR" and + b12 in ~c"iI" and b13 in ~c"gG" and b14 in ~c"iI" and b15 in ~c"nN", do: :subclass_origin + + def ident(:ident, [b1]) when b1 in ~c"tT", do: :t + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"tT" and b2 in ~c"aA" and b3 in ~c"bB" and b4 in ~c"lL" and b5 in ~c"eE" and b6 in ~c"_" and + b7 in ~c"nN" and b8 in ~c"aA" and b9 in ~c"mM" and b10 in ~c"eE", do: :table_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"tT" and b2 in ~c"eE" and b3 in ~c"mM" and b4 in ~c"pP" and b5 in ~c"oO" and b6 in ~c"rR" and + b7 in ~c"aA" and b8 in ~c"rR" and b9 in ~c"yY", do: :temporary + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"tT" and b2 in ~c"hH" and b3 in ~c"rR" and b4 in ~c"oO" and b5 in ~c"uU" and b6 in ~c"gG" and + b7 in ~c"hH", do: :through + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"iI" and b3 in ~c"eE" and b4 in ~c"sS", do: :ties + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"tT" and b2 in ~c"oO" and b3 in ~c"pP" and b4 in ~c"_" and b5 in ~c"lL" and b6 in ~c"eE" and + b7 in ~c"vV" and b8 in ~c"eE" and b9 in ~c"lL" and b10 in ~c"_" and b11 in ~c"cC" and + b12 in ~c"oO" and b13 in ~c"uU" and b14 in ~c"nN" and b15 in ~c"tT", do: :top_level_count + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"aA" and + b7 in ~c"cC" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN", do: :transaction + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"aA" and + b7 in ~c"cC" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN" and + b12 in ~c"_" and b13 in ~c"aA" and b14 in ~c"cC" and b15 in ~c"tT" and b16 in ~c"iI" and + b17 in ~c"vV" and b18 in ~c"eE", do: :transaction_active + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"aA" and + b7 in ~c"cC" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN" and + b12 in ~c"sS" and b13 in ~c"_" and b14 in ~c"cC" and b15 in ~c"oO" and b16 in ~c"mM" and + b17 in ~c"mM" and b18 in ~c"iI" and b19 in ~c"tT" and b20 in ~c"tT" and b21 in ~c"eE" and + b22 in ~c"dD", do: :transactions_committed + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"aA" and + b7 in ~c"cC" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN" and + b12 in ~c"sS" and b13 in ~c"_" and b14 in ~c"rR" and b15 in ~c"oO" and b16 in ~c"lL" and + b17 in ~c"lL" and b18 in ~c"eE" and b19 in ~c"dD" and b20 in ~c"_" and b21 in ~c"bB" and + b22 in ~c"aA" and b23 in ~c"cC" and b24 in ~c"kK", do: :transactions_rolled_back + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"fF" and + b7 in ~c"oO" and b8 in ~c"rR" and b9 in ~c"mM", do: :transform + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"nN" and b5 in ~c"sS" and b6 in ~c"fF" and + b7 in ~c"oO" and b8 in ~c"rR" and b9 in ~c"mM" and b10 in ~c"sS", do: :transforms + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"gG" and b5 in ~c"gG" and b6 in ~c"eE" and + b7 in ~c"rR" and b8 in ~c"_" and b9 in ~c"cC" and b10 in ~c"aA" and b11 in ~c"tT" and + b12 in ~c"aA" and b13 in ~c"lL" and b14 in ~c"oO" and b15 in ~c"gG", do: :trigger_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"gG" and b5 in ~c"gG" and b6 in ~c"eE" and + b7 in ~c"rR" and b8 in ~c"_" and b9 in ~c"nN" and b10 in ~c"aA" and b11 in ~c"mM" and + b12 in ~c"eE", do: :trigger_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14]) when b1 in ~c"tT" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"gG" and b5 in ~c"gG" and b6 in ~c"eE" and + b7 in ~c"rR" and b8 in ~c"_" and b9 in ~c"sS" and b10 in ~c"cC" and b11 in ~c"hH" and + b12 in ~c"eE" and b13 in ~c"mM" and b14 in ~c"aA", do: :trigger_schema + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"tT" and b2 in ~c"yY" and b3 in ~c"pP" and b4 in ~c"eE", do: :type + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"bB" and b4 in ~c"oO" and b5 in ~c"uU" and b6 in ~c"nN" and + b7 in ~c"dD" and b8 in ~c"eE" and b9 in ~c"dD", do: :unbounded + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"cC" and b4 in ~c"oO" and b5 in ~c"mM" and b6 in ~c"mM" and + b7 in ~c"iI" and b8 in ~c"tT" and b9 in ~c"tT" and b10 in ~c"eE" and b11 in ~c"dD", do: :uncommitted + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"cC" and b4 in ~c"oO" and b5 in ~c"nN" and b6 in ~c"dD" and + b7 in ~c"iI" and b8 in ~c"tT" and b9 in ~c"iI" and b10 in ~c"oO" and b11 in ~c"nN" and + b12 in ~c"aA" and b13 in ~c"lL", do: :unconditional + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"dD" and b4 in ~c"eE" and b5 in ~c"rR", do: :under + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"mM" and b4 in ~c"aA" and b5 in ~c"tT" and b6 in ~c"cC" and + b7 in ~c"hH" and b8 in ~c"eE" and b9 in ~c"dD", do: :unmatched + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"uU" and b2 in ~c"nN" and b3 in ~c"nN" and b4 in ~c"aA" and b5 in ~c"mM" and b6 in ~c"eE" and + b7 in ~c"dD", do: :unnamed + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"aA" and b4 in ~c"gG" and b5 in ~c"eE", do: :usage + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24,b25]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"fF" and b9 in ~c"iI" and b10 in ~c"nN" and b11 in ~c"eE" and + b12 in ~c"dD" and b13 in ~c"_" and b14 in ~c"tT" and b15 in ~c"yY" and b16 in ~c"pP" and + b17 in ~c"eE" and b18 in ~c"_" and b19 in ~c"cC" and b20 in ~c"aA" and b21 in ~c"tT" and + b22 in ~c"aA" and b23 in ~c"lL" and b24 in ~c"oO" and b25 in ~c"gG", do: :user_defined_type_catalog + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"fF" and b9 in ~c"iI" and b10 in ~c"nN" and b11 in ~c"eE" and + b12 in ~c"dD" and b13 in ~c"_" and b14 in ~c"tT" and b15 in ~c"yY" and b16 in ~c"pP" and + b17 in ~c"eE" and b18 in ~c"_" and b19 in ~c"cC" and b20 in ~c"oO" and b21 in ~c"dD" and + b22 in ~c"eE", do: :user_defined_type_code + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"fF" and b9 in ~c"iI" and b10 in ~c"nN" and b11 in ~c"eE" and + b12 in ~c"dD" and b13 in ~c"_" and b14 in ~c"tT" and b15 in ~c"yY" and b16 in ~c"pP" and + b17 in ~c"eE" and b18 in ~c"_" and b19 in ~c"nN" and b20 in ~c"aA" and b21 in ~c"mM" and + b22 in ~c"eE", do: :user_defined_type_name + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24]) when b1 in ~c"uU" and b2 in ~c"sS" and b3 in ~c"eE" and b4 in ~c"rR" and b5 in ~c"_" and b6 in ~c"dD" and + b7 in ~c"eE" and b8 in ~c"fF" and b9 in ~c"iI" and b10 in ~c"nN" and b11 in ~c"eE" and + b12 in ~c"dD" and b13 in ~c"_" and b14 in ~c"tT" and b15 in ~c"yY" and b16 in ~c"pP" and + b17 in ~c"eE" and b18 in ~c"_" and b19 in ~c"sS" and b20 in ~c"cC" and b21 in ~c"hH" and + b22 in ~c"eE" and b23 in ~c"mM" and b24 in ~c"aA", do: :user_defined_type_schema + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"tT" and b3 in ~c"fF" and b4 in ~c"1" and b5 in ~c"6", do: :utf16 + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"uU" and b2 in ~c"tT" and b3 in ~c"fF" and b4 in ~c"3" and b5 in ~c"2", do: :utf32 + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"uU" and b2 in ~c"tT" and b3 in ~c"fF" and b4 in ~c"8", do: :utf8 + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"vV" and b2 in ~c"iI" and b3 in ~c"eE" and b4 in ~c"wW", do: :view + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"wW" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"kK", do: :work + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"wW" and b2 in ~c"rR" and b3 in ~c"aA" and b4 in ~c"pP" and b5 in ~c"pP" and b6 in ~c"eE" and + b7 in ~c"rR", do: :wrapper + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"wW" and b2 in ~c"rR" and b3 in ~c"iI" and b4 in ~c"tT" and b5 in ~c"eE", do: :write + + def ident(:ident, [b1,b2,b3,b4]) when b1 in ~c"zZ" and b2 in ~c"oO" and b3 in ~c"nN" and b4 in ~c"eE", do: :zone + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"lL" and b2 in ~c"iI" and b3 in ~c"mM" and b4 in ~c"iI" and b5 in ~c"tT", do: :limit + + def ident(:ident, [b1,b2,b3,b4,b5]) when b1 in ~c"iI" and b2 in ~c"lL" and b3 in ~c"iI" and b4 in ~c"kK" and b5 in ~c"eE", do: :ilike + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7,b8]) when b1 in ~c"bB" and b2 in ~c"aA" and b3 in ~c"cC" and b4 in ~c"kK" and b5 in ~c"wW" and b6 in ~c"aA" and + b7 in ~c"rR" and b8 in ~c"dD", do: :backward + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"fF" and b2 in ~c"oO" and b3 in ~c"rR" and b4 in ~c"wW" and b5 in ~c"aA" and b6 in ~c"rR" and + b7 in ~c"dD", do: :forward + + def ident(:ident, [b1,b2,b3,b4,b5,b6]) when b1 in ~c"iI" and b2 in ~c"sS" and b3 in ~c"nN" and b4 in ~c"uU" and b5 in ~c"lL" and b6 in ~c"lL", do: :isnull + + def ident(:ident, [b1,b2,b3,b4,b5,b6,b7]) when b1 in ~c"nN" and b2 in ~c"oO" and b3 in ~c"tT" and b4 in ~c"nN" and b5 in ~c"uU" and b6 in ~c"lL" and + b7 in ~c"lL", do: :notnull + + def ident(type, _), do: type +end diff --git a/lib/mix/tasks/sql.gen.parser.ex b/lib/mix/tasks/sql.gen.parser.ex new file mode 100644 index 0000000..90e69f4 --- /dev/null +++ b/lib/mix/tasks/sql.gen.parser.ex @@ -0,0 +1,579 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule Mix.Tasks.Sql.Gen.Parser do + use Mix.Task + import Mix.Generator + + @shortdoc "Generates a lexer and parser from the BNF rules" + @shortdoc since: "0.2.0" + + def run(_args) do + rules = SQL.BNF.parse() + space = Enum.map(rules[""], fn <> -> c end) + whitespace = Enum.map(rules[""], fn <> -> c end) + newline = Enum.map(rules[""], fn <> -> c end) + + keywords = String.split(rules[""], "|") ++ String.split(rules[""], "|") |> Enum.map(&String.trim/1) |> Enum.reject(&(&1 == "")) + keywords = keywords ++ ~w[LIMIT ILIKE BACKWARD FORWARD ISNULL NOTNULL] + create_file("lib/lexer.ex", lexer_template([mod: SQL.Lexer, keywords: keywords, space: space, whitespace: whitespace, newline: newline])) + create_file("lib/parser.ex", parser_template([mod: SQL.Parser, keywords: Enum.map(keywords, &String.to_atom(String.downcase(&1)))])) + end + + def guard(keyword) do + {value, _n} = for <>, reduce: {[], 1} do + {[], n} -> {{:in, [context: Elixir, imports: [{2, Kernel}]], [{:"b#{n}", [], Elixir}, Enum.uniq(~c"#{<>}#{String.upcase(<>)}")]}, n+1} + {left, n} -> {{:and, [context: Elixir, imports: [{2, Kernel}]], [left, {:in, [context: Elixir, imports: [{2, Kernel}]], [{:"b#{n}", [], Elixir}, Enum.uniq(~c"#{<>}#{String.upcase(<>)}")]}]}, n+1} + end + Macro.to_string(value) + end + + embed_template(:parser, """ + # SPDX-License-Identifier: Apache-2.0 + # SPDX-FileCopyrightText: 2025 DBVisor + + defmodule <%= inspect @mod %> do + @moduledoc false + import Kernel, except: [is_boolean: 1] + + defguard is_and(node) when elem(node, 0) == :and + defguard is_between(node) when elem(node, 0) == :between + defguard is_boolean(node) when elem(node, 0) in ~w[and or <> <= >= != < > !< !> = true false unknown like ilike in all any is isnull notnull between]a + defguard is_combinator(node) when elem(node, 0) in ~w[except intersect union]a and elem(node, 2) == [] + defguard is_comma(node) when elem(node, 0) == :comma + defguard is_comment(node) when elem(node, 0) in ~w[comment comments]a + defguard is_conditional(node) when elem(node, 0) in ~w[and or]a and elem(node, 2) == [] + defguard is_colon(node) when elem(node, 0) == :colon + defguard is_distinct(node) when elem(node, 0) == :distinct + defguard is_declare(node) when elem(node, 0) == :declare + defguard is_data_type(node) when elem(node, 0) in ~w[integer float ident quote double_quote backtick bracket parens . binding]a + defguard is_fetch(node) when elem(node, 0) == :fetch + defguard is_fetch_dir(node) when elem(node, 0) in ~w[absolute backward forward relative]a + defguard is_from(node) when elem(node, 0) == :from + defguard is_for(node) when elem(node, 0) == :for + defguard is_grant(node) when elem(node, 0) == :grant + defguard is_revoke(node) when elem(node, 0) == :revoke + defguard is_keyword(node) when elem(node, 0) in <%= inspect(@keywords, limit: :infinity) %> + defguard is_not(node) when elem(node, 0) == :not and elem(node, 2) == [] + defguard is_join(node) when elem(node, 0) == :join + defguard is_parens(node) when elem(node, 0) == :parens + defguard is_operator(node) when elem(node, 0) in ~w[operator :: + - * / ^ % & += -= *= /= %= &= ^-= |*= <=> || as <> <= >= != < > !< !> = like ilike in all any is isnull notnull between]a + defguard is_of(node) when elem(node, 0) == :of + defguard is_is(node) when elem(node, 0) == :is + defguard is_on(node) when elem(node, 0) == :on + defguard is_select(node) when elem(node, 0) == :select + + def predicate([l, c, r]) when is_boolean(l) and is_conditional(c) and is_boolean(r) do + {elem(c, 0), elem(c, 1), [l, r]} + end + def predicate([l, b]) when is_boolean(b) do + [{elem(b, 0), elem(b, 1), [l | elem(b, 2)]}] + end + def predicate([l, b, r | rest]) when is_boolean(b) or is_operator(b) do + predicate([{elem(b, 0), elem(b, 1), [l, r]} | rest]) + end + def predicate([{_, _, _}, node | _] = unit) when is_comma(node) do + unit + end + def predicate([l, b, r, c | rest]) when is_comma(c) and (is_boolean(b) or is_operator(b)) do + [{elem(b, 0), elem(b, 1), [l, r]}, c | rest] + end + def predicate([l, c, r, c2 | rest]) when is_boolean(l) and is_conditional(c) and is_boolean(r) and is_conditional(c2) do + predicate([{elem(c, 0), elem(c, 1), [l, r]}, c2 | rest]) + end + def predicate([f, c, l, b, r, c2 | rest]) when is_boolean(b) and is_conditional(c) and is_conditional(c2) do + predicate([f, c, {elem(b, 0), elem(b, 1), [l, r]}, c2 | rest]) + end + def predicate([f, c, l, b, r]) when is_boolean(b) and is_conditional(c) do + predicate([f, c, {elem(b, 0), elem(b, 1), [l, r]}]) + end + def predicate([l, b, r, c | rest]) when is_boolean(b) and is_conditional(c) do + predicate([{elem(b, 0), elem(b, 1), [l, r]}, c | rest]) + end + def predicate(unit) do + unit + end + + + def insert_node(node, unit, acc, context, root) when is_parens(node) do + {[{elem(node, 0), elem(node, 1), parse(elem(node, 2))} | unit], acc, context, root} + end + def insert_node(node, [{:in = tag, meta, []}, right, {:using, _, _} = using | unit], acc, context, root) do + {[{tag, meta, [node, [right, using | unit]]}], acc, context, root} + end + def insert_node({:in, _, _} = node, [_, {:using, _, _}|_] = unit, acc, context, root) do + {[node | unit], acc, context, root} + end + def insert_node({:into = tag, meta, _}, [_] = unit, acc, context, root) do + {[{tag, meta, unit}], acc, context, root} + end + def insert_node(node, [n, b, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_not(n) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [{elem(n, 0), elem(n, 1), [node]}, {elem(c, 0), elem(c, 1), [r, l]}]} | unit], acc, context, root} + end + def insert_node(node, [n, b, s, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_not(n) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [{elem(n, 0), elem(n, 1), [node]}, {elem(s, 0), elem(s, 1), [{elem(c, 0), elem(c, 1), [r, l]}]}]} | unit], acc, context, root} + end + def insert_node(node, [b, s, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [node, {elem(s, 0), elem(s, 1), [{elem(c, 0), elem(c, 1), [r, l]}]}]} | unit], acc, context, root} + end + def insert_node(node, [b, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [node, {elem(c, 0), elem(c, 1), [r, l]}]} | unit], acc, context, root} + end + def insert_node(node, [b, l, c | unit], acc, context, root) when is_data_type(node) and is_operator(b) and is_data_type(l) and is_conditional(c) do + {[{elem(b, 0), elem(b, 1), [node, l]}, c | unit], acc, context, root} + end + def insert_node(node, [r, b, l | unit], acc, context, root) when is_conditional(node) and is_data_type(r) and is_operator(b) and is_data_type(l) do + {[node, {elem(b, 0), elem(b, 1), [r, l]} | unit], acc, context, root} + end + def insert_node(node, [o, l], acc, context, root) when is_data_type(node) and is_operator(o) and is_data_type(l) do + {[{elem(o, 0), elem(o, 1), [node, l]}], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_not(node) and elem(u, 0) in ~w[false true unknown null]a do + {[{elem(node, 0), elem(node, 1), [u]} | unit], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_not(u) and is_data_type(node) do + {[{elem(u, 0), elem(u, 1), [node | unit]}], acc, context, root} + end + def insert_node({:into = tag, meta, []}, [ident, parens, values], acc, context, root) do + {[], [{tag, meta, [ident, parens, values]} | acc], context, root} + end + def insert_node({tag, meta, []}, [ident, parens], acc, context, root) when tag in ~w[into table]a do + {[], [{tag, meta, [ident, parens]} | acc], context, root} + end + def insert_node({:add = tag, meta, []}, [ident, type], acc, context, root) do + {[], [{tag, meta, [ident, type]} | acc], context, root} + end + def insert_node({:type = tag, meta, []}, [ident, as, type], acc, context, root) do + {[], [{tag, meta, [{elem(as, 0), elem(as, 1), [ident, type]}]} | acc], context, root} + end + def insert_node({tag, meta, []}, [ident], acc, context, root) when tag in ~w[type table]a do + {[], [{tag, meta, [ident]} | acc], context, root} + end + def insert_node({:with = tag, meta, []}, [{:recursive = t, m, []}, {:ident, _, _} = l, {:parens, _, _} = r, {:as = t2, m2, a}], [], context, root) do + {[], [], context, root ++ [{tag, meta, [{t2, m2, [{t, m, [l, r]} | a]}]}]} + end + def insert_node({:with = tag, meta, []}, [{:ident, _, _} = l, {:parens, _, _} = r, {:as = t2, m2, a}], [], context, root) do + {[], [], context, root ++ [{tag, meta, [{t2, m2, [[l, r] | a]}]}]} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[by in references]a do + {[{tag, meta, predicate(unit ++ acc)}], [], context, root} + end + def insert_node(node, [n|_] = unit, acc, context, root) when (is_on(n) or is_of(n)) and elem(node, 0) in ~w[select insert update delete truncate references trigger create connect temporary execute usage set alter system maintain]a do + {[node|unit], acc, context, root} + end + def insert_node(node, [_, n|_] = unit, acc, context, root) when is_for(n) and is_from(node) do + {[node|unit], acc, context, root} + end + def insert_node(node, [_, _, _, n|_] = unit, acc, context, root) when is_for(n) and is_select(node) do + {[node|unit], acc, context, root} + end + def insert_node(node, [] = unit, [] = acc, [] = context, root) when elem(node, 0) in ~w[create drop insert alter update delete start set open close commit rollback]a do + {[node | unit], acc, context, root} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[create drop insert alter update delete start set open close commit rollback]a do + {[], [], context, [{tag, meta, List.wrap(predicate(unit ++ acc))} | root]} + end + def insert_node(node, [n |_] = unit, acc, context, root) when is_grant(node) and elem(n, 0) == :option do + {[node | unit], acc, context, root} + end + def insert_node(node, unit, acc, context, root) when is_grant(node) or is_revoke(node) or is_declare(node) do + {[], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]} + end + def insert_node({:distinct = tag, meta, []}, [{:on, _, _} = on | unit], acc, context, root) do + {[{tag, meta, [on]} | unit], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_fetch_dir(node) and elem(u, 0) != :in do + {[{elem(node, 0), elem(node, 1), [u]}], unit++acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_fetch(node) do + {[], [], context, [{elem(node, 0), elem(node, 1), [u]} | unit ++ acc ++ root]} + end + def insert_node(node, [on], [], context, root) when is_join(node) and is_on(on) do + {[], [], context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [on]} | root]} + end + def insert_node(node, [ident, on], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [ident | elem(on, 2)]}]} | root]} + end + def insert_node(node, [ident, as, on | unit], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [[ident, as]] ++ elem(on, 2) ++ unit}]} | root]} + end + def insert_node(node, [ident, on | unit], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [ident] ++ elem(on, 2) ++ unit}]} | root]} + end + def insert_node(node, unit, acc, context, root) when is_join(node) do + a = elem(node, 2) + acc = unit ++ acc + acc = if a == [], do: acc, else: a ++ [acc] + {[], [], context, [{elem(node, 0), elem(node, 1), acc} | root]} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[select from where group having order limit offset]a do + {[], [], context, [{tag, meta, List.wrap(predicate(unit ++ acc))} | root]} + end + def insert_node(node, unit, acc, context, {:colon, meta, []}) do + {unit, acc, context, {:colon, meta, [node]}} + end + def insert_node(node, [parens | unit], acc, context, root) when is_parens(parens) and is_keyword(node) do + {[{elem(node, 0), elem(node, 1), [parens]} | unit], acc, context, root} + end + def insert_node(node, unit, acc, context, root) do + {[node | unit], acc, context, root} + end + + def parse(tokens) do + parse(tokens, [], [], [], []) + end + def parse([], [], [], [], root) do + root + end + def parse([], unit, acc, [], []) do + predicate(unit ++ acc) + end + def parse([], unit, acc, [], root) do + predicate(unit ++ acc) ++ root + end + def parse([], unit, acc, context, root) when is_tuple(context) do + [{elem(context, 0), elem(context, 1), [unit ++ acc ++ root, elem(context, 2)]}] + end + def parse([node | rest], unit, acc, context, root) when is_comment(node) do + parse(rest, unit, acc, context, [node | root]) + end + def parse([{:all, m, _}, node | rest], unit, acc, [], root) when is_combinator(node) do + parse(rest, [], [], {elem(node, 0), elem(node, 1), [{:all, m, unit ++ acc ++ root}]}, []) + end + def parse([node | rest], unit, acc, [], root) when is_combinator(node) do + parse(rest, [], [], {elem(node, 0), elem(node, 1), unit ++ acc ++ root}, []) + end + def parse([node | rest], unit, acc, context, root) when is_colon(node) do + parse(rest, [], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]) + end + def parse([ident, from, distinct, n, is, left | rest], unit, acc, context, root) when is_is(is) and is_from(from) and is_distinct(distinct) do + node = {elem(is, 0), elem(is, 1), [left, {elem(n, 0), elem(n, 1), [{elem(distinct, 0), elem(distinct, 1), [{elem(from, 0), elem(from, 1), [ident]}]}]}]} + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) + end + def parse([ident, from, distinct, is, left | rest], unit, acc, context, root) when is_is(is) and is_from(from) and is_distinct(distinct) do + node = {elem(is, 0), elem(is, 1), [left, {elem(distinct, 0), elem(distinct, 1), [{elem(from, 0), elem(from, 1), [ident]}]}]} + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) + end + def parse([node | rest], unit, acc, context, root) when is_colon(node) do + parse(rest, [], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]) + end + def parse([parens, node | rest], unit, acc, [], root) when is_parens(parens) and is_combinator(node) do + parse(rest, unit, acc, {elem(node, 0), elem(node, 1), [{elem(parens, 0), elem(parens, 1), parse(elem(parens, 2))}]}, root) + end + def parse([node | rest], unit, acc, context, root) when is_comma(node) do + parse(rest, [], [{elem(node, 0), elem(node, 1), predicate(unit)} | acc], context, root) + end + def parse([node | rest], unit, acc, context, root) do + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) + end + end + """) + + + embed_template(:lexer, """ + # SPDX-License-Identifier: Apache-2.0 + # SPDX-FileCopyrightText: 2025 DBVisor + + defmodule <%= inspect @mod %> do + @moduledoc false + + defguard is_data_type(node) when elem(node, 0) in ~w[integer float ident quote double_quote backtick bracket parens .]a + defguard is_newline(b) when b in <%= inspect(@newline) %> + defguard is_space(b) when b in <%= inspect(@space) %> + defguard is_whitespace(b) when b in <%= inspect(@whitespace) %> + + def opening_delimiter(:parens), do: :"(" + def opening_delimiter(:bracket), do: :"[" + def opening_delimiter(:double_quote), do: :"\\"" + def opening_delimiter(:quote), do: :"'" + def opening_delimiter(:backtick), do: :"`" + def opening_delimiter(type) when type in ~w[var code braces]a, do: :"{" + + def expected_delimiter(:parens), do: :")" + def expected_delimiter(:bracket), do: :"]" + def expected_delimiter(:double_quote), do: :"\\"" + def expected_delimiter(:quote), do: :"'" + def expected_delimiter(:backtick), do: :"`" + def expected_delimiter(type) when type in ~w[var code braces]a, do: :"}" + + def lex(binary, binding, _meta, params \\\\ [], opts \\\\ [metadata: true]) do + case lex(binary, binary, [binding: binding, params: params] ++ opts, 0, 0, nil, [], [], 0) do + {"", _binary, opts, line, column, nil = type, [] = data, acc, _n} -> + {:ok, opts, line, column, type, data, acc} + + {"", binary, _opts, end_line, end_column, type, _data, [{_, [line: line, column: column, file: file], _}|_], _n} when type in ~w[parens bracket double_quote quote backtick var code]a -> + raise TokenMissingError, file: "\#{file}", snippet: binary, end_line: end_line, end_column: end_column, line: line, column: column, opening_delimiter: opening_delimiter(type), expected_delimiter: expected_delimiter(type) + + {"", _binary, opts, line, column, type, data, acc, _n} -> + {:ok, opts, line, column, type, data, insert_node(node(ident(type, data), line, column, data, opts), acc)} + end + end + def lex("" = rest, binary, opts, line, column, type, data, acc, n) do + {rest, binary, opts, line, column, type, data, acc, n} + end + def lex(<>, binary, opts, line, column, type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :comment, [], insert_node(type, line, column, data, opts, acc), n) + end + def lex(<>, binary, opts, line, column, _type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :comments, data, acc, n) + end + def lex(<>, binary, opts, line, column, :comments, data, acc, n) do + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:comments, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :comments, data, acc, n) do + lex(rest, binary, opts, line, column+1, :comments, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, _type, data, acc, n) do + lex(rest, binary, opts, line, column+2, :var, data, acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, 0 = n) when type in ~w[code var]a do + if opts[:binding] do + opts = if type == :var do + update_in(opts, [:params], &(&1 ++ [opts[:binding][List.to_atom(data)]])) + else + update_in(opts, [:params], &(&1 ++ [elem(Code.eval_string(to_string(data), opts[:binding]), 0)])) + end + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:binding, line, column, length(opts[:params]), opts), acc), n) + else + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node(:binding, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, :code = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, type, data ++ [?}], acc, n-1) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[var code]a and b in [?{] do + lex(rest, binary, opts, line, column+1, :code, data ++ [b], acc, n+1) + end + def lex(<>, binary, opts, line, column, :var = type, data, acc, n) when b in ?0..?9 and data != [] do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, :var = type, data, acc, n) when b in ?a..?z or b in ?A..?Z or (b == ?_ and data != []) do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[var code]a do + lex(rest, binary, opts, line, column+1, :code, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?(, ?[] do + acc = case ident(type, data) do + nil -> acc + :ident -> insert_node(node(type, line, column, data, opts), acc) + tag -> insert_node(node(tag, line, column, [], opts), acc) + end + case lex(rest, binary, opts, line, column+1, nil, [], [], n) do + {rest, opts, line, column, value} -> + lex(rest, binary, opts, line, column, nil, [], insert_node(node(ident(type, [b]), line, column, value, opts), acc), n) + {rest, binary, o, l, c, t, d, a, _n} -> + value = if t, do: insert_node(node(t, l, c, d, o), a), else: a + lex(rest, binary, opts, l, c, (if b == ?(, do: :parens, else: :bracket), [], insert_node(node(ident(type, [b]), line, column, value, opts), acc), n) + end + end + def lex(<>, _binary, opts, line, column, type, data, acc, _n) when b in [?), ?]] do + acc = if type, do: insert_node(node(type, line, column, data, opts), acc), else: acc + {rest, opts, line, column+1, acc} + end + def lex(<>, binary, opts, line, column, :double_quote = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :backtick = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, :quote = type, data, acc, n) do + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(type, line, column, data, opts), acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[double_quote quote backtick]a do + lex(rest, binary, opts, line, column+1, type, data ++ [b], acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_newline(b) do + if data == [] do + lex(rest, binary, opts, line+1, column, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line+1, column, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_space(b) do + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when is_whitespace(b) do + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, acc, n) + else + tag = ident(type, data) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node(tag, line, column, data, opts), acc), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?,, ?;] do + acc = if type, do: insert_node(node(ident(type, data), line, column, data, opts), acc), else: acc + lex(rest, binary, opts, line, column, nil, [], insert_node(node(type(b), line, column+1, [], opts), acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in ~w[^-= |*= <=>] do + node = node(String.to_atom(b), line, column+3, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+3, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+3, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in ~w[:: <> != !< !> <= >= += -= *= /= %= &= ||] do + node = node(String.to_atom(b), line, column+2, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+2, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+2, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when type in ~w[integer float]a and b in [?E, ?e] and (e in [?-, ?+] or e in ?0..?9) do + type = :float + lex(rest, binary, opts, line, column+2, type, merge(merge(data, b, type), e, type), acc, n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b == ?. and e in ?0..?9 do + lex(rest, binary, opts, line, column+2, :float, [b, e], acc, n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b in [?-, ?+] and e == ?. do + lex(rest, binary, opts, line, column+2, :float, [b,e], acc, n) + end + def lex(<>, binary, opts, line, column, :integer, data, acc, n) when b == ?. do + type = :float + lex(rest, binary, opts, line, column+1, type, merge(data, b, type), acc, n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b == ?. do + node = node(List.to_atom([b]), line, column+1, [], opts) + if data == [] do + lex(rest, binary, opts, line, column+1, type, data, insert_node(node, acc), n) + else + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + end + def lex(<>, binary, opts, line, column, _type, [] = data, [node | _] = acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] and is_data_type(node) do + node = node(List.to_atom([b]), line, column+1, data, opts) + lex(rest, binary, opts, line, column+1, nil, data, insert_node(node, acc), n) + end + def lex(<>, binary, opts, line, column, nil, [], acc, n) when b in [?+, ?-] and c in ?0..?9 do + lex(rest, binary, opts, line, column+2, :integer, [b, c], acc, n) + end + def lex(<>, binary, opts, line, column, nil = type, data, acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] do + node = node(List.to_atom([b]), line, column+1, data, opts) + lex(rest, binary, opts, line, column+1, type, data, insert_node(node, acc), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) when b in [?+, ?-, ?^, ?*, ?/, ?%, ?&, ?<, ?>, ?=] and type in ~w[integer float ident quote double_quote backtick bracket parens nil]a do + node = node(List.to_atom([b]), line, column+1, [], opts) + lex(rest, binary, opts, line, column+1, nil, [], insert_node(node, insert_node(node(ident(type, data), line, column, data, opts), acc)), n) + end + def lex(<>, binary, opts, line, column, type, data, acc, n) do + type = type(b, type) + lex(rest, binary, opts, line, column+1, type, merge(data, b, type), acc, n) + end + + def insert_node(nil, _line, _column, _data, _opts, acc) do + acc + end + def insert_node(type, line, column, data, opts, acc) do + insert_node(node(type, line, column, data, opts), acc) + end + def insert_node(right, [{:. = tag, m, a}, {:., _, [_, _]} = left | acc]) do + [{tag, m, [left, right | a]} | acc] + end + def insert_node(right, [{:. = tag, meta, [left]} | acc]) do + [{tag, meta, [left, right]} | acc] + end + def insert_node({:., _, _} = node, [right, {:. = tag, m, []}, left | acc]) do + [node, {tag, m, [left, right]} | acc] + end + def insert_node({:. = t, m, a}, [left | acc]) do + [{t, m, [left|a]} | acc] + end + def insert_node({:join = t, m, a} = node, acc) do + case join(acc) do + {qualified, rest} -> [{t, m, [qualified|a]} | rest] + rest -> [node | rest] + end + end + def insert_node(node, acc) do + [node | acc] + end + + def join([{:outer, _} = r, {tag, _} = l, {:natural, _} = n | rest]) when tag in ~w[left right full]a do + {[n, l, r], rest} + end + def join([{:outer, _} = r, {tag, _} = l | rest]) when tag in ~w[left right full]a do + {[l, r], rest} + end + def join([{:inner, _} = r, {:natural, _} = l| rest]) do + {[l, r], rest} + end + def join([{tag, _} = l | rest]) when tag in ~w[inner left right full natural cross]a do + {[l], rest} + end + def join(acc) do + acc + end + + def merge([] = data, _b, type) when type in ~w[double_quote quote backtick]a, do: data + def merge(data, b, _type), do: data ++ [b] + + def type(?;), do: :colon + def type(?,), do: :comma + def type(?"), do: :double_quote + def type(?'), do: :quote + def type(?`), do: :backtick + def type(?(), do: :left_paren + def type(?)), do: :right_paren + def type(?[), do: :left_bracket + def type(?]), do: :right_bracket + + def type(%param{}), do: param + def type(param) when is_float(param), do: :float + def type(param) when is_integer(param), do: :integer + def type(param) when is_map(param), do: :map + def type(param) when is_list(param), do: {:list, Enum.uniq(Enum.map(param, &type/1))} + def type(param) when is_binary(param), do: :string + def type(_param), do: nil + + def type(_, type) when type in ~w[double_quote quote backtick comment comments]a, do: type + def type(?", _type), do: :double_quote + def type(?', _type), do: :quote + def type(?`, _type), do: :backtick + def type(b, type) when b in ?0..?9 and type in ~w[nil integer float]a, do: type || :integer + def type(?., :integer), do: :float + def type(_b, _type), do: :ident + + def meta(line, column, opts) do + if opts[:metadata], do: [line: line, column: column, file: opts[:file]], else: [] + end + + def node(:binding = tag, line, column, [idx], [{:binding, false}|_] = opts) do + {tag, meta(line, column, opts), Enum.at(opts[:params], idx)} + end + def node(tag, line, column, data, opts) when tag in ~w[ident float integer double_quote quote backtick binding parens bracket . comment comments]a do + data = case data do + [] -> data + [{_, _, _} | _] -> data + _ -> [data] + end + {tag, meta(line, column, opts), data} + end + def node(tag, line, column, _data, opts) when tag in ~w[asterisk inner left right full natural cross outer]a do + {tag, meta(line, column, opts)} + end + def node(tag, line, column, _data, opts) do + {tag, meta(line, column, opts), []} + end + + def ident(_type, [?*]), do: :asterisk + def ident(_type, [?(]), do: :parens + def ident(_type, [?[]), do: :bracket + <%= for keyword <- @keywords do %> + def ident(:ident, [<%= Enum.map_join(1..byte_size(keyword), ",", fn n -> "b\#{n}" end) %>]) when <%= guard(keyword) %>, do: <%= inspect(String.to_atom(String.downcase(keyword))) %> + <% end %> + def ident(type, _), do: type + end + """) +end diff --git a/lib/parser.ex b/lib/parser.ex index a9b40eb..4684162 100644 --- a/lib/parser.ex +++ b/lib/parser.ex @@ -3,322 +3,239 @@ defmodule SQL.Parser do @moduledoc false + import Kernel, except: [is_boolean: 1] - def context(?'), do: :"''" - def context(?"), do: :"" - def context(?[), do: :"[]" - def context(?(), do: :"()" + defguard is_and(node) when elem(node, 0) == :and + defguard is_between(node) when elem(node, 0) == :between + defguard is_boolean(node) when elem(node, 0) in ~w[and or <> <= >= != < > !< !> = true false unknown like ilike in all any is isnull notnull between]a + defguard is_combinator(node) when elem(node, 0) in ~w[except intersect union]a and elem(node, 2) == [] + defguard is_comma(node) when elem(node, 0) == :comma + defguard is_comment(node) when elem(node, 0) in ~w[comment comments]a + defguard is_conditional(node) when elem(node, 0) in ~w[and or]a and elem(node, 2) == [] + defguard is_colon(node) when elem(node, 0) == :colon + defguard is_distinct(node) when elem(node, 0) == :distinct + defguard is_declare(node) when elem(node, 0) == :declare + defguard is_data_type(node) when elem(node, 0) in ~w[integer float ident quote double_quote backtick bracket parens . binding]a + defguard is_fetch(node) when elem(node, 0) == :fetch + defguard is_fetch_dir(node) when elem(node, 0) in ~w[absolute backward forward relative]a + defguard is_from(node) when elem(node, 0) == :from + defguard is_for(node) when elem(node, 0) == :for + defguard is_grant(node) when elem(node, 0) == :grant + defguard is_revoke(node) when elem(node, 0) == :revoke + defguard is_keyword(node) when elem(node, 0) in [:abs, :absent, :acos, :all, :allocate, :alter, :and, :any, :any_value, :are, :array, :array_agg, :array_max_cardinality, :as, :asensitive, :asin, :asymmetric, :at, :atan, :atomic, :authorization, :avg, :begin, :begin_frame, :begin_partition, :between, :bigint, :binary, :blob, :boolean, :both, :btrim, :by, :call, :called, :cardinality, :cascaded, :case, :cast, :ceil, :ceiling, :char, :char_length, :character, :character_length, :check, :classifier, :clob, :close, :coalesce, :collate, :collect, :column, :commit, :condition, :connect, :constraint, :contains, :convert, :copy, :corr, :corresponding, :cos, :cosh, :count, :covar_pop, :covar_samp, :create, :cross, :cube, :cume_dist, :current, :current_catalog, :current_date, :current_default_transform_group, :current_path, :current_role, :current_row, :current_schema, :current_time, :current_timestamp, :current_transform_group_for_type, :current_user, :cursor, :cycle, :date, :day, :deallocate, :dec, :decfloat, :decimal, :declare, :default, :define, :delete, :dense_rank, :deref, :describe, :deterministic, :disconnect, :distinct, :double, :drop, :dynamic, :each, :element, :else, :empty, :end, :end_frame, :end_partition, :"end-exec", :equals, :escape, :every, :except, :exec, :execute, :exists, :exp, :external, :extract, false, :fetch, :filter, :first_value, :float, :floor, :for, :foreign, :frame_row, :free, :from, :full, :function, :fusion, :get, :global, :grant, :greatest, :group, :grouping, :groups, :having, :hold, :hour, :identity, :in, :indicator, :initial, :inner, :inout, :insensitive, :insert, :int, :integer, :intersect, :intersection, :interval, :into, :is, :join, :json, :json_array, :json_arrayagg, :json_exists, :json_object, :json_objectagg, :json_query, :json_scalar, :json_serialize, :json_table, :json_table_primitive, :json_value, :lag, :language, :large, :last_value, :lateral, :lead, :leading, :least, :left, :like, :like_regex, :listagg, :ln, :local, :localtime, :localtimestamp, :log, :log10, :lower, :lpad, :ltrim, :match, :match_number, :match_recognize, :matches, :max, :member, :merge, :method, :min, :minute, :mod, :modifies, :module, :month, :multiset, :national, :natural, :nchar, :nclob, :new, :no, :none, :normalize, :not, :nth_value, :ntile, :null, :nullif, :numeric, :occurrences_regex, :octet_length, :of, :offset, :old, :omit, :on, :one, :only, :open, :or, :order, :out, :outer, :over, :overlaps, :overlay, :parameter, :partition, :pattern, :per, :percent, :percent_rank, :percentile_cont, :percentile_disc, :period, :portion, :position, :position_regex, :power, :precedes, :precision, :prepare, :primary, :procedure, :ptf, :range, :rank, :reads, :real, :recursive, :ref, :references, :referencing, :regr_avgx, :regr_avgy, :regr_count, :regr_intercept, :regr_r2, :regr_slope, :regr_sxx, :regr_sxy, :regr_syy, :release, :result, :return, :returns, :revoke, :right, :rollback, :rollup, :row, :row_number, :rows, :rpad, :rtrim, :running, :savepoint, :scope, :scroll, :search, :second, :seek, :select, :sensitive, :session_user, :set, :show, :similar, :sin, :sinh, :skip, :smallint, :some, :specific, :specifictype, :sql, :sqlexception, :sqlstate, :sqlwarning, :sqrt, :start, :static, :stddev_pop, :stddev_samp, :submultiset, :subset, :substring, :substring_regex, :succeeds, :sum, :symmetric, :system, :system_time, :system_user, :table, :tablesample, :tan, :tanh, :then, :time, :timestamp, :timezone_hour, :timezone_minute, :to, :trailing, :translate, :translate_regex, :translation, :treat, :trigger, :trim, :trim_array, true, :truncate, :uescape, :union, :unique, :unknown, :unnest, :update, :upper, :user, :using, :value, :values, :value_of, :var_pop, :var_samp, :varbinary, :varchar, :varying, :versioning, :when, :whenever, :where, :width_bucket, :window, :with, :within, :without, :year, :a, :absolute, :action, :ada, :add, :admin, :after, :always, :asc, :assertion, :assignment, :attribute, :attributes, :before, :bernoulli, :breadth, :c, :cascade, :catalog, :catalog_name, :chain, :chaining, :character_set_catalog, :character_set_name, :character_set_schema, :characteristics, :characters, :class_origin, :cobol, :collation, :collation_catalog, :collation_name, :collation_schema, :columns, :column_name, :command_function, :command_function_code, :committed, :conditional, :condition_number, :connection, :connection_name, :constraint_catalog, :constraint_name, :constraint_schema, :constraints, :constructor, :continue, :copartition, :cursor_name, :data, :datetime_interval_code, :datetime_interval_precision, :defaults, :deferrable, :deferred, :defined, :definer, :degree, :depth, :derived, :desc, :descriptor, :diagnostics, :dispatch, :domain, :dynamic_function, :dynamic_function_code, :encoding, :enforced, :error, :exclude, :excluding, :expression, :final, :finish, :first, :flag, :following, :format, :fortran, :found, :fulfill, :g, :general, :generated, :go, :goto, :granted, :hierarchy, :ignore, :immediate, :immediately, :implementation, :including, :increment, :initially, :input, :instance, :instantiable, :instead, :invoker, :isolation, :k, :keep, :key, :keys, :key_member, :key_type, :last, :length, :level, :locator, :m, :map, :matched, :maxvalue, :measures, :message_length, :message_octet_length, :message_text, :minvalue, :more, :mumps, :name, :names, :nested, :nesting, :next, :nfc, :nfd, :nfkc, :nfkd, :normalized, :null_ordering, :nullable, :nulls, :number, :object, :occurrence, :octets, :option, :options, :ordering, :ordinality, :others, :output, :overflow, :overriding, :p, :pad, :parameter_mode, :parameter_name, :parameter_ordinal_position, :parameter_specific_catalog, :parameter_specific_name, :parameter_specific_schema, :partial, :pascal, :pass, :passing, :past, :path, :permute, :pipe, :placing, :plan, :pli, :preceding, :preserve, :prev, :prior, :private, :privileges, :prune, :public, :quotes, :read, :relative, :repeatable, :respect, :restart, :restrict, :returned_cardinality, :returned_length, :returned_octet_length, :returned_sqlstate, :returning, :role, :routine, :routine_catalog, :routine_name, :routine_schema, :row_count, :scalar, :scale, :schema, :schema_name, :scope_catalog, :scope_name, :scope_schema, :section, :security, :self, :semantics, :sequence, :serializable, :server_name, :session, :sets, :simple, :size, :sort_direction, :source, :space, :specific_name, :state, :statement, :string, :structure, :style, :subclass_origin, :t, :table_name, :temporary, :through, :ties, :top_level_count, :transaction, :transaction_active, :transactions_committed, :transactions_rolled_back, :transform, :transforms, :trigger_catalog, :trigger_name, :trigger_schema, :type, :unbounded, :uncommitted, :unconditional, :under, :unmatched, :unnamed, :usage, :user_defined_type_catalog, :user_defined_type_code, :user_defined_type_name, :user_defined_type_schema, :utf16, :utf32, :utf8, :view, :work, :wrapper, :write, :zone, :limit, :ilike, :backward, :forward, :isnull, :notnull] + defguard is_not(node) when elem(node, 0) == :not and elem(node, 2) == [] + defguard is_join(node) when elem(node, 0) == :join + defguard is_parens(node) when elem(node, 0) == :parens + defguard is_operator(node) when elem(node, 0) in ~w[operator :: + - * / ^ % & += -= *= /= %= &= ^-= |*= <=> || as <> <= >= != < > !< !> = like ilike in all any is isnull notnull between]a + defguard is_of(node) when elem(node, 0) == :of + defguard is_is(node) when elem(node, 0) == :is + defguard is_on(node) when elem(node, 0) == :on + defguard is_select(node) when elem(node, 0) == :select - def type(%param{}), do: param - def type(param) when is_float(param), do: :float - def type(param) when is_integer(param), do: :integer - def type(param) when is_map(param), do: :map - def type(param) when is_list(param), do: {:list, Enum.uniq(Enum.map(param, &type/1))} - def type(param) when is_binary(param), do: :string - def type(_param), do: nil - - def type(?., :integer), do: :float - def type(b, type) when b in ?0..?9 and type in ~w[nil integer float]a, do: type || :integer - def type(_b, _type), do: :ident - - def node(context, metadata, acc, opts), do: {context, List.wrap(if opts[:metadata], do: metadata), List.wrap(acc)} - - ##### This is a mess, we might do better by leveraging the associatity rules instead of pattern matching while merging the nodes - defguard is_ident(value) when elem(value, 0) in [:., :ident, :"", :"''", :"[]"] - defguard is_bool(value) when elem(value, 0) in ~w[null true false unknown]a - defguard is_bool_op(value) when elem(value, 0) in ~w[<> <= >= != < > = like ilike is in]a - defguard is_op(value) when elem(value, 0) in ~w[:: || + - ^ * / % as from]a - defguard is_lop(value) when elem(value, 0) in ~w[and or]a - defguard is_numeric(value) when elem(value, 0) in ~w[float integer]a - defguard is_expr(value) when elem(value, 0) in [:"()", :"\#{}", :binding] - defguard is_datatype(value) when is_ident(value) or is_numeric(value) or is_bool(value) or is_expr(value) - defguard is_operator(value) when is_bool_op(value) or is_op(value) - - def merge([{:is, _, _}, {tag, _, _}] = rest) when tag in ~w[not distinct]a, do: rest - def merge([{:is = tag, meta, acc}, {:distinct = t, m, []}, {:from = t2, m2, []}, right | rest]), do: merge([{tag, meta, acc ++ [{t, m, [{t2, m2, [right]}]}]} | rest]) - def merge([{:is = tag, meta, acc}, {:from = t, m, []}, right | rest]), do: merge([{tag, meta, acc ++ [{t, m, [right]}]} | rest]) - def merge([right, {:is = tag, meta, []} | rest]) when is_ident(right) or is_numeric(right) or is_expr(right), do: merge([{tag, meta, [right]} | rest]) - def merge([{:is = tag, meta, acc}, {:not = t, m, []}, right | rest]), do: merge([{tag, meta, acc ++ [{t, m, [right]}]} | rest]) - def merge([{:is = tag, meta, acc}, right | rest]), do: merge([{tag, meta, acc ++ [right]} | rest]) - def merge([{_, _, _} = right, {tag, meta, [] = acc} | rest]) when tag in ~w[not]a, do: merge([{tag, meta, acc ++ [right]} | rest]) - def merge([{_, _, _} = right, {tag, meta, [] = acc} | rest]) when tag in ~w[asc desc isnull notnull]a, do: merge([{tag, meta, acc ++ [right]} | rest]) - def merge([{tag, meta, []}, {:integer, _, _} = left | rest]) when tag in ~w[absolute relative]a, do: merge([{tag, meta, [left]} | rest]) - def merge([{tag, meta, []}, {t, _, _} = left | rest]) when tag in ~w[forward backward]a and t in ~w[integer all]a, do: merge([{tag, meta, [left]} | rest]) - def merge([{tag, _, _} = right, {t, m, []} | left]) when tag in ~w[next prior first last absolute relative all forward backward]a and t in ~w[in from]a, do: merge([{t, m, [right | left]}]) - def merge([{:distinct = tag, meta, []}, {:on = t, m, []}, {:"()", _, _} = right | rest]), do: merge([{tag, meta, [{:on = t, m, [right]}]} | rest]) - def merge([left, {:on = tag, meta, []}, {:"()", _, _} = right | rest]), do: merge([{tag, meta, [left, right]} | rest]) - - def merge([left, {:all = tag, meta, []}, {:"()", _, _} = right | rest]), do: merge([left, {tag, meta, [right]} | rest]) - - def merge([left, {:on = tag, meta, []} | right]), do: merge([{tag, meta, [left] ++ right}]) - def merge([l1, l2, {:on = tag, meta, []} | right]), do: merge([{tag, meta, [[l1, l2]] ++ right}]) - def merge([left, {:all = tag, meta, [] = acc} | right]), do: merge([left, {tag, meta, acc ++ right}]) - def merge([{:by = tag, meta, acc}, {_, _, _} = right | rest]), do: merge([{tag, meta, acc ++ [right]} | rest]) - def merge([op, right, {:. = tag, meta, []}, left | rest]) when (is_bool_op(op) or is_lop(op) or is_op(op)) and is_ident(right) and is_ident(left), do: merge([op, {tag, meta, [right, left]} | rest]) - def merge([lop, op, right, {:. = tag, meta, []}, left | rest]) when is_lop(lop) and is_bool_op(op) and is_ident(right) and is_ident(left), do: merge([lop, op, {tag, meta, [right, left]} | rest]) - def merge([right, {:. = tag, meta, []}, left | rest]) when is_ident(right) and is_ident(left), do: merge([{tag, meta, [right, left]} | rest]) - def merge([op, l, {:between = tag, meta, []}, right, {:and = t, m, []}, left | rest]) when is_lop(op) and is_datatype(l) and is_datatype(right) and is_datatype(left), do: merge([op, {tag, meta, [l, {t, m, [right, left]}]} | rest]) - - def merge([op, l, {:between = tag, meta, []}, {:symmetric = t, m, []}, right, {:and = t2, m2, []}, left | rest]) when is_lop(op) and is_datatype(l) and is_datatype(right) and is_datatype(left), do: merge([op, {tag, meta, [l, {t, m, [{t2, m2, [right, left]}]}]} | rest]) - - def merge([l, {:between = tag, meta, []}, {:symmetric = t, m, []}, right, {:and = t2, m2, []}, left | rest]) when (is_datatype(l) or elem(l, 0) == :not) and is_datatype(right) and is_datatype(left), do: merge([{tag, meta, [l, {t, m, [{t2, m2, [right, left]}]}]} | rest]) - def merge([l, {:between = tag, meta, []}, right, {:and = t, m, []}, left | rest]) when (is_datatype(l) or elem(l, 0) == :not) and is_datatype(right) and is_datatype(left), do: merge([{tag, meta, [l, {t, m, [right, left]}]} | rest]) - def merge([{t, m, [r]} = op, {:between, _, _} = left | rest]) when is_lop(op), do: merge([{t, m, [r, left]} | rest]) - def merge([right, {t, m, []} = op, left | rest]) when is_lop(right) and is_lop(op) and is_bool(left), do: merge([{t, m, [right, left]} | rest]) - def merge([right, {tag, meta, []} = left | rest]) when is_datatype(right) and is_op(left), do: merge([{tag, meta, [right]} | rest]) - def merge([right, {tag, meta, []} = left | rest]) when is_datatype(right) and is_bool_op(left), do: merge([{tag, meta, [right]} | rest]) - def merge([op, right, {tag, meta, []} = left | rest]) when (is_bool_op(op) or is_lop(op) or is_op(op)) and is_datatype(right) and is_operator(left), do: merge([op, {tag, meta, [right]} | rest]) - def merge([{t, m, [r]} = lop, {t2, m2, [r2]} = op, left, {t3, m3, []} = lop2 | rest]) when is_lop(lop) and is_lop(lop2) and is_bool_op(op) and is_datatype(left), do: merge([{t3, m3, [{t, m, [r, {t2, m2, [r2, left]}]}]} | rest]) - - def merge([op, right, {tag, meta, []} = left | rest]) when is_lop(op) and is_datatype(right) and is_bool_op(left), do: merge([op, {tag, meta, [right]} | rest]) - def merge([{tag, meta, [right]} = op, left, lop | rest]) when is_bool_op(op) and is_datatype(left) and is_lop(lop), do: merge([{tag, meta, [right, left]}, lop | rest]) - - def merge([{tag, meta, [right]} = op, left | rest]) when (is_bool_op(op) or is_op(op)) and is_datatype(left), do: merge([{tag, meta, [right, left]} | rest]) - def merge([{_, _, [_, _]} = right, {tag, meta, []} = left | rest]) when is_bool_op(right) and is_lop(left), do: merge([{tag, meta, [right]} | rest]) - - def merge([{tag, meta, [right]} = lop, {_, _, [_, _]} = left | rest]) when is_bool_op(left) and is_lop(lop), do: merge([{tag, meta, [right, left]} | rest]) - - def merge([{tag, meta, [right]} = lop, {_, _, []} = left | rest]) when is_bool(left) and is_lop(lop), do: merge([{tag, meta, [right, left]} | rest]) - def merge([{:recursive = t, m, []}, {:as = t2, m2, [l, r]}]), do: merge([{t2, m2, [{t, m, l}, r]}]) - def merge([{:ident, _, _} = l1, {:"()", _, _} = l2, {:as = t2, m2, []}, {:"()", _, _} = r]), do: merge([{t2, m2, [[l1, l2], r]}]) - def merge(unit), do: unit - ##### - - def merge(unit, nil, _data, _line, _column, _opts), do: merge(unit) - def merge(unit, type, data, line, column, opts) when is_integer(line) and type != nil, do: merge(unit ++ [node(type, [line: line, column: column - length(data), end_line: line, end_column: column], [data], opts)]) - - def merge(root, [], _metadata, acc, unit, _opts), do: root ++ merge(acc ++ unit) - def merge([] = root, :"()", _metadata, [], [], _opts), do: root - def merge(root, context, metadata, acc, unit, opts) do - root ++ [node(context, metadata, merge(acc ++ unit), opts)] + def predicate([l, c, r]) when is_boolean(l) and is_conditional(c) and is_boolean(r) do + {elem(c, 0), elem(c, 1), [l, r]} + end + def predicate([l, b]) when is_boolean(b) do + [{elem(b, 0), elem(b, 1), [l | elem(b, 2)]}] + end + def predicate([l, b, r | rest]) when is_boolean(b) or is_operator(b) do + predicate([{elem(b, 0), elem(b, 1), [l, r]} | rest]) + end + def predicate([{_, _, _}, node | _] = unit) when is_comma(node) do + unit + end + def predicate([l, b, r, c | rest]) when is_comma(c) and (is_boolean(b) or is_operator(b)) do + [{elem(b, 0), elem(b, 1), [l, r]}, c | rest] + end + def predicate([l, c, r, c2 | rest]) when is_boolean(l) and is_conditional(c) and is_boolean(r) and is_conditional(c2) do + predicate([{elem(c, 0), elem(c, 1), [l, r]}, c2 | rest]) + end + def predicate([f, c, l, b, r, c2 | rest]) when is_boolean(b) and is_conditional(c) and is_conditional(c2) do + predicate([f, c, {elem(b, 0), elem(b, 1), [l, r]}, c2 | rest]) + end + def predicate([f, c, l, b, r]) when is_boolean(b) and is_conditional(c) do + predicate([f, c, {elem(b, 0), elem(b, 1), [l, r]}]) + end + def predicate([l, b, r, c | rest]) when is_boolean(b) and is_conditional(c) do + predicate([{elem(b, 0), elem(b, 1), [l, r]}, c | rest]) + end + def predicate(unit) do + unit end - def expected_delimiter(:"()"), do: :")" - def expected_delimiter(:"''"), do: :"'" - def expected_delimiter(:""), do: :"\"" - - def opening_delimiter(:"()"), do: :"(" - def opening_delimiter(:"''"), do: :"'" - def opening_delimiter(:""), do: :"\"" - - def error!(attrs), do: raise(TokenMissingError, attrs) - def parse(binary, binding, _meta, params \\ [], opts \\ [metadata: true]) do - case parse(binary, binary, opts ++ [binding: binding, params: params], 0, 0, nil, [], [], [], [], [], []) do - {"", _binary, opts, line, column, type, data, unit, context, metadata, acc, root} -> - {:ok, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts), opts[:params]} - end - end - def parse(<>, binary, opts, line, column, type, data, unit, :"" = context, metadata, acc, root) when b != ?" do - parse(rest, binary, opts, line, column+1, type(b, type), data ++ [b], unit, context, metadata, acc, root) - end - def parse(<>, binary, opts, line, column, type, data, unit, :"''" = context, metadata, acc, root) when b != ?' do - parse(rest, binary, opts, line, column+1, type(b, type), data ++ [b], unit, context, metadata, acc, root) - end - def parse("" = rest, binary, opts, line, column, type, data, unit, context, metadata, acc, root) do - {rest, binary, opts, line, column, type, data, unit, context, metadata, acc, root} - end - def parse(<>, binary, opts, line, column, nil = type, [] = data, [] = unit, context, metadata, acc, root) when b == ?+ or b == ?- do - parse(rest, binary, opts, line, column+1, type, data ++ [b], unit, context, metadata, acc, root) - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) when type in ~w[float integer]a and (b == ?. or b >= ?0 and b <= ?9) do - parse(rest, binary, opts, line, column+1, type(b, type), data ++ [b], unit, context, metadata, acc, root) - end - for keyword <- ~w[with select where group having order offset limit fetch] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, end_column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - column = end_column+unquote(len) - parse(unquote(rest), binary, opts, line, column, type, data, [], unquote(tag), [line: line, column: column], [], merge(root, context, metadata ++ [end_line: line, end_column: end_column], acc, unit, opts)) - end - end - for keyword <- ~w[inner natural left right full cross] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, [], :join, [line: line, column: end_column], [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], merge(root, context, metadata ++ [end_line: line, end_column: column], acc, unit, opts)) - end - end - for keyword <- ~w[outer on by recursive] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, end_column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - parse(unquote(rest), binary, opts, line, end_column+unquote(len), type, data, [], context, [line: line, column: end_column], acc ++ unit ++ [node(unquote(tag), metadata ++ [end_line: line, end_column: end_column], [], opts)], root) - end - end - for keyword <- ~w[except intersect union] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, type, data, unit, context, metadata, acc, root) when unquote(guard) do - left = case merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts) do - [{tag, _, _}] = left when tag in ~w[all ()]a -> left - left -> [left] - end - column = column+unquote(len) - case parse(unquote(rest), binary, opts, line, column, nil, [], [], unquote(tag), [line: line, column: column], [], []) do - {rest, binary, opts, line, column, type, data, unit, context, metadata, acc, [{unquote(tag), meta, []} | right]} -> - {rest, binary, opts, line, column, nil, [], [], [], metadata, [], [{unquote(tag), meta, left ++ [merge(right, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)]}]} - {rest, binary, opts, line, column, type, data, unit, context, metadata, acc, root} -> - {rest, binary, opts, line, column, nil, [], [], [], metadata, acc, merge(root, context, metadata ++ [end_line: line, end_column: column], left ++ acc, merge(unit, type, data, line, column, opts), opts)} - end - end - end - for keyword <- ~w[all] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, :fetch = context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, unit ++ [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], context, metadata, acc, root) - end - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - case parse(unquote(rest), binary, opts, line, column+unquote(len), type, data, [], unquote(tag), [line: line, column: column], [], []) do - {rest, end_line, end_column, result} -> - parse(rest, binary, opts, end_line, end_column, type, data, unit ++ result, context, metadata, acc, root) - {rest, binary, opts, end_line, end_column, t, d, u, c, m, a, r} -> - {rest, binary, opts, end_line, end_column, type, data, unit ++ merge(r, c, m ++ [end_line: end_line, end_column: end_column], a, merge(u, t, d, end_line, end_column, opts), opts), context, metadata, acc, root} - end - end - end - for keyword <- ~w[is isnull not notnull as at in collate next prior first last absolute relative forward backward distinct any exists some between symmetric ilike like similar operator count] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, unit ++ [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], context, metadata, acc, root) - end - end - for keyword <- ~w[unknown true false null isnull notnull asc desc] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword, next: [?\s, ?\t, ?\r, ?\n, ?\f, 194, 160, ?,]) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, unit ++ [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], context, metadata, acc, root) - end - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword, eos: true) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, unit ++ [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], context, metadata, acc, root) - end - end - for keyword <- ~w[and or] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - parse(unquote(rest), binary, opts, line, end_column, type, data, merge(unit, type, data, line, column, opts) ++ [node(unquote(tag), [line: line, column: column, end_line: line, end_column: end_column], [], opts)], context, metadata, acc, root) - end - end - for keyword <- ~w{:: [] <> <= >= != !< !> += -= *= /= %= &= ^-= |*= <=> || . + - ^ * / % & < > =} do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword, next: false) - def parse(unquote(match), binary, opts, line, column, type, data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - meta = [line: line, column: column, end_line: line, end_column: end_column] - unit = merge(unit, type, data, line, column, opts) - parse(unquote(rest), binary, opts, line, end_column, nil, [], unit ++ [node(unquote(tag), meta, [], opts)], context, metadata, acc, root) - end - end - for keyword <- ~w[from join] do - {match, guard, rest, len, tag} = SQL.Compiler.generate(keyword) - def parse(unquote(match), binary, opts, line, column, nil = type, [] = data, unit, context, metadata, acc, root) when unquote(guard) do - end_column = column+unquote(len) - metadata = metadata ++ [end_line: line, end_column: end_column] - tag = Enum.at(unit, 0) - cond do - context == :join -> - acc = if acc == [], do: acc, else: [acc] - parse(unquote({:rest, [], Elixir}), binary, opts, line, end_column, type, data, unit, context, metadata, acc, root) - is_tuple(tag) and elem(tag, 0) == :is and context in ~w[where having]a -> - parse(unquote({:rest, [], Elixir}), binary, opts, line, end_column, type, data, unit ++ [node(unquote(tag), [], [], opts)], context, metadata, acc, root) - true -> - parse(unquote(rest), binary, opts, line, end_column, type, data, [], unquote(tag), [line: line, column: column], [], merge(root, context, metadata, acc, unit, opts)) - end - end - end - def parse(<>, binary, opts, line, column, _type, data, unit, context, metadata, acc, root) do - column = column+2 - binding = opts[:binding] - case interpolation(rest, binding, line, column) do - {:error, "", end_line, end_column, _acc} -> - error!([line: line, column: column, end_line: end_line, end_column: end_column, file: "", snippet: binary, opening_delimiter: :"\#{", expected_delimiter: :"}"]) - {rest, end_line, end_column, result} when binding == false -> - parse(rest, binary, opts, end_line, end_column, nil, data, unit ++ [{:"\#{}", [line: line, column: column, end_line: end_line, end_column: end_column], [result]}], context, metadata, acc, root) - {rest, end_line, end_column, result} when is_atom(result) -> - if param = binding[result] do - parse(rest, binary, update_in(opts, [:params], &(&1++[param])), end_line, end_column, nil, data, unit ++ [{:binding, [type: type(param), line: line, column: column, end_line: end_line, end_column: end_column], [length(opts[:params])+1]}], context, metadata, acc, root) - else - raise ArgumentError, "The variable #{result} is not defined" - end - {rest, end_line, end_column, {param, _}} -> - parse(rest, binary, update_in(opts, [:params], &(&1++[param])), end_line, end_column, nil, data, unit ++ [{:binding, [type: type(param), line: line, column: column, end_line: end_line, end_column: end_column], [length(opts[:params])+1]}], context, metadata, acc, root) - end - end - def parse(<>, _binary, opts, line, column, type, data, unit, :"()" = context, metadata, acc, root) do - column = column+1 - {rest, line, column, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)} - end - def parse(<>, _binary, opts, line, column, type, data, unit, :"[]" = context, metadata, acc, root) do - {rest, line, column, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)} - end - def parse(<>, _binary, opts, line, column, type, data, unit, :"" = context, metadata, acc, root) do - {rest, line, column, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)} - end - def parse(<>, _binary, opts, line, column, type, data, unit, :"''" = context, metadata, acc, root) do - {rest, line, column, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)} - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) when b in [?(, ?[, ?", ?'] do - unit = merge(unit, type, data, line, column, opts) - column = column+1 - tag = context(b) - case parse(rest, binary, opts, line, column, nil, [], [], tag, [line: line, column: column], [], []) do - {rest, end_line, end_column, [{^tag, _, _}] = result} -> - parse(rest, binary, opts, end_line, end_column, nil, data, unit ++ result, context, metadata, acc, root) - {rest, end_line, end_column, result} -> - parse(rest, binary, opts, end_line, end_column, nil, data, unit ++ [node(tag, [line: line, column: column, end_line: end_line, end_column: end_column], result, opts)], context, metadata, acc, root) - {"" = rest, binary, opts, end_line, end_column, nil, [], [], [], _meta, [], nodes} when nodes != [] -> - {rest, binary, opts, end_line, end_column, type, data, unit ++ [node(tag, [line: line, column: column, end_line: end_line, end_column: end_column], nodes, opts)], context, metadata, acc, root} - {"", binary, _, end_line, end_column, _, _, _, _, _, _, _} -> - error!([line: line, column: column, end_line: end_line, end_column: end_column, file: "", snippet: binary, opening_delimiter: opening_delimiter(tag), expected_delimiter: expected_delimiter(tag)]) - end - end - def parse(<>, _binary, opts, line, column, type, data, unit, context, metadata, acc, root) when b in [?), ?], ?", ?'] do - column = column+1 - {rest, line, column, merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts)} - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) do - parse(rest, binary, opts, line, column+1, nil, [], [], context, metadata, acc ++ [{:",", [line: line, column: column, end_line: line, end_column: column+1], merge(merge(unit, type, data, line, column, opts))}], root) - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) do - end_column = column+1 - node = node(:";", [line: line, column: column, end_line: line, end_column: end_column], merge(root, context, metadata ++ [end_line: line, end_column: column], acc, merge(unit, type, data, line, column, opts), opts), opts) - parse(rest, binary, opts, line, end_column, nil, [], [], [], [], [], [] ++ [node]) - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) do - parse(rest, binary, opts, line+1, column, nil, [], merge(unit, type, data, line, column, opts), context, metadata, acc, root) - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) when b in [?\s, ?\t, ?\r, ?\f, 194, 160] do - parse(rest, binary, opts, line, column+1, nil, [], merge(unit, type, data, line, column, opts), context, metadata, acc, root) - end - def parse(<>, binary, opts, line, column, type, data, unit, context, metadata, acc, root) do - parse(rest, binary, opts, line, column+1, type(b, type), data ++ [b], unit, context, metadata, acc, root) + def insert_node(node, unit, acc, context, root) when is_parens(node) do + {[{elem(node, 0), elem(node, 1), parse(elem(node, 2))} | unit], acc, context, root} + end + def insert_node(node, [{:in = tag, meta, []}, right, {:using, _, _} = using | unit], acc, context, root) do + {[{tag, meta, [node, [right, using | unit]]}], acc, context, root} + end + def insert_node({:in, _, _} = node, [_, {:using, _, _}|_] = unit, acc, context, root) do + {[node | unit], acc, context, root} + end + def insert_node({:into = tag, meta, _}, [_] = unit, acc, context, root) do + {[{tag, meta, unit}], acc, context, root} + end + def insert_node(node, [n, b, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_not(n) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [{elem(n, 0), elem(n, 1), [node]}, {elem(c, 0), elem(c, 1), [r, l]}]} | unit], acc, context, root} + end + def insert_node(node, [n, b, s, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_not(n) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [{elem(n, 0), elem(n, 1), [node]}, {elem(s, 0), elem(s, 1), [{elem(c, 0), elem(c, 1), [r, l]}]}]} | unit], acc, context, root} + end + def insert_node(node, [b, s, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [node, {elem(s, 0), elem(s, 1), [{elem(c, 0), elem(c, 1), [r, l]}]}]} | unit], acc, context, root} + end + def insert_node(node, [b, r, c, l | unit], acc, context, root) when is_between(b) and is_and(c) and is_data_type(r) and is_data_type(l) and is_data_type(node) do + {[{elem(b, 0), elem(b, 1), [node, {elem(c, 0), elem(c, 1), [r, l]}]} | unit], acc, context, root} + end + def insert_node(node, [b, l, c | unit], acc, context, root) when is_data_type(node) and is_operator(b) and is_data_type(l) and is_conditional(c) do + {[{elem(b, 0), elem(b, 1), [node, l]}, c | unit], acc, context, root} + end + def insert_node(node, [r, b, l | unit], acc, context, root) when is_conditional(node) and is_data_type(r) and is_operator(b) and is_data_type(l) do + {[node, {elem(b, 0), elem(b, 1), [r, l]} | unit], acc, context, root} + end + def insert_node(node, [o, l], acc, context, root) when is_data_type(node) and is_operator(o) and is_data_type(l) do + {[{elem(o, 0), elem(o, 1), [node, l]}], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_not(node) and elem(u, 0) in ~w[false true unknown null]a do + {[{elem(node, 0), elem(node, 1), [u]} | unit], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_not(u) and is_data_type(node) do + {[{elem(u, 0), elem(u, 1), [node | unit]}], acc, context, root} + end + def insert_node({:into = tag, meta, []}, [ident, parens, values], acc, context, root) do + {[], [{tag, meta, [ident, parens, values]} | acc], context, root} + end + def insert_node({tag, meta, []}, [ident, parens], acc, context, root) when tag in ~w[into table]a do + {[], [{tag, meta, [ident, parens]} | acc], context, root} + end + def insert_node({:add = tag, meta, []}, [ident, type], acc, context, root) do + {[], [{tag, meta, [ident, type]} | acc], context, root} + end + def insert_node({:type = tag, meta, []}, [ident, as, type], acc, context, root) do + {[], [{tag, meta, [{elem(as, 0), elem(as, 1), [ident, type]}]} | acc], context, root} + end + def insert_node({tag, meta, []}, [ident], acc, context, root) when tag in ~w[type table]a do + {[], [{tag, meta, [ident]} | acc], context, root} + end + def insert_node({:with = tag, meta, []}, [{:recursive = t, m, []}, {:ident, _, _} = l, {:parens, _, _} = r, {:as = t2, m2, a}], [], context, root) do + {[], [], context, root ++ [{tag, meta, [{t2, m2, [{t, m, [l, r]} | a]}]}]} + end + def insert_node({:with = tag, meta, []}, [{:ident, _, _} = l, {:parens, _, _} = r, {:as = t2, m2, a}], [], context, root) do + {[], [], context, root ++ [{tag, meta, [{t2, m2, [[l, r] | a]}]}]} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[by in references]a do + {[{tag, meta, predicate(unit ++ acc)}], [], context, root} + end + def insert_node(node, [n|_] = unit, acc, context, root) when (is_on(n) or is_of(n)) and elem(node, 0) in ~w[select insert update delete truncate references trigger create connect temporary execute usage set alter system maintain]a do + {[node|unit], acc, context, root} + end + def insert_node(node, [_, n|_] = unit, acc, context, root) when is_for(n) and is_from(node) do + {[node|unit], acc, context, root} + end + def insert_node(node, [_, _, _, n|_] = unit, acc, context, root) when is_for(n) and is_select(node) do + {[node|unit], acc, context, root} + end + def insert_node(node, [] = unit, [] = acc, [] = context, root) when elem(node, 0) in ~w[create drop insert alter update delete start set open close commit rollback]a do + {[node | unit], acc, context, root} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[create drop insert alter update delete start set open close commit rollback]a do + {[], [], context, [{tag, meta, List.wrap(predicate(unit ++ acc))} | root]} + end + def insert_node(node, [n |_] = unit, acc, context, root) when is_grant(node) and elem(n, 0) == :option do + {[node | unit], acc, context, root} + end + def insert_node(node, unit, acc, context, root) when is_grant(node) or is_revoke(node) or is_declare(node) do + {[], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]} + end + def insert_node({:distinct = tag, meta, []}, [{:on, _, _} = on | unit], acc, context, root) do + {[{tag, meta, [on]} | unit], acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_fetch_dir(node) and elem(u, 0) != :in do + {[{elem(node, 0), elem(node, 1), [u]}], unit++acc, context, root} + end + def insert_node(node, [u | unit], acc, context, root) when is_fetch(node) do + {[], [], context, [{elem(node, 0), elem(node, 1), [u]} | unit ++ acc ++ root]} + end + def insert_node(node, [on], [], context, root) when is_join(node) and is_on(on) do + {[], [], context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [on]} | root]} + end + def insert_node(node, [ident, on], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [ident | elem(on, 2)]}]} | root]} + end + def insert_node(node, [ident, as, on | unit], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [[ident, as]] ++ elem(on, 2) ++ unit}]} | root]} + end + def insert_node(node, [ident, on | unit], [] = acc, context, root) when is_join(node) and is_on(on) do + {[], acc, context, [{elem(node, 0), elem(node, 1), elem(node, 2) ++ [{elem(on, 0), elem(on, 1), [ident] ++ elem(on, 2) ++ unit}]} | root]} + end + def insert_node(node, unit, acc, context, root) when is_join(node) do + a = elem(node, 2) + acc = unit ++ acc + acc = if a == [], do: acc, else: a ++ [acc] + {[], [], context, [{elem(node, 0), elem(node, 1), acc} | root]} + end + def insert_node({tag, meta, []}, unit, acc, context, root) when tag in ~w[select from where group having order limit offset]a do + {[], [], context, [{tag, meta, List.wrap(predicate(unit ++ acc))} | root]} + end + def insert_node(node, unit, acc, context, {:colon, meta, []}) do + {unit, acc, context, {:colon, meta, [node]}} + end + def insert_node(node, [parens | unit], acc, context, root) when is_parens(parens) and is_keyword(node) do + {[{elem(node, 0), elem(node, 1), [parens]} | unit], acc, context, root} + end + def insert_node(node, unit, acc, context, root) do + {[node | unit], acc, context, root} end - def interpolation(binary, binding, line, column, type \\ :var, acc \\ [], n \\ 0) - def interpolation("" = rest, _binding, line, column, _type, acc, 0), do: {:error, rest, line, column, acc} - def interpolation(<>, _binding, line, column, :var, acc, 0) do - {<>, line, column+1, List.to_atom(acc)} + def parse(tokens) do + parse(tokens, [], [], [], []) + end + def parse([], [], [], [], root) do + root + end + def parse([], unit, acc, [], []) do + predicate(unit ++ acc) + end + def parse([], unit, acc, [], root) do + predicate(unit ++ acc) ++ root + end + def parse([], unit, acc, context, root) when is_tuple(context) do + [{elem(context, 0), elem(context, 1), [unit ++ acc ++ root, elem(context, 2)]}] + end + def parse([node | rest], unit, acc, context, root) when is_comment(node) do + parse(rest, unit, acc, context, [node | root]) + end + def parse([{:all, m, _}, node | rest], unit, acc, [], root) when is_combinator(node) do + parse(rest, [], [], {elem(node, 0), elem(node, 1), [{:all, m, unit ++ acc ++ root}]}, []) + end + def parse([node | rest], unit, acc, [], root) when is_combinator(node) do + parse(rest, [], [], {elem(node, 0), elem(node, 1), unit ++ acc ++ root}, []) end - def interpolation(<>, binding, line, column, :code, acc, 0) do - {<>, line, column+1, Code.eval_string("#{acc}", binding)} + def parse([node | rest], unit, acc, context, root) when is_colon(node) do + parse(rest, [], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]) end - def interpolation(<>, binding, line, column, _type, acc, n) do - interpolation(rest, binding, line, column, :code, acc ++ [?{], n+1) + def parse([ident, from, distinct, n, is, left | rest], unit, acc, context, root) when is_is(is) and is_from(from) and is_distinct(distinct) do + node = {elem(is, 0), elem(is, 1), [left, {elem(n, 0), elem(n, 1), [{elem(distinct, 0), elem(distinct, 1), [{elem(from, 0), elem(from, 1), [ident]}]}]}]} + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) end - def interpolation(<>, binding, line, column, type, acc, n) do - interpolation(rest, binding, line, column+1, type, acc ++ [?}], n-1) + def parse([ident, from, distinct, is, left | rest], unit, acc, context, root) when is_is(is) and is_from(from) and is_distinct(distinct) do + node = {elem(is, 0), elem(is, 1), [left, {elem(distinct, 0), elem(distinct, 1), [{elem(from, 0), elem(from, 1), [ident]}]}]} + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) end - def interpolation(<>, binding, line, column, :var = type, acc, n) when v in ?0..?9 and acc != [] do - interpolation(rest, binding, line+1, column, type, acc ++ [v], n) + def parse([node | rest], unit, acc, context, root) when is_colon(node) do + parse(rest, [], [], context, [{elem(node, 0), elem(node, 1), unit ++ acc ++ root}]) end - def interpolation(<>, binding, line, column, :var = type, acc, n) when v in ?a..?z or v in ?A..?Z or (v == ?_ and acc != []) do - interpolation(rest, binding, line+1, column, type, acc ++ [v], n) + def parse([parens, node | rest], unit, acc, [], root) when is_parens(parens) and is_combinator(node) do + parse(rest, unit, acc, {elem(node, 0), elem(node, 1), [{elem(parens, 0), elem(parens, 1), parse(elem(parens, 2))}]}, root) end - def interpolation(<>, binding, line, column, _type, acc, n) do - interpolation(rest, binding, line+1, column, :code, acc ++ [?\n], n) + def parse([node | rest], unit, acc, context, root) when is_comma(node) do + parse(rest, [], [{elem(node, 0), elem(node, 1), predicate(unit)} | acc], context, root) end - def interpolation(<>, binding, line, column, _type, acc, n) do - interpolation(rest, binding, line, column+1, :code, acc ++ [v], n) + def parse([node | rest], unit, acc, context, root) do + {unit, acc, context, root} = insert_node(node, unit, acc, context, root) + parse(rest, unit, acc, context, root) end end diff --git a/lib/sql.ex b/lib/sql.ex index 135a717..2da3b43 100644 --- a/lib/sql.ex +++ b/lib/sql.ex @@ -13,6 +13,7 @@ defmodule SQL do @doc false @behaviour SQL import SQL + def config, do: unquote(opts) def token_to_sql(token), do: token_to_sql(token) defoverridable token_to_sql: 1 end @@ -23,6 +24,7 @@ defmodule SQL do Returns a SQL string for a given token. """ @doc since: "0.1.0" + @doc deprecated: "Use SQL.Token.token_to_string/1 instead" @callback token_to_sql(token :: {atom, keyword, list}) :: String.t() defstruct [:tokens, :query, :params, :module] @@ -40,15 +42,16 @@ defmodule SQL do @doc false def build(right, {:<<>>, meta, _} = left, _modifiers, env) do - quote bind_quoted: [right: Macro.unpipe(right), left: left, meta: Macro.escape({meta[:line], meta[:column] || 0, env.file})] do + quote bind_quoted: [right: Macro.unpipe(right), left: left, meta: Macro.escape({meta[:line], meta[:column] || 0, env.file}), e: Macro.escape(env)] do {t, p} = Enum.reduce(right, {[], []}, fn {[], 0}, acc -> acc + {v, 0}, {:ok, opts, _, _, _, _, tokens} -> {tokens ++ v.tokens, opts[:params] ++ v.params} {v, 0}, {tokens, params} -> {tokens ++ v.tokens, params ++ v.params} end) - {:ok, tokens, params} = SQL.Parser.parse(left, binding(), meta, p) - t ++ tokens + {:ok, opts, _, _, _, _, tokens} = SQL.Lexer.lex(left, binding(), meta, p) + t ++ SQL.Parser.parse(tokens) |> SQL.to_query() - |> Map.merge(%{module: __MODULE__, params: params}) + |> Map.merge(%{module: __MODULE__, params: opts[:params]}) end end @@ -67,16 +70,23 @@ defmodule SQL do end @doc false + @doc since: "0.1.0" def parse(binary) do - {:ok, tokens, []} = SQL.Parser.parse(binary, false, {1, 0, nil}) - to_query(tokens) + {:ok, _opts, _, _, _, _, tokens} = SQL.Lexer.lex(binary, false, {1, 0, nil}, []) + tokens + |> SQL.Parser.parse() + |> to_query() end @doc false - @acc ~w[; with update delete select fetch from join where group having window except intersect union order limit offset lock]a + @doc since: "0.1.0" + @acc ~w[for create drop insert alter with update delete select set fetch from join where group having window except intersect union order limit offset lock colon in declare start grant revoke commit rollback open close comment comments into]a def to_query([value | _] = tokens) when is_tuple(value) and elem(value, 0) in @acc do struct(SQL, tokens: tokens, query: Enum.reduce(@acc, [], fn key, acc -> acc ++ for {k, meta, v} <- Enum.filter(tokens, &(elem(&1, 0) == key)), do: {k, meta, Enum.map(v, &to_query/1)} end)) end + def to_query({:parens = tag, meta, values}) do + {tag, meta, to_query(values)} + end def to_query({tag, meta, values}) do {tag, meta, Enum.map(values, &to_query/1)} end @@ -87,25 +97,28 @@ defmodule SQL do token end - @doc false - def __token_to_sql__(sql) do - if Kernel.function_exported?(sql.module, :token_to_sql, 1) do - &sql.module.token_to_sql/1 - else - &SQL.String.token_to_sql/1 - end - end - defimpl Inspect, for: SQL do def inspect(sql, _opts) do - fun = SQL.__token_to_sql__(sql) - Enum.reduce(0..length(sql.params), to_string(sql), &String.replace(&2, fun.({:binding, [], [&1]}), fun.(Enum.at(sql.params, &1)))) + if Kernel.function_exported?(sql.module, :config, 0) do + Enum.reduce(0..length(sql.params), to_string(sql), &String.replace(&2, sql.module.config()[:adapter].token_to_string({:binding, [], [&1]}), sql.module.config()[:adapter].token_to_string(Enum.at(sql.params, &1)), global: false)) + else + Enum.reduce(0..length(sql.params), to_string(sql), &String.replace(&2, SQL.String.token_to_sql({:binding, [], [&1]}), SQL.String.token_to_sql(Enum.at(sql.params, &1)))) + end end end defimpl String.Chars, for: SQL do def to_string(sql) do - Enum.map_join(sql.query, " ", &SQL.__token_to_sql__(sql).(&1)) + cond do + Kernel.function_exported?(sql.module, :config, 0) -> Enum.map(sql.query, &sql.module.config()[:adapter].token_to_string(&1)) + Kernel.function_exported?(sql.module, :token_to_string, 2) -> Enum.map(sql.query, &sql.module.token_to_string(&1)) + true -> Enum.map(sql.query, &SQL.String.token_to_sql(&1)) + end + |> Enum.reduce("", fn + v, "" -> v + <<";", _::binary>> = v, acc -> acc <> v + v, acc -> acc <> " " <> v + end) end end end diff --git a/lib/string.ex b/lib/string.ex index 04238b0..54992ad 100644 --- a/lib/string.ex +++ b/lib/string.ex @@ -8,91 +8,93 @@ defmodule SQL.String do def token_to_sql(value, _mod) when is_struct(value) do to_string(value) end - def token_to_sql({tag, _, []}, mod) do - "#{mod.token_to_sql(tag)}" + + def token_to_sql({tag, _, [{:parens, _, _} = value]}, mod) when tag in ~w[integer float update]a do + "#{mod.token_to_sql(tag)}#{mod.token_to_sql(value)}" end def token_to_sql({tag, _, value}, _mod) when tag in ~w[ident integer float]a do "#{value}" end - def token_to_sql({:"", _, value}, mod) do - "\"#{mod.token_to_sql(value)}\"" + def token_to_sql({tag, _}, mod) do + mod.token_to_sql(tag) end - def token_to_sql({:"''", _, value}, mod) do - "'#{mod.token_to_sql(value)}'" + def token_to_sql({:comment, _, value}, _mod) do + "-- #{value}" end - def token_to_sql({:"()", _, value}, mod) do - "(#{mod.token_to_sql(value)})" + def token_to_sql({:comments, _, value}, _mod) do + "\\* #{value} *\\" end - def token_to_sql({:"\#{}", _, [value]}, _mod) do - "\#{#{value}}" + def token_to_sql({:double_quote, _, value}, _mod) do + "\"#{value}\"" end - def token_to_sql({:in, _, [right, {:binding, _, _} = left]}, mod) do - "#{mod.token_to_sql(right)} = ANY(#{mod.token_to_sql(left)})" + def token_to_sql({:quote, _, value}, _mod) do + "'#{value}'" end - def token_to_sql({tag, _, value}, mod) when tag in ~w[; ,]a do - "#{mod.token_to_sql(value)}#{mod.token_to_sql(tag)}" + def token_to_sql({:parens, _, value}, mod) do + "(#{mod.token_to_sql(value)})" end - def token_to_sql({:distinct = t1, _, [{:from, _, _} = left]}, mod) do - "#{mod.token_to_sql(t1)} #{mod.token_to_sql(left)}" + def token_to_sql({:colon, _, value}, mod) do + "; #{mod.token_to_sql(value)}" end - def token_to_sql({:distinct = t1, _, [{:on = t2, _, [{:"()", _, values}]}]}, mod) do - "#{mod.token_to_sql(t1)} #{mod.token_to_sql(t2)} (#{Enum.map_join(values, " ", &mod.token_to_sql/1)})" + def token_to_sql({:comma, _, value}, mod) do + ", #{mod.token_to_sql(value)}" end - def token_to_sql({:in = t1, _, [ident, {:"()", _, values}]}, mod) do - "#{mod.token_to_sql(ident)} #{mod.token_to_sql(t1)} (#{Enum.map_join(values, " ", &mod.token_to_sql/1)})" + def token_to_sql({tag, _, []}, mod) do + mod.token_to_sql(tag) end - def token_to_sql({:recursive = t1, _, [ident, {:"()", _, values}]}, mod) do - "#{mod.token_to_sql(t1)} #{mod.token_to_sql(ident)} (#{Enum.map_join(values, " ", &mod.token_to_sql/1)})" + def token_to_sql({tag, _, [[_ | _] = left, right]}, mod) when tag in ~w[join]a do + "#{mod.token_to_sql(left)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(right)}" end - def token_to_sql({:is = t1, _, [ident, distinct, from]}, mod) do - "#{mod.token_to_sql(ident)} #{mod.token_to_sql(t1)} #{mod.token_to_sql(distinct)} #{mod.token_to_sql(from)}" + def token_to_sql({tag, _, [{:with = t, _, [left, right]}]}, mod) when tag in ~w[to]a do + "#{mod.token_to_sql(tag)} #{mod.token_to_sql(left)} #{mod.token_to_sql(t)} #{mod.token_to_sql(right)}" end - def token_to_sql({tag, _, values}, mod) when tag in ~w[all]a do - "#{mod.token_to_sql(tag)} #{mod.token_to_sql(values)}" + def token_to_sql({tag, _, value}, mod) when tag in ~w[select from fetch limit where order offset group having with join by distinct create type drop insert alter table add into delete update start grant revoke set declare open close commit rollback references recursive]a do + "#{mod.token_to_sql(tag)} #{mod.token_to_sql(value)}" end - def token_to_sql({:select = tag, _, [{:distinct, _, _} = distinct | rest]}, mod) do - "#{mod.token_to_sql(tag)} #{mod.token_to_sql(distinct)} #{Enum.map_join(rest, " ", &mod.token_to_sql/1)}" + def token_to_sql({:on = tag, _, [source, as, value]}, mod) do + "#{mod.token_to_sql(source)} #{mod.token_to_sql(as)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(value)}" end - def token_to_sql({tag, _, value}, mod) when tag in ~w[select from by]a do - "#{mod.token_to_sql(tag)} #{Enum.map_join(value, " ", &mod.token_to_sql/1)}" + def token_to_sql({tag, _, [left, [{:all = t, _, right}]]}, mod) when tag in ~w[union except intersect]a do + "#{mod.token_to_sql(left)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(t)} #{mod.token_to_sql(right)}" end - def token_to_sql({tag, _, [[_ | _] = left, right]}, mod) when tag in ~w[join]a do - "#{Enum.map_join(left, " ", &mod.token_to_sql/1)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(right)}" + def token_to_sql({:between = tag, _, [{:not = t, _, right}, left]}, mod) do + "#{mod.token_to_sql(right)} #{mod.token_to_sql(t)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(left)}" end - def token_to_sql({tag, _, value}, mod) when tag in ~w[fetch limit where order offset group having with join]a do - "#{mod.token_to_sql(tag)} #{mod.token_to_sql(value)}" - end - def token_to_sql({tag, _, [left, right]}, mod) when tag in ~w[:: [\] <> <= >= != || + - ^ * / % < > = like ilike as union except intersect between and or on is not all in]a do + def token_to_sql({tag, _, [left, right]}, mod) when tag in ~w[:: [\] <> <= >= != || + - ^ * / % < > = like ilike as union except intersect between and or on is not in cursor for to]a do "#{mod.token_to_sql(left)} #{mod.token_to_sql(tag)} #{mod.token_to_sql(right)}" end - def token_to_sql({tag, _, [left, right]}, mod) when tag in ~w[.]a do - "#{mod.token_to_sql(left)}#{mod.token_to_sql(tag)}#{mod.token_to_sql(right)}" + def token_to_sql({tag, _, [{:parens, _, _} = value]}, mod) when tag not in ~w[in on]a do + "#{mod.token_to_sql(tag)}#{mod.token_to_sql(value)}" + end + def token_to_sql({tag, _, values}, mod) when tag in ~w[not all between symmetric absolute relative forward backward on in for without]a do + "#{mod.token_to_sql(tag)} #{mod.token_to_sql(values)}" end - def token_to_sql({tag, _, [{t, _, _} = right]}, mod) when tag in ~w[not]a and t in ~w[null false true unknown distinct]a do - "#{mod.token_to_sql(tag)} #{mod.token_to_sql(right)}" + def token_to_sql({tag, _, [left, right]}, mod) when tag in ~w[.]a do + "#{mod.token_to_sql(left)}.#{mod.token_to_sql(right)}" end def token_to_sql({tag, _, [left]}, mod) when tag in ~w[not]a do "#{mod.token_to_sql(left)} #{mod.token_to_sql(tag)}" end - def token_to_sql({tag, _, [right]}, mod) when tag in ~w[not all between symmetric absolute relative forward backward]a do - "#{mod.token_to_sql(tag)} #{mod.token_to_sql(right)}" - end def token_to_sql({tag, _, [left]}, mod) when tag in ~w[asc desc isnull notnull]a do "#{mod.token_to_sql(left)} #{mod.token_to_sql(tag)}" end - def token_to_sql({:binding, _, [idx]}, _mod) do - "$#{idx}" + def token_to_sql({:binding, _, [idx]}, _mod) when is_integer(idx) do + "?" end - def token_to_sql(value, _mod) when is_atom(value) do - "#{value}" + def token_to_sql({:binding, _, value}, _mod) do + "{{#{value}}}" end - def token_to_sql(value, _mod) when is_binary(value) do - "'#{value}'" + def token_to_sql(:asterisk, _mod) do + "*" end - def token_to_sql(value, _mod) when is_number(value) do - "#{value}" + def token_to_sql(value, _mod) when is_atom(value) do + "#{value}" end def token_to_sql(values, mod) when is_list(values) do - Enum.map_join(values, " ", &mod.token_to_sql/1) + Enum.reduce(values, "", fn + token, "" -> mod.token_to_sql(token, mod) + {:comma, _, _} = token, acc -> acc <> mod.token_to_sql(token, mod) + token, acc -> acc <> " " <> mod.token_to_sql(token, mod) + end) end end diff --git a/lib/token.ex b/lib/token.ex new file mode 100644 index 0000000..978ab5e --- /dev/null +++ b/lib/token.ex @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Token do + @moduledoc false + + @doc """ + Returns a SQL string for a given token. + """ + @doc since: "0.2.0" + @callback token_to_string(token :: {atom, keyword, list} | {atom, keyword}) :: String.t() + + defmacro __using__(opts) do + quote bind_quoted: [opts: opts] do + @doc false + @behaviour SQL.Token + def token_to_string(token), do: SQL.Adapters.ANSI.token_to_string(token, __MODULE__) + defoverridable token_to_string: 1 + end + end +end diff --git a/test/adapters/ansi_test.exs b/test/adapters/ansi_test.exs new file mode 100644 index 0000000..9566935 --- /dev/null +++ b/test/adapters/ansi_test.exs @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.ANSITest do + use ExUnit.Case + use SQL, adapter: SQL.Adapters.ANSI + + describe "with" do + test "recursive" do + assert "with recursive temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + + test "regular" do + assert "with temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + end + + describe "combinations" do + test "except" do + assert "(select id from users) except (select id from users)" == to_string(~SQL[(select id from users) except (select id from users)]) + assert "(select id from users) except select id from users" == to_string(~SQL[(select id from users) except select id from users]) + assert "select id from users except (select id from users)" == to_string(~SQL[select id from users except (select id from users)]) + assert "select id from users except select id from users" == to_string(~SQL[select id from users except select id from users]) + + assert "(select id from users) except all (select id from users)" == to_string(~SQL[(select id from users) except all (select id from users)]) + assert "(select id from users) except all select id from users" == to_string(~SQL[(select id from users) except all select id from users]) + assert "select id from users except all (select id from users)" == to_string(~SQL[select id from users except all (select id from users)]) + assert "select id from users except all select id from users" == to_string(~SQL[select id from users except all select id from users]) + end + + test "intersect" do + assert "(select id from users) intersect (select id from users)" == to_string(~SQL[(select id from users) intersect (select id from users)]) + assert "(select id from users) intersect select id from users" == to_string(~SQL[(select id from users) intersect select id from users]) + assert "select id from users intersect (select id from users)" == to_string(~SQL[select id from users intersect (select id from users)]) + assert "select id from users intersect select id from users" == to_string(~SQL[select id from users intersect select id from users]) + + assert "(select id from users) intersect all (select id from users)" == to_string(~SQL[(select id from users) intersect all (select id from users)]) + assert "(select id from users) intersect all select id from users" == to_string(~SQL[(select id from users) intersect all select id from users]) + assert "select id from users intersect all (select id from users)" == to_string(~SQL[select id from users intersect all (select id from users)]) + assert "select id from users intersect all select id from users" == to_string(~SQL[select id from users intersect all select id from users]) + end + + test "union" do + assert "(select id from users) union (select id from users)" == to_string(~SQL[(select id from users) union (select id from users)]) + assert "(select id from users) union select id from users" == to_string(~SQL[(select id from users) union select id from users]) + assert "select id from users union (select id from users)" == to_string(~SQL[select id from users union (select id from users)]) + assert "select id from users union select id from users" == to_string(~SQL[select id from users union select id from users]) + + assert "(select id from users) union all (select id from users)" == to_string(~SQL[(select id from users) union all (select id from users)]) + assert "(select id from users) union all select id from users" == to_string(~SQL[(select id from users) union all select id from users]) + assert "select id from users union all (select id from users)" == to_string(~SQL[select id from users union all (select id from users)]) + assert "select id from users union all select id from users" == to_string(~SQL[select id from users union all select id from users]) + end + end + + describe "query" do + test "select" do + assert "select id" == to_string(~SQL[select id]) + assert "select id, id as di" == to_string(~SQL[select id, id as di]) + assert "select id, (select id from users) as di" == to_string(~SQL[select id, (select id from users) as di]) + assert "select unknownn" == to_string(~SQL[select unknownn]) + assert "select truee" == to_string(~SQL[select truee]) + assert "select falsee" == to_string(~SQL[select falsee]) + assert "select nulll" == to_string(~SQL[select nulll]) + assert "select isnulll" == to_string(~SQL[select isnulll]) + assert "select notnulll" == to_string(~SQL[select notnulll]) + assert "select ascc" == to_string(~SQL[select ascc]) + assert "select descc" == to_string(~SQL[select descc]) + assert "select distinct id" == to_string(~SQL[select distinct id]) + assert "select distinct on (id, users) id" == to_string(~SQL[select distinct on (id, users) id]) + end + + test "from" do + assert "from users" == to_string(~SQL[from users]) + assert "from users u, persons p" == to_string(~SQL[from users u, persons p]) + assert "from users u" == to_string(~SQL[from users u]) + assert "from users as u" == to_string(~SQL[from users as u]) + assert "from users u" == to_string(~SQL[from users u]) + end + + test "join" do + assert "inner join users" == to_string(~SQL[inner join users]) + assert "join users" == to_string(~SQL[join users]) + assert "left outer join users" == to_string(~SQL[left outer join users]) + assert "left join users" == to_string(~SQL[left join users]) + assert "natural join users" == to_string(~SQL[natural join users]) + assert "full join users" == to_string(~SQL[full join users]) + assert "cross join users" == to_string(~SQL[cross join users]) + assert "join users u" == to_string(~SQL[join users u]) + assert "join users on id = id" == to_string(~SQL[join users on id = id]) + assert "join users u on id = id" == to_string(~SQL[join users u on id = id]) + assert "join users on (id = id)" == to_string(~SQL[join users on (id = id)]) + assert "join (select * from users) on (id = id)" == to_string(~SQL[join (select * from users) on (id = id)]) + assert "join (select * from users) u on (id = id)" == to_string(~SQL[join (select * from users) u on (id = id)]) + end + + test "where" do + assert "where 1 = 2" == to_string(~SQL[where 1 = 2]) + assert "where 1 = 2" == to_string(~SQL[where 1=2]) + assert "where 1 != 2" == to_string(~SQL[where 1 != 2]) + assert "where 1 <> 2" == to_string(~SQL[where 1 <> 2]) + assert "where 1 = 2 and id = users.id and id > 3 or true" == to_string(~SQL[where 1 = 2 and id = users.id and id > 3 or true]) + end + + test "group by" do + assert "group by id" == to_string(~SQL[group by id]) + assert "group by users.id" == to_string(~SQL[group by users.id]) + assert "group by id, users.id" == to_string(~SQL[group by id, users.id]) + end + + test "having" do + assert "having 1 = 2" == to_string(~SQL[having 1 = 2]) + assert "having 1 != 2" == to_string(~SQL[having 1 != 2]) + assert "having 1 <> 2" == to_string(~SQL[having 1 <> 2]) + end + + test "order by" do + assert "order by id" == to_string(~SQL[order by id]) + assert "order by users.id" == to_string(~SQL[order by users.id]) + assert "order by id, users.id, users.id asc, id desc" == to_string(~SQL[order by id, users.id, users.id asc, id desc]) + end + + test "offset" do + assert "offset 1" == to_string(~SQL[offset 1]) + end + + test "limit" do + assert "limit 1" == to_string(~SQL[limit 1]) + end + + test "fetch" do + assert "fetch next from users" == to_string(~SQL[fetch next from users]) + assert "fetch prior from users" == to_string(~SQL[fetch prior from users]) + assert "fetch first from users" == to_string(~SQL[fetch first from users]) + assert "fetch last from users" == to_string(~SQL[fetch last from users]) + assert "fetch absolute 1 from users" == to_string(~SQL[fetch absolute 1 from users]) + assert "fetch relative 1 from users" == to_string(~SQL[fetch relative 1 from users]) + assert "fetch 1 from users" == to_string(~SQL[fetch 1 from users]) + assert "fetch all from users" == to_string(~SQL[fetch all from users]) + assert "fetch forward from users" == to_string(~SQL[fetch forward from users]) + assert "fetch forward 1 from users" == to_string(~SQL[fetch forward 1 from users]) + assert "fetch forward all from users" == to_string(~SQL[fetch forward all from users]) + assert "fetch backward from users" == to_string(~SQL[fetch backward from users]) + assert "fetch backward 1 from users" == to_string(~SQL[fetch backward 1 from users]) + assert "fetch backward all from users" == to_string(~SQL[fetch backward all from users]) + + assert "fetch next in users" == to_string(~SQL[fetch next in users]) + assert "fetch prior in users" == to_string(~SQL[fetch prior in users]) + assert "fetch first in users" == to_string(~SQL[fetch first in users]) + assert "fetch last in users" == to_string(~SQL[fetch last in users]) + assert "fetch absolute 1 in users" == to_string(~SQL[fetch absolute 1 in users]) + assert "fetch relative 1 in users" == to_string(~SQL[fetch relative 1 in users]) + assert "fetch 1 in users" == to_string(~SQL[fetch 1 in users]) + assert "fetch all in users" == to_string(~SQL[fetch all in users]) + assert "fetch forward in users" == to_string(~SQL[fetch forward in users]) + assert "fetch forward 1 in users" == to_string(~SQL[fetch forward 1 in users]) + assert "fetch forward all in users" == to_string(~SQL[fetch forward all in users]) + assert "fetch backward in users" == to_string(~SQL[fetch backward in users]) + assert "fetch backward 1 in users" == to_string(~SQL[fetch backward 1 in users]) + assert "fetch backward all in users" == to_string(~SQL[fetch backward all in users]) + end + end + + describe "datatypes" do + test "integer" do + assert "select 1" == to_string(~SQL[select 1]) + assert "select 1000" == to_string(~SQL[select 1000]) + assert "select -1000" == to_string(~SQL[select -1000]) + assert "select +1000" == to_string(~SQL[select +1000]) + end + + test "float" do + assert "select +10.00" == to_string(~SQL[select +10.00]) + assert "select -10.00" == to_string(~SQL[select -10.00]) + end + + test "identifier" do + assert "select db.users.id" == to_string(~SQL[select db.users.id]) + assert "select db.users" == to_string(~SQL[select db.users]) + assert "select db" == to_string(~SQL[select db]) + end + + test "qouted" do + assert "select \"db.users.id\"" == to_string(~SQL[select "db.users.id"]) + assert "select 'db.users'" == to_string(~SQL[select 'db.users']) + assert "select \"db.users.id\", 'db.users'" == to_string(~SQL[select "db.users.id", 'db.users']) + end + end + + describe "interpolation" do + test "binding" do + var1 = 1 + var0 = "id" + var2 = ~SQL[select {{var0}}] + assert ["id"] == var2.params + sql = ~SQL[select {{var2}}, {{var1}}] + assert [var2, 1] == sql.params + assert "select ?, ?" == to_string(sql) + end + + test ". syntax" do + map = %{k: "v"} + sql = ~SQL[select {{map.k <> "v"}}] + assert ["vv"] == sql.params + assert "select ?" == to_string(sql) + end + + test "code" do + sql = ~SQL[select {{0}}, {{%{k: 1}}}] + assert [0, %{k: 1}] == sql.params + assert "select ?, ?" == to_string(sql) + end + + test "in" do + sql = ~SQL"select {{1}} in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select ? in ?" == to_string(sql) + + sql = ~SQL"select {{1}} not in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select ? not in ?" == to_string(sql) + end + end + + describe "operators" do + test "=" do + assert "where id = 1" == to_string(~SQL[where id = 1]) + assert "where id = 1" == to_string(~SQL[where id=1]) + end + test "-" do + assert "where id - 1" == to_string(~SQL[where id - 1]) + assert "where id - 1" == to_string(~SQL[where id-1]) + end + test "+" do + assert "where id + 1" == to_string(~SQL[where id + 1]) + assert "where id + 1" == to_string(~SQL[where id+1]) + end + test "*" do + assert "where id * 1" == to_string(~SQL[where id * 1]) + assert "where id * 1" == to_string(~SQL[where id*1]) + end + test "/" do + assert "where id / 1" == to_string(~SQL[where id / 1]) + assert "where id / 1" == to_string(~SQL[where id/1]) + end + test "<>" do + assert "where id <> 1" == to_string(~SQL[where id <> 1]) + assert "where id <> 1" == to_string(~SQL[where id<>1]) + end + test ">" do + assert "where id > 1" == to_string(~SQL[where id > 1]) + assert "where id > 1" == to_string(~SQL[where id>1]) + end + test "<" do + assert "where id < 1" == to_string(~SQL[where id < 1]) + assert "where id < 1" == to_string(~SQL[where id<1]) + end + test ">=" do + assert "where id >= 1" == to_string(~SQL[where id >= 1]) + assert "where id >= 1" == to_string(~SQL[where id>=1]) + end + test "<=" do + assert "where id <= 1" == to_string(~SQL[where id <= 1]) + assert "where id <= 1" == to_string(~SQL[where id<=1]) + end + test "between" do + assert "where id between 1 and 2" == to_string(~SQL[where id between 1 and 2]) + assert "where id not between 1 and 2" == to_string(~SQL[where id not between 1 and 2]) + assert "where id between symmetric 1 and 2" == to_string(~SQL[where id between symmetric 1 and 2]) + assert "where id not between symmetric 1 and 2" == to_string(~SQL[where id not between symmetric 1 and 2]) + end + test "like" do + assert "where id like 1" == to_string(~SQL[where id like 1]) + end + test "ilike" do + assert "where id ilike 1" == to_string(~SQL[where id ilike 1]) + end + test "in" do + assert "where id in (1, 2)" == to_string(~SQL[where id in (1, 2)]) + end + test "is" do + assert "where id is null" == to_string(~SQL[where id is null]) + assert "where id is false" == to_string(~SQL[where id is false]) + assert "where id is true" == to_string(~SQL[where id is true]) + assert "where id is unknown" == to_string(~SQL[where id is unknown]) + + assert "where id is not null" == to_string(~SQL[where id is not null]) + assert "where id is not false" == to_string(~SQL[where id is not false]) + assert "where id is not true" == to_string(~SQL[where id is not true]) + assert "where id is not unknown" == to_string(~SQL[where id is not unknown]) + + assert "where id is distinct from 1" == to_string(~SQL[where id is distinct from 1]) + assert "where id is not distinct from 1" == to_string(~SQL[where id is not distinct from 1]) + + assert "where id isnull" == to_string(~SQL[where id isnull]) + assert "where id notnull" == to_string(~SQL[where id notnull]) + end + test "as" do + assert "select id as dd" == to_string(~SQL[select id as dd]) + end + end +end diff --git a/test/adapters/mysql_test.exs b/test/adapters/mysql_test.exs new file mode 100644 index 0000000..d5a0aa1 --- /dev/null +++ b/test/adapters/mysql_test.exs @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.MySQLTest do + use ExUnit.Case + use SQL, adapter: SQL.Adapters.MySQL + + describe "with" do + test "recursive" do + assert "with recursive temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + + test "regular" do + assert "with temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + end + + describe "combinations" do + test "except" do + assert "(select id from users) except (select id from users)" == to_string(~SQL[(select id from users) except (select id from users)]) + assert "(select id from users) except select id from users" == to_string(~SQL[(select id from users) except select id from users]) + assert "select id from users except (select id from users)" == to_string(~SQL[select id from users except (select id from users)]) + assert "select id from users except select id from users" == to_string(~SQL[select id from users except select id from users]) + + assert "(select id from users) except all (select id from users)" == to_string(~SQL[(select id from users) except all (select id from users)]) + assert "(select id from users) except all select id from users" == to_string(~SQL[(select id from users) except all select id from users]) + assert "select id from users except all (select id from users)" == to_string(~SQL[select id from users except all (select id from users)]) + assert "select id from users except all select id from users" == to_string(~SQL[select id from users except all select id from users]) + end + + test "intersect" do + assert "(select id from users) intersect (select id from users)" == to_string(~SQL[(select id from users) intersect (select id from users)]) + assert "(select id from users) intersect select id from users" == to_string(~SQL[(select id from users) intersect select id from users]) + assert "select id from users intersect (select id from users)" == to_string(~SQL[select id from users intersect (select id from users)]) + assert "select id from users intersect select id from users" == to_string(~SQL[select id from users intersect select id from users]) + + assert "(select id from users) intersect all (select id from users)" == to_string(~SQL[(select id from users) intersect all (select id from users)]) + assert "(select id from users) intersect all select id from users" == to_string(~SQL[(select id from users) intersect all select id from users]) + assert "select id from users intersect all (select id from users)" == to_string(~SQL[select id from users intersect all (select id from users)]) + assert "select id from users intersect all select id from users" == to_string(~SQL[select id from users intersect all select id from users]) + end + + test "union" do + assert "(select id from users) union (select id from users)" == to_string(~SQL[(select id from users) union (select id from users)]) + assert "(select id from users) union select id from users" == to_string(~SQL[(select id from users) union select id from users]) + assert "select id from users union (select id from users)" == to_string(~SQL[select id from users union (select id from users)]) + assert "select id from users union select id from users" == to_string(~SQL[select id from users union select id from users]) + + assert "(select id from users) union all (select id from users)" == to_string(~SQL[(select id from users) union all (select id from users)]) + assert "(select id from users) union all select id from users" == to_string(~SQL[(select id from users) union all select id from users]) + assert "select id from users union all (select id from users)" == to_string(~SQL[select id from users union all (select id from users)]) + assert "select id from users union all select id from users" == to_string(~SQL[select id from users union all select id from users]) + end + end + + describe "query" do + test "select" do + assert "select id" == to_string(~SQL[select id]) + assert "select id, id as di" == to_string(~SQL[select id, id as di]) + assert "select id, (select id from users) as di" == to_string(~SQL[select id, (select id from users) as di]) + assert "select unknownn" == to_string(~SQL[select unknownn]) + assert "select truee" == to_string(~SQL[select truee]) + assert "select falsee" == to_string(~SQL[select falsee]) + assert "select nulll" == to_string(~SQL[select nulll]) + assert "select isnulll" == to_string(~SQL[select isnulll]) + assert "select notnulll" == to_string(~SQL[select notnulll]) + assert "select ascc" == to_string(~SQL[select ascc]) + assert "select descc" == to_string(~SQL[select descc]) + assert "select distinct id" == to_string(~SQL[select distinct id]) + assert "select distinct on (id, users) id" == to_string(~SQL[select distinct on (id, users) id]) + end + + test "from" do + assert "from users" == to_string(~SQL[from users]) + assert "from users u, persons p" == to_string(~SQL[from users u, persons p]) + assert "from users u" == to_string(~SQL[from users u]) + assert "from users as u" == to_string(~SQL[from users as u]) + assert "from users u" == to_string(~SQL[from users u]) + end + + test "join" do + assert "inner join users" == to_string(~SQL[inner join users]) + assert "join users" == to_string(~SQL[join users]) + assert "left outer join users" == to_string(~SQL[left outer join users]) + assert "left join users" == to_string(~SQL[left join users]) + assert "natural join users" == to_string(~SQL[natural join users]) + assert "full join users" == to_string(~SQL[full join users]) + assert "cross join users" == to_string(~SQL[cross join users]) + assert "join users u" == to_string(~SQL[join users u]) + assert "join users on id = id" == to_string(~SQL[join users on id = id]) + assert "join users u on id = id" == to_string(~SQL[join users u on id = id]) + assert "join users on (id = id)" == to_string(~SQL[join users on (id = id)]) + assert "join (select * from users) on (id = id)" == to_string(~SQL[join (select * from users) on (id = id)]) + assert "join (select * from users) u on (id = id)" == to_string(~SQL[join (select * from users) u on (id = id)]) + end + + test "where" do + assert "where 1 = 2" == to_string(~SQL[where 1 = 2]) + assert "where 1 = 2" == to_string(~SQL[where 1=2]) + assert "where 1 != 2" == to_string(~SQL[where 1 != 2]) + assert "where 1 <> 2" == to_string(~SQL[where 1 <> 2]) + assert "where 1 = 2 and id = users.id and id > 3 or true" == to_string(~SQL[where 1 = 2 and id = users.id and id > 3 or true]) + end + + test "group by" do + assert "group by id" == to_string(~SQL[group by id]) + assert "group by users.id" == to_string(~SQL[group by users.id]) + assert "group by id, users.id" == to_string(~SQL[group by id, users.id]) + end + + test "having" do + assert "having 1 = 2" == to_string(~SQL[having 1 = 2]) + assert "having 1 != 2" == to_string(~SQL[having 1 != 2]) + assert "having 1 <> 2" == to_string(~SQL[having 1 <> 2]) + end + + test "order by" do + assert "order by id" == to_string(~SQL[order by id]) + assert "order by users.id" == to_string(~SQL[order by users.id]) + assert "order by id, users.id, users.id asc, id desc" == to_string(~SQL[order by id, users.id, users.id asc, id desc]) + end + + test "offset" do + assert "offset 1" == to_string(~SQL[offset 1]) + end + + test "limit" do + assert "limit 1" == to_string(~SQL[limit 1]) + end + + test "fetch" do + assert "fetch next from users" == to_string(~SQL[fetch next from users]) + assert "fetch prior from users" == to_string(~SQL[fetch prior from users]) + assert "fetch first from users" == to_string(~SQL[fetch first from users]) + assert "fetch last from users" == to_string(~SQL[fetch last from users]) + assert "fetch absolute 1 from users" == to_string(~SQL[fetch absolute 1 from users]) + assert "fetch relative 1 from users" == to_string(~SQL[fetch relative 1 from users]) + assert "fetch 1 from users" == to_string(~SQL[fetch 1 from users]) + assert "fetch all from users" == to_string(~SQL[fetch all from users]) + assert "fetch forward from users" == to_string(~SQL[fetch forward from users]) + assert "fetch forward 1 from users" == to_string(~SQL[fetch forward 1 from users]) + assert "fetch forward all from users" == to_string(~SQL[fetch forward all from users]) + assert "fetch backward from users" == to_string(~SQL[fetch backward from users]) + assert "fetch backward 1 from users" == to_string(~SQL[fetch backward 1 from users]) + assert "fetch backward all from users" == to_string(~SQL[fetch backward all from users]) + + assert "fetch next in users" == to_string(~SQL[fetch next in users]) + assert "fetch prior in users" == to_string(~SQL[fetch prior in users]) + assert "fetch first in users" == to_string(~SQL[fetch first in users]) + assert "fetch last in users" == to_string(~SQL[fetch last in users]) + assert "fetch absolute 1 in users" == to_string(~SQL[fetch absolute 1 in users]) + assert "fetch relative 1 in users" == to_string(~SQL[fetch relative 1 in users]) + assert "fetch 1 in users" == to_string(~SQL[fetch 1 in users]) + assert "fetch all in users" == to_string(~SQL[fetch all in users]) + assert "fetch forward in users" == to_string(~SQL[fetch forward in users]) + assert "fetch forward 1 in users" == to_string(~SQL[fetch forward 1 in users]) + assert "fetch forward all in users" == to_string(~SQL[fetch forward all in users]) + assert "fetch backward in users" == to_string(~SQL[fetch backward in users]) + assert "fetch backward 1 in users" == to_string(~SQL[fetch backward 1 in users]) + assert "fetch backward all in users" == to_string(~SQL[fetch backward all in users]) + end + end + + describe "datatypes" do + test "integer" do + assert "select 1" == to_string(~SQL[select 1]) + assert "select 1000" == to_string(~SQL[select 1000]) + assert "select -1000" == to_string(~SQL[select -1000]) + assert "select +1000" == to_string(~SQL[select +1000]) + end + + test "float" do + assert "select +10.00" == to_string(~SQL[select +10.00]) + assert "select -10.00" == to_string(~SQL[select -10.00]) + end + + test "identifier" do + assert "select db.users.id" == to_string(~SQL[select db.users.id]) + assert "select db.users" == to_string(~SQL[select db.users]) + assert "select db" == to_string(~SQL[select db]) + end + + test "qouted" do + assert "select \"db.users.id\"" == to_string(~SQL[select "db.users.id"]) + assert "select 'db.users'" == to_string(~SQL[select 'db.users']) + assert "select \"db.users.id\", 'db.users'" == to_string(~SQL[select "db.users.id", 'db.users']) + end + end + + describe "interpolation" do + test "binding" do + var1 = 1 + var0 = "id" + var2 = ~SQL[select {{var0}}] + assert ["id"] == var2.params + sql = ~SQL[select {{var2}}, {{var1}}] + assert [var2, 1] == sql.params + assert "select ?, ?" == to_string(sql) + end + + test ". syntax" do + map = %{k: "v"} + sql = ~SQL[select {{map.k <> "v"}}] + assert ["vv"] == sql.params + assert "select ?" == to_string(sql) + end + + test "code" do + sql = ~SQL[select {{0}}, {{%{k: 1}}}] + assert [0, %{k: 1}] == sql.params + assert "select ?, ?" == to_string(sql) + end + + test "in" do + sql = ~SQL"select {{1}} in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select ? in ?" == to_string(sql) + + sql = ~SQL"select {{1}} not in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select ? not in ?" == to_string(sql) + end + end + + describe "operators" do + test "=" do + assert "where id = 1" == to_string(~SQL[where id = 1]) + assert "where id = 1" == to_string(~SQL[where id=1]) + end + test "-" do + assert "where id - 1" == to_string(~SQL[where id - 1]) + assert "where id - 1" == to_string(~SQL[where id-1]) + end + test "+" do + assert "where id + 1" == to_string(~SQL[where id + 1]) + assert "where id + 1" == to_string(~SQL[where id+1]) + end + test "*" do + assert "where id * 1" == to_string(~SQL[where id * 1]) + assert "where id * 1" == to_string(~SQL[where id*1]) + end + test "/" do + assert "where id / 1" == to_string(~SQL[where id / 1]) + assert "where id / 1" == to_string(~SQL[where id/1]) + end + test "<>" do + assert "where id <> 1" == to_string(~SQL[where id <> 1]) + assert "where id <> 1" == to_string(~SQL[where id<>1]) + end + test ">" do + assert "where id > 1" == to_string(~SQL[where id > 1]) + assert "where id > 1" == to_string(~SQL[where id>1]) + end + test "<" do + assert "where id < 1" == to_string(~SQL[where id < 1]) + assert "where id < 1" == to_string(~SQL[where id<1]) + end + test ">=" do + assert "where id >= 1" == to_string(~SQL[where id >= 1]) + assert "where id >= 1" == to_string(~SQL[where id>=1]) + end + test "<=" do + assert "where id <= 1" == to_string(~SQL[where id <= 1]) + assert "where id <= 1" == to_string(~SQL[where id<=1]) + end + test "between" do + assert "where id between 1 and 2" == to_string(~SQL[where id between 1 and 2]) + assert "where id not between 1 and 2" == to_string(~SQL[where id not between 1 and 2]) + assert "where id between symmetric 1 and 2" == to_string(~SQL[where id between symmetric 1 and 2]) + assert "where id not between symmetric 1 and 2" == to_string(~SQL[where id not between symmetric 1 and 2]) + end + test "like" do + assert "where id like 1" == to_string(~SQL[where id like 1]) + end + test "ilike" do + assert "where id ilike 1" == to_string(~SQL[where id ilike 1]) + end + test "in" do + assert "where id in (1, 2)" == to_string(~SQL[where id in (1, 2)]) + end + test "is" do + assert "where id is null" == to_string(~SQL[where id is null]) + assert "where id is false" == to_string(~SQL[where id is false]) + assert "where id is true" == to_string(~SQL[where id is true]) + assert "where id is unknown" == to_string(~SQL[where id is unknown]) + + assert "where id is not null" == to_string(~SQL[where id is not null]) + assert "where id is not false" == to_string(~SQL[where id is not false]) + assert "where id is not true" == to_string(~SQL[where id is not true]) + assert "where id is not unknown" == to_string(~SQL[where id is not unknown]) + + assert "where id is distinct from 1" == to_string(~SQL[where id is distinct from 1]) + assert "where id is not distinct from 1" == to_string(~SQL[where id is not distinct from 1]) + + assert "where id isnull" == to_string(~SQL[where id isnull]) + assert "where id notnull" == to_string(~SQL[where id notnull]) + end + test "as" do + assert "select id as dd" == to_string(~SQL[select id as dd]) + end + end +end diff --git a/test/adapters/postgres_test.exs b/test/adapters/postgres_test.exs new file mode 100644 index 0000000..2e63190 --- /dev/null +++ b/test/adapters/postgres_test.exs @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.PostgresTest do + use ExUnit.Case + use SQL, adapter: SQL.Adapters.Postgres + + describe "with" do + test "recursive" do + assert "with recursive temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + + test "regular" do + assert "with temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + end + + describe "combinations" do + test "except" do + assert "(select id from users) except (select id from users)" == to_string(~SQL[(select id from users) except (select id from users)]) + assert "(select id from users) except select id from users" == to_string(~SQL[(select id from users) except select id from users]) + assert "select id from users except (select id from users)" == to_string(~SQL[select id from users except (select id from users)]) + assert "select id from users except select id from users" == to_string(~SQL[select id from users except select id from users]) + + assert "(select id from users) except all (select id from users)" == to_string(~SQL[(select id from users) except all (select id from users)]) + assert "(select id from users) except all select id from users" == to_string(~SQL[(select id from users) except all select id from users]) + assert "select id from users except all (select id from users)" == to_string(~SQL[select id from users except all (select id from users)]) + assert "select id from users except all select id from users" == to_string(~SQL[select id from users except all select id from users]) + end + + test "intersect" do + assert "(select id from users) intersect (select id from users)" == to_string(~SQL[(select id from users) intersect (select id from users)]) + assert "(select id from users) intersect select id from users" == to_string(~SQL[(select id from users) intersect select id from users]) + assert "select id from users intersect (select id from users)" == to_string(~SQL[select id from users intersect (select id from users)]) + assert "select id from users intersect select id from users" == to_string(~SQL[select id from users intersect select id from users]) + + assert "(select id from users) intersect all (select id from users)" == to_string(~SQL[(select id from users) intersect all (select id from users)]) + assert "(select id from users) intersect all select id from users" == to_string(~SQL[(select id from users) intersect all select id from users]) + assert "select id from users intersect all (select id from users)" == to_string(~SQL[select id from users intersect all (select id from users)]) + assert "select id from users intersect all select id from users" == to_string(~SQL[select id from users intersect all select id from users]) + end + + test "union" do + assert "(select id from users) union (select id from users)" == to_string(~SQL[(select id from users) union (select id from users)]) + assert "(select id from users) union select id from users" == to_string(~SQL[(select id from users) union select id from users]) + assert "select id from users union (select id from users)" == to_string(~SQL[select id from users union (select id from users)]) + assert "select id from users union select id from users" == to_string(~SQL[select id from users union select id from users]) + + assert "(select id from users) union all (select id from users)" == to_string(~SQL[(select id from users) union all (select id from users)]) + assert "(select id from users) union all select id from users" == to_string(~SQL[(select id from users) union all select id from users]) + assert "select id from users union all (select id from users)" == to_string(~SQL[select id from users union all (select id from users)]) + assert "select id from users union all select id from users" == to_string(~SQL[select id from users union all select id from users]) + end + end + + describe "query" do + test "select" do + assert "select id" == to_string(~SQL[select id]) + assert "select id, id as di" == to_string(~SQL[select id, id as di]) + assert "select id, (select id from users) as di" == to_string(~SQL[select id, (select id from users) as di]) + assert "select unknownn" == to_string(~SQL[select unknownn]) + assert "select truee" == to_string(~SQL[select truee]) + assert "select falsee" == to_string(~SQL[select falsee]) + assert "select nulll" == to_string(~SQL[select nulll]) + assert "select isnulll" == to_string(~SQL[select isnulll]) + assert "select notnulll" == to_string(~SQL[select notnulll]) + assert "select ascc" == to_string(~SQL[select ascc]) + assert "select descc" == to_string(~SQL[select descc]) + assert "select distinct id" == to_string(~SQL[select distinct id]) + assert "select distinct on (id, users) id" == to_string(~SQL[select distinct on (id, users) id]) + end + + test "from" do + assert "from users" == to_string(~SQL[from users]) + assert "from users u, persons p" == to_string(~SQL[from users u, persons p]) + assert "from users u" == to_string(~SQL[from users u]) + assert "from users as u" == to_string(~SQL[from users as u]) + assert "from users u" == to_string(~SQL[from users u]) + end + + test "join" do + assert "inner join users" == to_string(~SQL[inner join users]) + assert "join users" == to_string(~SQL[join users]) + assert "left outer join users" == to_string(~SQL[left outer join users]) + assert "left join users" == to_string(~SQL[left join users]) + assert "natural join users" == to_string(~SQL[natural join users]) + assert "full join users" == to_string(~SQL[full join users]) + assert "cross join users" == to_string(~SQL[cross join users]) + assert "join users u" == to_string(~SQL[join users u]) + assert "join users on id = id" == to_string(~SQL[join users on id = id]) + assert "join users u on id = id" == to_string(~SQL[join users u on id = id]) + assert "join users on (id = id)" == to_string(~SQL[join users on (id = id)]) + assert "join (select * from users) on (id = id)" == to_string(~SQL[join (select * from users) on (id = id)]) + assert "join (select * from users) u on (id = id)" == to_string(~SQL[join (select * from users) u on (id = id)]) + end + + test "where" do + assert "where 1 = 2" == to_string(~SQL[where 1 = 2]) + assert "where 1 = 2" == to_string(~SQL[where 1=2]) + assert "where 1 != 2" == to_string(~SQL[where 1 != 2]) + assert "where 1 <> 2" == to_string(~SQL[where 1 <> 2]) + assert "where 1 = 2 and id = users.id and id > 3 or true" == to_string(~SQL[where 1 = 2 and id = users.id and id > 3 or true]) + end + + test "group by" do + assert "group by id" == to_string(~SQL[group by id]) + assert "group by users.id" == to_string(~SQL[group by users.id]) + assert "group by id, users.id" == to_string(~SQL[group by id, users.id]) + end + + test "having" do + assert "having 1 = 2" == to_string(~SQL[having 1 = 2]) + assert "having 1 != 2" == to_string(~SQL[having 1 != 2]) + assert "having 1 <> 2" == to_string(~SQL[having 1 <> 2]) + end + + test "order by" do + assert "order by id" == to_string(~SQL[order by id]) + assert "order by users.id" == to_string(~SQL[order by users.id]) + assert "order by id, users.id, users.id asc, id desc" == to_string(~SQL[order by id, users.id, users.id asc, id desc]) + end + + test "offset" do + assert "offset 1" == to_string(~SQL[offset 1]) + end + + test "limit" do + assert "limit 1" == to_string(~SQL[limit 1]) + end + + test "fetch" do + assert "fetch next from users" == to_string(~SQL[fetch next from users]) + assert "fetch prior from users" == to_string(~SQL[fetch prior from users]) + assert "fetch first from users" == to_string(~SQL[fetch first from users]) + assert "fetch last from users" == to_string(~SQL[fetch last from users]) + assert "fetch absolute 1 from users" == to_string(~SQL[fetch absolute 1 from users]) + assert "fetch relative 1 from users" == to_string(~SQL[fetch relative 1 from users]) + assert "fetch 1 from users" == to_string(~SQL[fetch 1 from users]) + assert "fetch all from users" == to_string(~SQL[fetch all from users]) + assert "fetch forward from users" == to_string(~SQL[fetch forward from users]) + assert "fetch forward 1 from users" == to_string(~SQL[fetch forward 1 from users]) + assert "fetch forward all from users" == to_string(~SQL[fetch forward all from users]) + assert "fetch backward from users" == to_string(~SQL[fetch backward from users]) + assert "fetch backward 1 from users" == to_string(~SQL[fetch backward 1 from users]) + assert "fetch backward all from users" == to_string(~SQL[fetch backward all from users]) + + assert "fetch next in users" == to_string(~SQL[fetch next in users]) + assert "fetch prior in users" == to_string(~SQL[fetch prior in users]) + assert "fetch first in users" == to_string(~SQL[fetch first in users]) + assert "fetch last in users" == to_string(~SQL[fetch last in users]) + assert "fetch absolute 1 in users" == to_string(~SQL[fetch absolute 1 in users]) + assert "fetch relative 1 in users" == to_string(~SQL[fetch relative 1 in users]) + assert "fetch 1 in users" == to_string(~SQL[fetch 1 in users]) + assert "fetch all in users" == to_string(~SQL[fetch all in users]) + assert "fetch forward in users" == to_string(~SQL[fetch forward in users]) + assert "fetch forward 1 in users" == to_string(~SQL[fetch forward 1 in users]) + assert "fetch forward all in users" == to_string(~SQL[fetch forward all in users]) + assert "fetch backward in users" == to_string(~SQL[fetch backward in users]) + assert "fetch backward 1 in users" == to_string(~SQL[fetch backward 1 in users]) + assert "fetch backward all in users" == to_string(~SQL[fetch backward all in users]) + end + end + + describe "datatypes" do + test "integer" do + assert "select 1" == to_string(~SQL[select 1]) + assert "select 1000" == to_string(~SQL[select 1000]) + assert "select -1000" == to_string(~SQL[select -1000]) + assert "select +1000" == to_string(~SQL[select +1000]) + end + + test "float" do + assert "select +10.00" == to_string(~SQL[select +10.00]) + assert "select -10.00" == to_string(~SQL[select -10.00]) + end + + test "identifier" do + assert "select db.users.id" == to_string(~SQL[select db.users.id]) + assert "select db.users" == to_string(~SQL[select db.users]) + assert "select db" == to_string(~SQL[select db]) + end + + test "qouted" do + assert "select \"db.users.id\"" == to_string(~SQL[select "db.users.id"]) + assert "select 'db.users'" == to_string(~SQL[select 'db.users']) + assert "select \"db.users.id\", 'db.users'" == to_string(~SQL[select "db.users.id", 'db.users']) + end + end + + describe "interpolation" do + test "binding" do + var1 = 1 + var0 = "id" + var2 = ~SQL[select {{var0}}] + assert ["id"] == var2.params + sql = ~SQL[select {{var2}}, {{var1}}] + assert [var2, 1] == sql.params + assert "select $1, $2" == to_string(sql) + end + + test ". syntax" do + map = %{k: "v"} + sql = ~SQL[select {{map.k <> "v"}}] + assert ["vv"] == sql.params + assert "select $1" == to_string(sql) + end + + test "code" do + sql = ~SQL[select {{0}}, {{%{k: 1}}}] + assert [0, %{k: 1}] == sql.params + assert "select $1, $2" == to_string(sql) + end + + test "in" do + sql = ~SQL"select {{1}} in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select $1 = ANY($2)" == to_string(sql) + + sql = ~SQL"select {{1}} not in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select $1 != ANY($2)" == to_string(sql) + end + end + + describe "operators" do + test "=" do + assert "where id = 1" == to_string(~SQL[where id = 1]) + assert "where id = 1" == to_string(~SQL[where id=1]) + end + test "-" do + assert "where id - 1" == to_string(~SQL[where id - 1]) + assert "where id - 1" == to_string(~SQL[where id-1]) + end + test "+" do + assert "where id + 1" == to_string(~SQL[where id + 1]) + assert "where id + 1" == to_string(~SQL[where id+1]) + end + test "*" do + assert "where id * 1" == to_string(~SQL[where id * 1]) + assert "where id * 1" == to_string(~SQL[where id*1]) + end + test "/" do + assert "where id / 1" == to_string(~SQL[where id / 1]) + assert "where id / 1" == to_string(~SQL[where id/1]) + end + test "<>" do + assert "where id <> 1" == to_string(~SQL[where id <> 1]) + assert "where id <> 1" == to_string(~SQL[where id<>1]) + end + test ">" do + assert "where id > 1" == to_string(~SQL[where id > 1]) + assert "where id > 1" == to_string(~SQL[where id>1]) + end + test "<" do + assert "where id < 1" == to_string(~SQL[where id < 1]) + assert "where id < 1" == to_string(~SQL[where id<1]) + end + test ">=" do + assert "where id >= 1" == to_string(~SQL[where id >= 1]) + assert "where id >= 1" == to_string(~SQL[where id>=1]) + end + test "<=" do + assert "where id <= 1" == to_string(~SQL[where id <= 1]) + assert "where id <= 1" == to_string(~SQL[where id<=1]) + end + test "between" do + assert "where id between 1 and 2" == to_string(~SQL[where id between 1 and 2]) + assert "where id not between 1 and 2" == to_string(~SQL[where id not between 1 and 2]) + assert "where id between symmetric 1 and 2" == to_string(~SQL[where id between symmetric 1 and 2]) + assert "where id not between symmetric 1 and 2" == to_string(~SQL[where id not between symmetric 1 and 2]) + end + test "like" do + assert "where id like 1" == to_string(~SQL[where id like 1]) + end + test "ilike" do + assert "where id ilike 1" == to_string(~SQL[where id ilike 1]) + end + test "in" do + assert "where id in (1, 2)" == to_string(~SQL[where id in (1, 2)]) + end + test "is" do + assert "where id is null" == to_string(~SQL[where id is null]) + assert "where id is false" == to_string(~SQL[where id is false]) + assert "where id is true" == to_string(~SQL[where id is true]) + assert "where id is unknown" == to_string(~SQL[where id is unknown]) + + assert "where id is not null" == to_string(~SQL[where id is not null]) + assert "where id is not false" == to_string(~SQL[where id is not false]) + assert "where id is not true" == to_string(~SQL[where id is not true]) + assert "where id is not unknown" == to_string(~SQL[where id is not unknown]) + + assert "where id is distinct from 1" == to_string(~SQL[where id is distinct from 1]) + assert "where id is not distinct from 1" == to_string(~SQL[where id is not distinct from 1]) + + assert "where id isnull" == to_string(~SQL[where id isnull]) + assert "where id notnull" == to_string(~SQL[where id notnull]) + end + test "as" do + assert "select id as dd" == to_string(~SQL[select id as dd]) + end + end +end diff --git a/test/adapters/tds_test.exs b/test/adapters/tds_test.exs new file mode 100644 index 0000000..787361d --- /dev/null +++ b/test/adapters/tds_test.exs @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.Adapters.TDSTest do + use ExUnit.Case + use SQL, adapter: SQL.Adapters.TDS + + describe "with" do + test "recursive" do + assert "with recursive temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + + test "regular" do + assert "with temp (n, fact) as (select 0, 1 union all select n + 1, (n + 1) * fact from temp where n < 9)" == to_string(~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) + end + end + + describe "combinations" do + test "except" do + assert "(select id from users) except (select id from users)" == to_string(~SQL[(select id from users) except (select id from users)]) + assert "(select id from users) except select id from users" == to_string(~SQL[(select id from users) except select id from users]) + assert "select id from users except (select id from users)" == to_string(~SQL[select id from users except (select id from users)]) + assert "select id from users except select id from users" == to_string(~SQL[select id from users except select id from users]) + + assert "(select id from users) except all (select id from users)" == to_string(~SQL[(select id from users) except all (select id from users)]) + assert "(select id from users) except all select id from users" == to_string(~SQL[(select id from users) except all select id from users]) + assert "select id from users except all (select id from users)" == to_string(~SQL[select id from users except all (select id from users)]) + assert "select id from users except all select id from users" == to_string(~SQL[select id from users except all select id from users]) + end + + test "intersect" do + assert "(select id from users) intersect (select id from users)" == to_string(~SQL[(select id from users) intersect (select id from users)]) + assert "(select id from users) intersect select id from users" == to_string(~SQL[(select id from users) intersect select id from users]) + assert "select id from users intersect (select id from users)" == to_string(~SQL[select id from users intersect (select id from users)]) + assert "select id from users intersect select id from users" == to_string(~SQL[select id from users intersect select id from users]) + + assert "(select id from users) intersect all (select id from users)" == to_string(~SQL[(select id from users) intersect all (select id from users)]) + assert "(select id from users) intersect all select id from users" == to_string(~SQL[(select id from users) intersect all select id from users]) + assert "select id from users intersect all (select id from users)" == to_string(~SQL[select id from users intersect all (select id from users)]) + assert "select id from users intersect all select id from users" == to_string(~SQL[select id from users intersect all select id from users]) + end + + test "union" do + assert "(select id from users) union (select id from users)" == to_string(~SQL[(select id from users) union (select id from users)]) + assert "(select id from users) union select id from users" == to_string(~SQL[(select id from users) union select id from users]) + assert "select id from users union (select id from users)" == to_string(~SQL[select id from users union (select id from users)]) + assert "select id from users union select id from users" == to_string(~SQL[select id from users union select id from users]) + + assert "(select id from users) union all (select id from users)" == to_string(~SQL[(select id from users) union all (select id from users)]) + assert "(select id from users) union all select id from users" == to_string(~SQL[(select id from users) union all select id from users]) + assert "select id from users union all (select id from users)" == to_string(~SQL[select id from users union all (select id from users)]) + assert "select id from users union all select id from users" == to_string(~SQL[select id from users union all select id from users]) + end + end + + describe "query" do + test "select" do + assert "select id" == to_string(~SQL[select id]) + assert "select id, id as di" == to_string(~SQL[select id, id as di]) + assert "select id, (select id from users) as di" == to_string(~SQL[select id, (select id from users) as di]) + assert "select unknownn" == to_string(~SQL[select unknownn]) + assert "select truee" == to_string(~SQL[select truee]) + assert "select falsee" == to_string(~SQL[select falsee]) + assert "select nulll" == to_string(~SQL[select nulll]) + assert "select isnulll" == to_string(~SQL[select isnulll]) + assert "select notnulll" == to_string(~SQL[select notnulll]) + assert "select ascc" == to_string(~SQL[select ascc]) + assert "select descc" == to_string(~SQL[select descc]) + assert "select distinct id" == to_string(~SQL[select distinct id]) + assert "select distinct on (id, users) id" == to_string(~SQL[select distinct on (id, users) id]) + end + + test "from" do + assert "from users" == to_string(~SQL[from users]) + assert "from users u, persons p" == to_string(~SQL[from users u, persons p]) + assert "from users u" == to_string(~SQL[from users u]) + assert "from users as u" == to_string(~SQL[from users as u]) + assert "from users u" == to_string(~SQL[from users u]) + end + + test "join" do + assert "inner join users" == to_string(~SQL[inner join users]) + assert "join users" == to_string(~SQL[join users]) + assert "left outer join users" == to_string(~SQL[left outer join users]) + assert "left join users" == to_string(~SQL[left join users]) + assert "natural join users" == to_string(~SQL[natural join users]) + assert "full join users" == to_string(~SQL[full join users]) + assert "cross join users" == to_string(~SQL[cross join users]) + assert "join users u" == to_string(~SQL[join users u]) + assert "join users on id = id" == to_string(~SQL[join users on id = id]) + assert "join users u on id = id" == to_string(~SQL[join users u on id = id]) + assert "join users on (id = id)" == to_string(~SQL[join users on (id = id)]) + assert "join (select * from users) on (id = id)" == to_string(~SQL[join (select * from users) on (id = id)]) + assert "join (select * from users) u on (id = id)" == to_string(~SQL[join (select * from users) u on (id = id)]) + end + + test "where" do + assert "where 1 = 2" == to_string(~SQL[where 1 = 2]) + assert "where 1 = 2" == to_string(~SQL[where 1=2]) + assert "where 1 != 2" == to_string(~SQL[where 1 != 2]) + assert "where 1 <> 2" == to_string(~SQL[where 1 <> 2]) + assert "where 1 = 2 and id = users.id and id > 3 or true" == to_string(~SQL[where 1 = 2 and id = users.id and id > 3 or true]) + end + + test "group by" do + assert "group by id" == to_string(~SQL[group by id]) + assert "group by users.id" == to_string(~SQL[group by users.id]) + assert "group by id, users.id" == to_string(~SQL[group by id, users.id]) + end + + test "having" do + assert "having 1 = 2" == to_string(~SQL[having 1 = 2]) + assert "having 1 != 2" == to_string(~SQL[having 1 != 2]) + assert "having 1 <> 2" == to_string(~SQL[having 1 <> 2]) + end + + test "order by" do + assert "order by id" == to_string(~SQL[order by id]) + assert "order by users.id" == to_string(~SQL[order by users.id]) + assert "order by id, users.id, users.id asc, id desc" == to_string(~SQL[order by id, users.id, users.id asc, id desc]) + end + + test "offset" do + assert "offset 1" == to_string(~SQL[offset 1]) + end + + test "limit" do + assert "limit 1" == to_string(~SQL[limit 1]) + end + + test "fetch" do + assert "fetch next from users" == to_string(~SQL[fetch next from users]) + assert "fetch prior from users" == to_string(~SQL[fetch prior from users]) + assert "fetch first from users" == to_string(~SQL[fetch first from users]) + assert "fetch last from users" == to_string(~SQL[fetch last from users]) + assert "fetch absolute 1 from users" == to_string(~SQL[fetch absolute 1 from users]) + assert "fetch relative 1 from users" == to_string(~SQL[fetch relative 1 from users]) + assert "fetch 1 from users" == to_string(~SQL[fetch 1 from users]) + assert "fetch all from users" == to_string(~SQL[fetch all from users]) + assert "fetch forward from users" == to_string(~SQL[fetch forward from users]) + assert "fetch forward 1 from users" == to_string(~SQL[fetch forward 1 from users]) + assert "fetch forward all from users" == to_string(~SQL[fetch forward all from users]) + assert "fetch backward from users" == to_string(~SQL[fetch backward from users]) + assert "fetch backward 1 from users" == to_string(~SQL[fetch backward 1 from users]) + assert "fetch backward all from users" == to_string(~SQL[fetch backward all from users]) + + assert "fetch next in users" == to_string(~SQL[fetch next in users]) + assert "fetch prior in users" == to_string(~SQL[fetch prior in users]) + assert "fetch first in users" == to_string(~SQL[fetch first in users]) + assert "fetch last in users" == to_string(~SQL[fetch last in users]) + assert "fetch absolute 1 in users" == to_string(~SQL[fetch absolute 1 in users]) + assert "fetch relative 1 in users" == to_string(~SQL[fetch relative 1 in users]) + assert "fetch 1 in users" == to_string(~SQL[fetch 1 in users]) + assert "fetch all in users" == to_string(~SQL[fetch all in users]) + assert "fetch forward in users" == to_string(~SQL[fetch forward in users]) + assert "fetch forward 1 in users" == to_string(~SQL[fetch forward 1 in users]) + assert "fetch forward all in users" == to_string(~SQL[fetch forward all in users]) + assert "fetch backward in users" == to_string(~SQL[fetch backward in users]) + assert "fetch backward 1 in users" == to_string(~SQL[fetch backward 1 in users]) + assert "fetch backward all in users" == to_string(~SQL[fetch backward all in users]) + end + end + + describe "datatypes" do + test "integer" do + assert "select 1" == to_string(~SQL[select 1]) + assert "select 1000" == to_string(~SQL[select 1000]) + assert "select -1000" == to_string(~SQL[select -1000]) + assert "select +1000" == to_string(~SQL[select +1000]) + end + + test "float" do + assert "select +10.00" == to_string(~SQL[select +10.00]) + assert "select -10.00" == to_string(~SQL[select -10.00]) + end + + test "identifier" do + assert "select db.users.id" == to_string(~SQL[select db.users.id]) + assert "select db.users" == to_string(~SQL[select db.users]) + assert "select db" == to_string(~SQL[select db]) + end + + test "qouted" do + assert "select \"db.users.id\"" == to_string(~SQL[select "db.users.id"]) + assert "select 'db.users'" == to_string(~SQL[select 'db.users']) + assert "select \"db.users.id\", 'db.users'" == to_string(~SQL[select "db.users.id", 'db.users']) + end + end + + describe "interpolation" do + test "binding" do + var1 = 1 + var0 = "id" + var2 = ~SQL[select {{var0}}] + assert ["id"] == var2.params + sql = ~SQL[select {{var2}}, {{var1}}] + assert [var2, 1] == sql.params + assert "select @1, @2" == to_string(sql) + end + + test ". syntax" do + map = %{k: "v"} + sql = ~SQL[select {{map.k <> "v"}}] + assert ["vv"] == sql.params + assert "select @1" == to_string(sql) + end + + test "code" do + sql = ~SQL[select {{0}}, {{%{k: 1}}}] + assert [0, %{k: 1}] == sql.params + assert "select @1, @2" == to_string(sql) + end + + test "in" do + sql = ~SQL"select {{1}} in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select @1 in @2" == to_string(sql) + + sql = ~SQL"select {{1}} not in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select @1 not in @2" == to_string(sql) + end + end + + describe "operators" do + test "=" do + assert "where id = 1" == to_string(~SQL[where id = 1]) + assert "where id = 1" == to_string(~SQL[where id=1]) + end + test "-" do + assert "where id - 1" == to_string(~SQL[where id - 1]) + assert "where id - 1" == to_string(~SQL[where id-1]) + end + test "+" do + assert "where id + 1" == to_string(~SQL[where id + 1]) + assert "where id + 1" == to_string(~SQL[where id+1]) + end + test "*" do + assert "where id * 1" == to_string(~SQL[where id * 1]) + assert "where id * 1" == to_string(~SQL[where id*1]) + end + test "/" do + assert "where id / 1" == to_string(~SQL[where id / 1]) + assert "where id / 1" == to_string(~SQL[where id/1]) + end + test "<>" do + assert "where id <> 1" == to_string(~SQL[where id <> 1]) + assert "where id <> 1" == to_string(~SQL[where id<>1]) + end + test ">" do + assert "where id > 1" == to_string(~SQL[where id > 1]) + assert "where id > 1" == to_string(~SQL[where id>1]) + end + test "<" do + assert "where id < 1" == to_string(~SQL[where id < 1]) + assert "where id < 1" == to_string(~SQL[where id<1]) + end + test ">=" do + assert "where id >= 1" == to_string(~SQL[where id >= 1]) + assert "where id >= 1" == to_string(~SQL[where id>=1]) + end + test "<=" do + assert "where id <= 1" == to_string(~SQL[where id <= 1]) + assert "where id <= 1" == to_string(~SQL[where id<=1]) + end + test "between" do + assert "where id between 1 and 2" == to_string(~SQL[where id between 1 and 2]) + assert "where id not between 1 and 2" == to_string(~SQL[where id not between 1 and 2]) + assert "where id between symmetric 1 and 2" == to_string(~SQL[where id between symmetric 1 and 2]) + assert "where id not between symmetric 1 and 2" == to_string(~SQL[where id not between symmetric 1 and 2]) + end + test "like" do + assert "where id like 1" == to_string(~SQL[where id like 1]) + end + test "ilike" do + assert "where id ilike 1" == to_string(~SQL[where id ilike 1]) + end + test "in" do + assert "where id in (1, 2)" == to_string(~SQL[where id in (1, 2)]) + end + test "is" do + assert "where id is null" == to_string(~SQL[where id is null]) + assert "where id is false" == to_string(~SQL[where id is false]) + assert "where id is true" == to_string(~SQL[where id is true]) + assert "where id is unknown" == to_string(~SQL[where id is unknown]) + + assert "where id is not null" == to_string(~SQL[where id is not null]) + assert "where id is not false" == to_string(~SQL[where id is not false]) + assert "where id is not true" == to_string(~SQL[where id is not true]) + assert "where id is not unknown" == to_string(~SQL[where id is not unknown]) + + assert "where id is distinct from 1" == to_string(~SQL[where id is distinct from 1]) + assert "where id is not distinct from 1" == to_string(~SQL[where id is not distinct from 1]) + + assert "where id isnull" == to_string(~SQL[where id isnull]) + assert "where id notnull" == to_string(~SQL[where id notnull]) + end + test "as" do + assert "select id as dd" == to_string(~SQL[select id as dd]) + end + end +end diff --git a/test/bnf_test.exs b/test/bnf_test.exs new file mode 100644 index 0000000..d4896b8 --- /dev/null +++ b/test/bnf_test.exs @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2025 DBVisor + +defmodule SQL.BNFTest do + use ExUnit.Case + + test "parse/1" do + assert %{"" => ""} == SQL.BNF.parse(""" + ::= + + """) + end +end diff --git a/test/compiler_test.exs b/test/compiler_test.exs deleted file mode 100644 index 637407d..0000000 --- a/test/compiler_test.exs +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2025 DBVisor - -defmodule SQL.CompilerTest do - use ExUnit.Case - - test "generate/2" do - assert {{:<<>>, [], [{:b1, [], Elixir}, {:b2, [], Elixir}, {:next, [], Elixir}, {:"::", [], [{:rest, [], Elixir}, {:binary, [], Elixir}]}]}, {:and, [context: Elixir, imports: [{2, Kernel}]], [{:and, [context: Elixir, imports: [{2, Kernel}]], [{:in, [context: Elixir, imports: [{2, Kernel}]], [{:b1, [], Elixir}, ~c"oO"]}, {:in, [context: Elixir, imports: [{2, Kernel}]], [{:b2, [], Elixir}, ~c"nN"]}]}, {:in, [context: Elixir, imports: [{2, Kernel}]], [{:next, [], Elixir}, [32, 9, 13, 10, 12, 194, 160]]}]}, {:<<>>, [], [{:next, [], Elixir}, {:"::", [], [{:rest, [], Elixir}, {:binary, [], Elixir}]}]}, 2, :on} == SQL.Compiler.generate("On") - - assert {{:<<>>, [], [{:b1, [], Elixir}, {:b2, [], Elixir}, {:"::", [], [{:rest, [], Elixir}, {:binary, [], Elixir}]}]}, {:and, [context: Elixir, imports: [{2, Kernel}]], [{:and, [context: Elixir, imports: [{2, Kernel}]], [{:in, [context: Elixir, imports: [{2, Kernel}]], [{:b1, [], Elixir}, ~c"oO"]}, {:in, [context: Elixir, imports: [{2, Kernel}]], [{:b2, [], Elixir}, ~c"nN"]}]}, {:==, [context: Elixir, imports: [{2, Kernel}]], [{:rest, [], Elixir}, ""]}]}, {:rest, [], Elixir}, 2, :on} == SQL.Compiler.generate("On", eos: true) - - assert {{:<<>>, [], [{:b1, [], Elixir}, {:b2, [], Elixir}, {:"::", [], [{:rest, [], Elixir}, {:binary, [], Elixir}]}]}, {:and, [context: Elixir, imports: [{2, Kernel}]], [{:in, [context: Elixir, imports: [{2, Kernel}]], [{:b1, [], Elixir}, ~c"oO"]}, {:in, [context: Elixir, imports: [{2, Kernel}]], [{:b2, [], Elixir}, ~c"nN"]}]}, {:rest, [], Elixir}, 2, :on} == SQL.Compiler.generate("On", next: false) - end -end diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 41949a1..ff6474d 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -9,6 +9,6 @@ defmodule SQL.FormatterTest do end test "format/2 preserve interpolation" do - assert "with recursive temp (n, fact) as (select 0, 1 union all select n + \#{one}, (n + \#{one}) * fact from temp where n < 9)" == SQL.MixFormatter.format("with recursive temp(n, fact) as (select 0, 1 union all select n + \#{one}, (n + \#{one}) * fact from temp where n < 9)", []) + assert "with recursive temp (n, fact) as (select 0, 1 union all select n + {{one}}, (n + {{one}}) * fact from temp where n < 9)" == SQL.MixFormatter.format("with recursive temp(n, fact) as (select 0, 1 union all select n + {{one}}, (n + {{one}}) * fact from temp where n < 9)", []) end end diff --git a/test/parser_test.exs b/test/parser_test.exs deleted file mode 100644 index 97cebe5..0000000 --- a/test/parser_test.exs +++ /dev/null @@ -1,68 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2025 DBVisor - -defmodule SQL.ParserTest do - use ExUnit.Case - require SQL.Parser - - test "is_ident/1" do - # defguard is_ident(value) when elem(value, 0) in [:., :ident, :"", :"''", :"[]"] - assert SQL.Parser.is_ident({:ident, [], []}) - assert SQL.Parser.is_ident({:., [], [{:ident, [], []}, {:ident, [], []}]}) - assert SQL.Parser.is_ident({:., [], [{:., [], [{:ident, [], []}, {:ident, [], []}]}, {:ident, [], []}]}) - assert SQL.Parser.is_ident({:"", [], [{:ident, [], []}]}) - assert SQL.Parser.is_ident({:'', [], [{:ident, [], []}]}) - assert SQL.Parser.is_ident({:"[]", [], [{:ident, [], []}]}) - end - test "is_bool/1" do - assert SQL.Parser.is_bool({:null, [], []}) - assert SQL.Parser.is_bool({:true, [], []}) - assert SQL.Parser.is_bool({:false, [], []}) - assert SQL.Parser.is_bool({:unknown, [], []}) - end - test "is_bool_op/1" do - assert SQL.Parser.is_bool_op({:<>, [], []}) - assert SQL.Parser.is_bool_op({:<=, [], []}) - assert SQL.Parser.is_bool_op({:>=, [], []}) - assert SQL.Parser.is_bool_op({:!=, [], []}) - assert SQL.Parser.is_bool_op({:<, [], []}) - assert SQL.Parser.is_bool_op({:>, [], []}) - assert SQL.Parser.is_bool_op({:=, [], []}) - assert SQL.Parser.is_bool_op({:like, [], []}) - assert SQL.Parser.is_bool_op({:ilike, [], []}) - assert SQL.Parser.is_bool_op({:is, [], []}) - assert SQL.Parser.is_bool_op({:in, [], []}) - end - test "is_op/1" do - assert SQL.Parser.is_op({:"::", [], []}) - assert SQL.Parser.is_op({:||, [], []}) - assert SQL.Parser.is_op({:+, [], []}) - assert SQL.Parser.is_op({:-, [], []}) - assert SQL.Parser.is_op({:^, [], []}) - assert SQL.Parser.is_op({:*, [], []}) - assert SQL.Parser.is_op({:/, [], []}) - assert SQL.Parser.is_op({:%, [], []}) - assert SQL.Parser.is_op({:as, [], []}) - assert SQL.Parser.is_op({:from, [], []}) - end - test "is_lop/1" do - assert SQL.Parser.is_lop({:and, [], []}) - assert SQL.Parser.is_lop({:or, [], []}) - end - test "is_numeric/1" do - assert SQL.Parser.is_numeric({:float, [], []}) - assert SQL.Parser.is_numeric({:integer, [], []}) - end - test "is_expr/1" do - assert SQL.Parser.is_expr({:"()", [], []}) - assert SQL.Parser.is_expr({:"\#{}", [], []}) - - end - test "is_datatype/1" do - assert SQL.Parser.is_datatype({:ident, [], []}) - end - test "is_operator/1" do - assert SQL.Parser.is_operator({:ilike, [], []}) - assert SQL.Parser.is_operator({:as, [], []}) - end -end diff --git a/test/sql_test.exs b/test/sql_test.exs index 76ada98..2c665c7 100644 --- a/test/sql_test.exs +++ b/test/sql_test.exs @@ -7,12 +7,12 @@ defmodule SQLTest do def from() do var = "users" - ~SQL[from #{var} u] + ~SQL[from {{var}} u] end def where(sql) do var = "john@example.com" - sql |> ~SQL[where u.email = #{var}] + sql |> ~SQL[where u.email = {{var}}] end describe "composable" do @@ -42,18 +42,18 @@ defmodule SQLTest do test "to_sql/1" do email = "john@example.com" - assert {"select id, email from users where email = $1", ["john@example.com"]} == to_sql(~SQL""" + assert {"select id, email from users where email = ?", ["john@example.com"]} == to_sql(~SQL""" select id, email - where email = #{email} + where email = {{email}} from users """) end test "can parse multiple queries" do email = "john@example.com" - assert {"select id, email where email = $1 from users; select id from users", [email]} == to_sql(~SQL""" + assert {"select id, email from users where email = ?; select id from users", [email]} == to_sql(~SQL""" select id, email - where email = #{email} + where email = {{email}} from users; select id from users """) @@ -70,12 +70,21 @@ defmodule SQLTest do end end + test "missing ]" do + assert_raise TokenMissingError, ~r"token missing on", fn -> + ~SQL{select id in ([1)}.tokens + end + assert_raise TokenMissingError, ~r"token missing on", fn -> + ~SQL{select id from users join orgs on ([1)}.tokens + end + end + test "missing }" do assert_raise TokenMissingError, ~r"token missing on", fn -> - ~SQL[select id in #{1].tokens + ~SQL[select id in {{1].tokens end assert_raise TokenMissingError, ~r"token missing on", fn -> - ~SQL[select id from users join orgs on #{id].tokens + ~SQL[select id from users join orgs on {{id].tokens end end @@ -100,57 +109,57 @@ defmodule SQLTest do describe "with" do test "recursive" do - assert [{:with, _, [{:as, _, [{:recursive, _, [{:ident, _, [~c"temp"]}, {:"()", _, [{:",", _, [{:ident, _, [~c"n"]}]}, {:ident, _, [~c"fact"]}]}]}, {:"()", _, [{:union, _, [[{:select, _, [{:",", _, [{:integer, _, [~c"0"]}]}, {:integer, _, [~c"1"]}]}], {:all, _, [{:select, _, [{:",", _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:*, _, [{:"()", _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:ident, _, [~c"fact"]}]}]}, {:from, _, [{:ident, _, [~c"temp"]}]}, {:where, _, [{:<, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"9"]}]}]}]}]}]}]}]}] = ~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)].tokens + assert [{:with, _, [{:as, _, [{:recursive, _, [{:ident, _, [~c"temp"]}, {:parens, _, [{:ident, _, [~c"n"]}, {:comma, _, [{:ident, _, [~c"fact"]}]}]}]}, {:parens, _, [{:union, _, [[{:select, _, [{:integer, _, [~c"0"]}, {:comma, _, [{:integer, _, [~c"1"]}]}]}], [{:all, _, [{:select, _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}, {:comma, _, [{:*, _, [{:parens, _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:ident, _, [~c"fact"]}]}]}]}, {:from, _, [{:ident, _, [~c"temp"]}]}, {:where, _, [{:<, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"9"]}]}]}]}]]}]}]}]}] = ~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)].tokens end test "regular" do - assert [{:with, _, [{:as, _, [[{:ident, _, [~c"temp"]}, {:"()", _, [{:",", _, [{:ident, _, [~c"n"]}]}, {:ident, _, [~c"fact"]}]}], {:"()", _, [{:union, _, [[{:select, _, [{:",", _, [{:integer, _, [~c"0"]}]}, {:integer, _, [~c"1"]}]}], {:all, _, [{:select, _, [{:",", _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:*, _, [{:"()", _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:ident, _, [~c"fact"]}]}]}, {:from, _, [{:ident, _, [~c"temp"]}]}, {:where, _, [{:<, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"9"]}]}]}]}]}]}]}]}] = ~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)].tokens + assert [{:with, _, [{:as, _, [[{:ident, _, [~c"temp"]}, {:parens, _, [{:ident, _, [~c"n"]}, {:comma, _, [{:ident, _, [~c"fact"]}]}]}], {:parens, _, [{:union, _, [[{:select, _, [{:integer, _, [~c"0"]}, {:comma, _, [{:integer, _, [~c"1"]}]}]}], [{:all, _, [{:select, _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}, {:comma, _, [{:*, _, [{:parens, _, [{:+, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"1"]}]}]}, {:ident, _, [~c"fact"]}]}]}]}, {:from, _, [{:ident, _, [~c"temp"]}]}, {:where, _, [{:<, _, [{:ident, _, [~c"n"]}, {:integer, _, [~c"9"]}]}]}]}]]}]}]}]}] = ~SQL[with temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)].tokens end end describe "combinations" do test "except" do - assert [{:except, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) except (select id from users)].tokens - assert [{:except, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) except select id from users].tokens - assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users except (select id from users)].tokens + assert [{:except, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) except (select id from users)].tokens + assert [{:except, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) except select id from users].tokens + assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users except (select id from users)].tokens assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[select id from users except select id from users].tokens - assert [{:except, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[(select id from users) except all (select id from users)].tokens - assert [{:except, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) except all select id from users].tokens - assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[select id from users except all (select id from users)].tokens - assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users except all select id from users].tokens + assert [{:except, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[(select id from users) except all (select id from users)].tokens + assert [{:except, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) except all select id from users].tokens + assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[select id from users except all (select id from users)].tokens + assert [{:except, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users except all select id from users].tokens end test "intersect" do - assert [{:intersect, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) intersect (select id from users)].tokens - assert [{:intersect, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) intersect select id from users].tokens - assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users intersect (select id from users)].tokens + assert [{:intersect, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) intersect (select id from users)].tokens + assert [{:intersect, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) intersect select id from users].tokens + assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users intersect (select id from users)].tokens assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[select id from users intersect select id from users].tokens - assert [{:intersect, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[(select id from users) intersect all (select id from users)].tokens - assert [{:intersect, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) intersect all select id from users].tokens - assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[select id from users intersect all (select id from users)].tokens - assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users intersect all select id from users].tokens + assert [{:intersect, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[(select id from users) intersect all (select id from users)].tokens + assert [{:intersect, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) intersect all select id from users].tokens + assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[select id from users intersect all (select id from users)].tokens + assert [{:intersect, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users intersect all select id from users].tokens end test "union" do - assert [{:union, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) union (select id from users)].tokens - assert [{:union, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) union select id from users].tokens - assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users union (select id from users)].tokens + assert [{:union, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) union (select id from users)].tokens + assert [{:union, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[(select id from users) union select id from users].tokens + assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users union (select id from users)].tokens assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]]}] = ~SQL[select id from users union select id from users].tokens - assert [{:union, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[(select id from users) union all (select id from users)].tokens - assert [{:union, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[(select id from users) union all select id from users].tokens - assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]}] = ~SQL[select id from users union all (select id from users)].tokens - assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], {:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}] = ~SQL[select id from users union all select id from users].tokens + assert [{:union, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[(select id from users) union all (select id from users)].tokens + assert [{:union, _, [[{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[(select id from users) union all select id from users].tokens + assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]}]]}] = ~SQL[select id from users union all (select id from users)].tokens + assert [{:union, _, [[{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}], [{:all, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}]]}] = ~SQL[select id from users union all select id from users].tokens end end describe "query" do test "select" do assert [{:select, _, [{:ident, _, [~c"id"]}]}] = ~SQL[select id].tokens - assert [{:select, _, [{:",", _, [{:ident, _, [~c"id"]}]}, {:as, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"di"]}]}]}] = ~SQL[select id, id as di].tokens - assert [{:select, _, [{:",", _, [{:ident, _, [~c"id"]}]}, {:as, _, [{:"()", _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:ident, _, [~c"di"]}]}]}] = ~SQL[select id, (select id from users) as di].tokens + assert [{:select, _, [{:ident, _, [~c"id"]}, {:comma, _, [{:as, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"di"]}]}]}]}] = ~SQL[select id, id as di].tokens + assert [{:select, _, [{:ident, _, [~c"id"]}, {:comma, _, [{:as, _, [{:parens, _, [{:select, _, [{:ident, _, [~c"id"]}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:ident, _, [~c"di"]}]}]}]}] = ~SQL[select id, (select id from users) as di].tokens assert [{:select, _, [{:ident, _, [~c"unknownn"]}]}] = ~SQL[select unknownn].tokens assert [{:select, _, [{:ident, _, [~c"truee"]}]}] = ~SQL[select truee].tokens assert [{:select, _, [{:ident, _, [~c"falsee"]}]}] = ~SQL[select falsee].tokens @@ -160,7 +169,7 @@ defmodule SQLTest do assert [{:select, _, [{:ident, _, [~c"ascc"]}]}] = ~SQL[select ascc].tokens assert [{:select, _, [{:ident, _, [~c"descc"]}]}] = ~SQL[select descc].tokens assert [{:select, _, [{:distinct, _, []}, {:ident, _, [~c"id"]}]}] = ~SQL[select distinct id].tokens - assert [{:select, _, [{:distinct, _, [{:on, _, [{:"()", _, [{:",", _, [{:ident, _, [~c"id"]}]}, {:ident, _, [~c"users"]}]}]}]}, {:ident, _, [~c"id"]}]}] = ~SQL[select distinct on (id, users) id].tokens + assert [{:select, _, [{:distinct, _, [{:on, _, [{:parens, _, [{:ident, _, [~c"id"]}, {:comma, _, [{:ident, _, [~c"users"]}]}]}]}]}, {:ident, _, [~c"id"]}]}] = ~SQL[select distinct on (id, users) id].tokens end test "from" do @@ -170,19 +179,20 @@ defmodule SQLTest do end test "join" do - assert [{:join, _, [[{:inner, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[inner join users].tokens + assert [{:join, _, [[inner: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[inner join users].tokens assert [{:join, _, [{:ident, _, [~c"users"]}]}] = ~SQL[join users].tokens - assert [{:join, _, [[{:left, _, []}, {:outer, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[left outer join users].tokens - assert [{:join, _, [[{:left, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[left join users].tokens - assert [{:join, _, [[{:natural, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[natural join users].tokens - assert [{:join, _, [[{:full, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[full join users].tokens - assert [{:join, _, [[{:cross, _, []}], {:ident, _, [~c"users"]}]}] = ~SQL[cross join users].tokens + assert [{:join, _, [[left: _, outer: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[left outer join users].tokens + assert [{:join, _, [[left: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[left join users].tokens + assert [{:join, _, [[natural: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[natural join users].tokens + assert [{:join, _, [[natural: _, left: _, outer: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[natural left outer join users].tokens + assert [{:join, _, [[full: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[full join users].tokens + assert [{:join, _, [[cross: _], [{:ident, _, [~c"users"]}]]}] = ~SQL[cross join users].tokens assert [{:join, _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"u"]}]}] = ~SQL[join users u].tokens assert [{:join, _, [{:on, _, [{:ident, _, [~c"users"]}, {:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}] = ~SQL[join users on id = id].tokens assert [{:join, _, [{:on, _, [[{:ident, _, [~c"users"]}, {:ident, _, [~c"u"]}], {:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}] = ~SQL[join users u on id = id].tokens - assert [{:join, _, [{:on, _, [{:ident, _, [~c"users"]}, {:"()", _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join users on (id = id)].tokens - assert [{:join, _, [{:on, _, [{:"()", _, [{:select, _, [{:*, _, []}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:"()", _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join (select * from users) on (id = id)].tokens - assert [{:join, _, [{:on, _, [[{:"()", _, [{:select, _, [{:*, _, []}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:ident, _, [~c"u"]}], {:"()", _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join (select * from users) u on (id = id)].tokens + assert [{:join, _, [{:on, _, [{:ident, _, [~c"users"]}, {:parens, _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join users on (id = id)].tokens + assert [{:join, _, [{:on, _, [{:parens, _, [{:select, _, [{:*, _, _}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:parens, _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join (select * from users) on (id = id)].tokens + assert [{:join, _, [{:on, _, [[{:parens, _, [{:select, _, [{:*, _, _}]}, {:from, _, [{:ident, _, [~c"users"]}]}]}, {:ident, _, [~c"u"]}], {:parens, _, [{:=, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[join (select * from users) u on (id = id)].tokens end test "where" do @@ -196,7 +206,7 @@ defmodule SQLTest do test "group by" do assert [{:group, _, [{:by, _, [{:ident, _, [~c"id"]}]}]}] = ~SQL[group by id].tokens assert [{:group, _, [{:by, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}]}] = ~SQL[group by users.id].tokens - assert [{:group, _, [{:by, _, [{:",", _, [{:ident, _, [~c"id"]}]}, {:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}]}] = ~SQL[group by id, users.id].tokens + assert [{:group, _, [{:by, _, [{:ident, _, [~c"id"]}, {:comma, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}]}]}] = ~SQL[group by id, users.id].tokens end test "having" do @@ -208,7 +218,9 @@ defmodule SQLTest do test "order by" do assert [{:order, _, [{:by, _, [{:ident, _, [~c"id"]}]}]}] = ~SQL[order by id].tokens assert [{:order, _, [{:by, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}]}] = ~SQL[order by users.id].tokens - assert [{:order, _, [{:by, _, [{:",", _, [{:ident, _, [~c"id"]}]}, {:",", _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}, {:",", _, [{:asc, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}]}, {:desc, _, [{:ident, _, [~c"id"]}]}]}]}] = ~SQL[order by id, users.id, users.id asc, id desc].tokens + assert [{:order, _, [{:by, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}, {:asc, _, _}, {:nulls, _, _}, {:first, _, _}]}]}] = ~SQL[order by users.id asc nulls first].tokens + assert [{:order, _, [{:by, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}, {:desc, _, _}, {:nulls, _, _}, {:last, _, _}]}]}] = ~SQL[order by users.id desc nulls last].tokens + assert [{:order, _, [{:by, _, [{:ident, _, [~c"id"]}, {:comma, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}]}, {:comma, _, [{:., _, [{:ident, _, [~c"users"]}, {:ident, _, [~c"id"]}]}, {:asc, _, _}]}, {:comma, _, [{:ident, _, [~c"id"]}, {:desc, _, _}]}]}]}] = ~SQL[order by id, users.id, users.id asc, id desc].tokens end test "offset" do @@ -235,20 +247,20 @@ defmodule SQLTest do assert [{:fetch, _, [{:backward, _, [{:integer, _, [~c"1"]}]}]}, {:from, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch backward 1 from users].tokens assert [{:fetch, _, [{:backward, _, [{:all, _, []}]}]}, {:from, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch backward all from users].tokens - assert [{:fetch, _, [{:in, _, [{:next, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch next in users].tokens - assert [{:fetch, _, [{:in, _, [{:prior, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch prior in users].tokens - assert [{:fetch, _, [{:in, _, [{:first, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch first in users].tokens - assert [{:fetch, _, [{:in, _, [{:last, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch last in users].tokens - assert [{:fetch, _, [{:in, _, [{:absolute, _, [{:integer, _, [~c"1"]}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch absolute 1 in users].tokens - assert [{:fetch, _, [{:in, _, [{:relative, _, [{:integer, _, [~c"1"]}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch relative 1 in users].tokens - assert [{:fetch, _, [{:in, _, [{:integer, _, [~c"1"]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch 1 in users].tokens - assert [{:fetch, _, [{:in, _, [{:all, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch all in users].tokens - assert [{:fetch, _, [{:in, _, [{:forward, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch forward in users].tokens - assert [{:fetch, _, [{:in, _, [{:forward, _, [{:integer, _, [~c"1"]}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch forward 1 in users].tokens - assert [{:fetch, _, [{:in, _, [{:forward, _, [{:all, _, []}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch forward all in users].tokens - assert [{:fetch, _, [{:in, _, [{:backward, _, []}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch backward in users].tokens - assert [{:fetch, _, [{:in, _, [{:backward, _, [{:integer, _, [~c"1"]}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch backward 1 in users].tokens - assert [{:fetch, _, [{:in, _, [{:backward, _, [{:all, _, []}]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[fetch backward all in users].tokens + assert [{:fetch, _, [{:next, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch next in users].tokens + assert [{:fetch, _, [{:prior, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch prior in users].tokens + assert [{:fetch, _, [{:first, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch first in users].tokens + assert [{:fetch, _, [{:last, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch last in users].tokens + assert [{:fetch, _, [{:absolute, _, [{:integer, _, [~c"1"]}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch absolute 1 in users].tokens + assert [{:fetch, _, [{:relative, _, [{:integer, _, [~c"1"]}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch relative 1 in users].tokens + assert [{:fetch, _, [{:integer, _, [~c"1"]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch 1 in users].tokens + assert [{:fetch, _, [{:all, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch all in users].tokens + assert [{:fetch, _, [{:forward, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch forward in users].tokens + assert [{:fetch, _, [{:forward, _, [{:integer, _, [~c"1"]}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch forward 1 in users].tokens + assert [{:fetch, _, [{:forward, _, [{:all, _, []}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch forward all in users].tokens + assert [{:fetch, _, [{:backward, _, []}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch backward in users].tokens + assert [{:fetch, _, [{:backward, _, [{:integer, _, [~c"1"]}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch backward 1 in users].tokens + assert [{:fetch, _, [{:backward, _, [{:all, _, []}]}]}, {:in, _, [{:ident, _, [~c"users"]}]}] = ~SQL[fetch backward all in users].tokens end end @@ -266,26 +278,26 @@ defmodule SQLTest do end test "identifier" do - assert [{:select, _, [{:., _, [{:., _, [{:"[]", _, [{:ident, _, [~c"db"]}]}, {:"[]", _, [{:ident, _, [~c"users"]}]}]}, {:"[]", _, [{:ident, _, [~c"id"]}]}]}]}] = ~SQL{select [db].[users].[id]}.tokens - assert [{:select, _, [{:., _, [{:., _, [{:"", _, [{:ident, _, [~c"db"]}]}, {:"", _, [{:ident, _, [~c"users"]}]}]}, {:"", _, [{:ident, _, [~c"id"]}]}]}]}] = ~SQL[select "db"."users"."id"].tokens + assert [{:select, _, [{:., _, [{:., _, [{:bracket, _, [{:ident, _, [~c"db"]}]}, {:bracket, _, [{:ident, _, [~c"users"]}]}]}, {:bracket, _, [{:ident, _, [~c"id"]}]}]}]}] = ~SQL{select [db].[users].[id]}.tokens + assert [{:select, _, [{:., _, [{:., _, [{:double_quote, _, [~c"db"]}, {:double_quote, _, [~c"users"]}]}, {:double_quote, _, [~c"id"]}]}]}] = ~SQL[select "db"."users"."id"].tokens assert [{:select, _, [{:., _, [{:., _, [{:ident, _, [~c"db"]}, {:ident, _, [~c"users"]}]}, {:ident, _, [~c"id"]}]}]}] = ~SQL[select db.users.id].tokens assert [{:select, _, [{:., _, [{:ident, _, [~c"db"]}, {:ident, _, [~c"users"]}]}]}] = ~SQL[select db.users].tokens assert [{:select, _, [{:ident, _, [~c"db"]}]}] = ~SQL[select db].tokens end - test "qouted" do - assert [{:select, _, [{:"", _, [{:ident, _, [~c"db.users.id"]}]}]}] = ~SQL[select "db.users.id"].tokens - assert [{:select, _, [{:"''", _, [{:ident, _, [~c"db.users"]}]}]}] = ~SQL[select 'db.users'].tokens - assert [{:select, _, [{:",", _, [{:"", _, [{:ident, _, [~c"db.users.id"]}]}]}, {:"''", _, [{:ident, _, [~c"db.users"]}]}]}] = ~SQL[select "db.users.id", 'db.users'].tokens + test "quoted" do + assert [{:select, _, [{:double_quote, _, [~c"db.users.id"]}]}] = ~SQL[select "db.users.id"].tokens + assert [{:select, _, [{:quote, _, [~c"db.users"]}]}] = ~SQL[select 'db.users'].tokens + assert [{:select, _, [{:double_quote, _, [~c"db.users.id"]}, {:comma, _, [{:quote, _, [~c"db.users"]}]}]}] = ~SQL[select "db.users.id", 'db.users'].tokens end end test "interpolation" do var = 1 - assert [{:select, _, [{:binding, _, [1]}]}] = ~SQL[select #{var}].tokens - assert [{:select, _, [{:binding, _, [1]}]}] = ~SQL[select #{ + assert [{:select, _, [{:binding, _, [1]}]}] = ~SQL[select {{var}}].tokens + assert [{:select, _, [{:binding, _, [1]}]}] = ~SQL[select {{ {} - }].tokens + }}].tokens end describe "operators" do @@ -342,7 +354,7 @@ defmodule SQLTest do assert [{:where, _, [{:ilike, _, [{:ident, _, [~c"id"]}, {:integer, _, [~c"1"]}]}]}] = ~SQL[where id ilike 1].tokens end test "in" do - assert [{:where, _, [{:in, _, [{:ident, _, [~c"id"]}, {:"()", _, [{:",", _, [{:integer, _, [~c"1"]}]}, {:integer, _, [~c"2"]}]}]}]}] = ~SQL[where id in (1, 2)].tokens + assert [{:where, _, [{:in, _, [{:ident, _, [~c"id"]}, {:parens, _, [{:integer, _, [~c"1"]}, {:comma, _, [{:integer, _, [~c"2"]}]}]}]}]}] = ~SQL[where id in (1, 2)].tokens end test "is" do assert [{:where, _, [{:is, _, [{:ident, _, [~c"id"]}, {:null, _, []}]}]}] = ~SQL[where id is null].tokens @@ -356,7 +368,7 @@ defmodule SQLTest do assert [{:where, _, [{:is, _, [{:ident, _, [~c"id"]}, {:not, _, [{:unknown, _, []}]}]}]}] = ~SQL[where id is not unknown].tokens assert [{:where, _, [{:is, _, [{:ident, _, [~c"id"]}, {:distinct, _, [{:from, _, [{:integer, _, [~c"1"]}]}]}]}]}] = ~SQL[where id is distinct from 1].tokens - assert [{:where, _, [{:is, _, [{:ident, _, [~c"id"]}, {:not, _, [{:distinct, _, []}]}, {:from, _, [{:integer, _, [~c"1"]}]}]}]}] = ~SQL[where id is not distinct from 1].tokens + assert [{:where, _, [{:is, _, [{:ident, _, [~c"id"]}, {:not, _, [{:distinct, _, [{:from, _, [{:integer, _, [~c"1"]}]}]}]}]}]}] = ~SQL[where id is not distinct from 1].tokens assert [{:where, _, [{:isnull, _, [{:ident, _, [~c"id"]}]}]}] = ~SQL[where id isnull].tokens assert [{:where, _, [{:notnull, _, [{:ident, _, [~c"id"]}]}]}] = ~SQL[where id notnull].tokens @@ -365,4 +377,35 @@ defmodule SQLTest do assert [{:select, _, [{:as, _, [{:ident, _, [~c"id"]}, {:ident, _, [~c"dd"]}]}]}] = ~SQL[select id as dd].tokens end end + + describe "functions" do + test "avg" do + assert "select avg(id)" == to_string(~SQL[select avg(id)]) + end + test "any" do + assert "select any(select *)" == to_string(~SQL[select any(select *)]) + end + test "all" do + assert "select all(select *)" == to_string(~SQL[select all(select *)]) + end + test "count" do + assert "select count(*)" == to_string(~SQL[select count(*)]) + assert "select count(id)" == to_string(~SQL[select count(id)]) + end + test "coalesce" do + assert "select coalesce(a, b)" == to_string(~SQL[select coalesce(a, b)]) + end + test "exists" do + assert "select exists(select *)" == to_string(~SQL[select exists(select *)]) + end + test "min" do + assert "select min(a, b)" == to_string(~SQL[select min(a, b)]) + end + test "max" do + assert "select max(a, b)" == to_string(~SQL[select max(a, b)]) + end + test "sum" do + assert "select sum(id)" == to_string(~SQL[select sum(id)]) + end + end end diff --git a/test/string_test.exs b/test/string_test.exs index 13c1655..1f9040d 100644 --- a/test/string_test.exs +++ b/test/string_test.exs @@ -191,30 +191,34 @@ defmodule SQL.StringTest do test "binding" do var1 = 1 var0 = "id" - var2 = ~SQL[select #{var0}] + var2 = ~SQL[select {{var0}}] assert ["id"] == var2.params - sql = ~SQL[select #{var2}, #{var1}] + sql = ~SQL[select {{var2}}, {{var1}}] assert [var2, 1] == sql.params - assert "select $1, $2" == to_string(sql) + assert "select ?, ?" == to_string(sql) end test ". syntax" do map = %{k: "v"} - sql = ~SQL[select #{map.k <> "v"}] + sql = ~SQL[select {{map.k <> "v"}}] assert ["vv"] == sql.params - assert "select $1" == to_string(sql) + assert "select ?" == to_string(sql) end test "code" do - sql = ~SQL[select #{0}, #{%{k: 1}}] + sql = ~SQL[select {{0}}, {{%{k: 1}}}] assert [0, %{k: 1}] == sql.params - assert "select $1, $2" == to_string(sql) + assert "select ?, ?" == to_string(sql) end test "in" do - sql = ~SQL"select #{1} in #{[1, 2]}" + sql = ~SQL"select {{1}} in {{[1, 2]}}" assert [1, [1, 2]] == sql.params - assert "select $1 = ANY($2)" == to_string(sql) + assert "select ? in ?" == to_string(sql) + + sql = ~SQL"select {{1}} not in {{[1, 2]}}" + assert [1, [1, 2]] == sql.params + assert "select ? not in ?" == to_string(sql) end end