Use prepared statement with mysql

This commit is contained in:
Paweł Chmielowski 2023-07-25 16:52:49 +02:00
parent db03c7428c
commit 3710dc1e3b
4 changed files with 41 additions and 7 deletions

View File

@ -138,7 +138,7 @@ defmodule Ejabberd.MixProject do
{config(:zlib), {:ezlib, "~> 1.0"}},
{if_version_below('22', true), {:lager, "~> 3.9.1"}},
{config(:lua), {:luerl, "~> 1.0"}},
{config(:mysql), {:p1_mysql, "~> 1.0.20"}},
{config(:mysql), {:p1_mysql, git: "https://github.com/processone/p1_mysql.git", ref: "150c15b96d2fb84cb00e07cc53cd97ec72b77efc"}},
{config(:pgsql), {:p1_pgsql, "~> 1.1"}},
{config(:sqlite), {:sqlite3, "~> 1.1"}},
{config(:stun), {:stun, "~> 1.0"}}], do:

View File

@ -63,7 +63,7 @@
{mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.15"}}},
{p1_acme, ".*", {git, "https://github.com/processone/p1_acme", {tag, "1.0.22"}}},
{if_var_true, mysql,
{p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.21"}}}},
{p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", "150c15b96d2fb84cb00e07cc53cd97ec72b77efc"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.11"}}},
{if_var_true, pgsql,
{p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.22"}}}},

View File

@ -683,7 +683,14 @@ sql_query_internal(#sql_query{} = Query) ->
pgsql_sql_query(Query)
end;
mysql ->
generic_sql_query(Query);
case {Query#sql_query.flags, ejabberd_option:sql_prepared_statements(State#state.host)} of
{1, _} ->
generic_sql_query(Query);
{_, false} ->
generic_sql_query(Query);
_ ->
mysql_prepared_execute(Query, State)
end;
sqlite ->
sqlite_sql_query(Query)
end
@ -862,6 +869,24 @@ pgsql_execute_sql_query(SQLQuery, State) ->
Res = pgsql_execute_to_odbc(ExecuteRes),
sql_query_format_res(Res, SQLQuery).
mysql_prepared_execute(#sql_query{hash = Hash} = Query, State) ->
ValEsc = #sql_escape{like_escape = fun() -> ignore end, _ = fun(X) -> X end},
TypesEsc = #sql_escape{string = fun(_) -> string end,
integer = fun(_) -> integer end,
boolean = fun(_) -> bool end,
in_array_string = fun(_) -> string end,
like_escape = fun() -> ignore end},
Val = [X || X <- (Query#sql_query.args)(ValEsc), X /= ignore],
Types = [X || X <- (Query#sql_query.args)(TypesEsc), X /= ignore],
QueryFn = fun() ->
PrepEsc = #sql_escape{like_escape = fun() -> <<>> end, _ = fun(_) -> <<"?">> end},
(Query#sql_query.format_query)((Query#sql_query.args)(PrepEsc))
end,
QueryTimeout = query_timeout(State#state.host),
Res = p1_mysql_conn:prepared_query(State#state.db_ref, QueryFn, Hash, Val, Types,
self(), [{timeout, QueryTimeout - 1000}]),
Res2 = mysql_to_odbc(Res),
sql_query_format_res(Res2, Query).
sql_query_format_res({selected, _, Rows}, SQLQuery) ->
Res =

View File

@ -42,7 +42,8 @@
used_vars = [],
use_new_schema,
need_timestamp_pass = false,
need_array_pass = false}).
need_array_pass = false,
has_list = false}).
-define(QUERY_RECORD, "sql_query").
@ -268,9 +269,12 @@ parse1([$@, $( | S], Acc, State) ->
Convert =
case Type of
integer ->
erl_syntax:application(
erl_syntax:atom(binary_to_integer),
[EVar]);
erl_syntax:if_expr([
erl_syntax:clause(
[erl_syntax:application(erl_syntax:atom(is_binary), [EVar])],
[erl_syntax:application(erl_syntax:atom(binary_to_integer), [EVar])]),
erl_syntax:clause([erl_syntax:atom(true)], [EVar])
]);
string ->
EVar;
timestamp ->
@ -339,6 +343,7 @@ parse1([$%, $( | S], Acc, State) ->
erl_syntax:variable(Name)]),
State2#state{'query' = [[{var, Var, Type}] | State2#state.'query'],
need_array_pass = true,
has_list = true,
args = [[Convert, ConvertArr] | State2#state.args],
params = [Var | State2#state.params],
param_pos = State2#state.param_pos + 1,
@ -467,6 +472,7 @@ make_sql_query(State, Type) ->
Hash = erlang:phash2(State#state{loc = undefined, use_new_schema = true}),
SHash = <<"Q", (integer_to_binary(Hash))/binary>>,
Query = pack_query(State#state.'query'),
Flags = case State#state.has_list of true -> 1; _ -> 0 end,
EQuery =
lists:flatmap(
fun({str, S}) ->
@ -515,6 +521,9 @@ make_sql_query(State, Type) ->
none,
[erl_syntax:tuple(State#state.res)]
)])),
erl_syntax:record_field(
erl_syntax:atom(flags),
erl_syntax:abstract(Flags)),
erl_syntax:record_field(
erl_syntax:atom(loc),
erl_syntax:abstract({get(?MOD), State#state.loc}))