mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Use SQL ESCAPE statement only with MSSQL and SQLite, improve compatibility with CockroachDB (#3074)
This commit is contained in:
parent
87ea71c3c9
commit
b2f536ec8b
@ -38,4 +38,5 @@
|
|||||||
-record(sql_escape, {string :: fun((binary()) -> binary()),
|
-record(sql_escape, {string :: fun((binary()) -> binary()),
|
||||||
integer :: fun((integer()) -> binary()),
|
integer :: fun((integer()) -> binary()),
|
||||||
boolean :: fun((boolean()) -> binary()),
|
boolean :: fun((boolean()) -> binary()),
|
||||||
in_array_string :: fun((binary()) -> binary())}).
|
in_array_string :: fun((binary()) -> binary()),
|
||||||
|
like_escape :: fun(() -> binary())}).
|
||||||
|
@ -205,12 +205,12 @@ list_users(LServer,
|
|||||||
[{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
|
[{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
|
||||||
when is_binary(Prefix) and is_integer(Limit) and
|
when is_binary(Prefix) and is_integer(Limit) and
|
||||||
is_integer(Offset) ->
|
is_integer(Offset) ->
|
||||||
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
|
SPrefix = ejabberd_sql:escape_like_arg(Prefix),
|
||||||
SPrefix2 = <<SPrefix/binary, $%>>,
|
SPrefix2 = <<SPrefix/binary, $%>>,
|
||||||
ejabberd_sql:sql_query(
|
ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
?SQL("select @(username)s from users "
|
?SQL("select @(username)s from users "
|
||||||
"where username like %(SPrefix2)s escape '^' and %(LServer)H "
|
"where username like %(SPrefix2)s %ESCAPE and %(LServer)H "
|
||||||
"order by username "
|
"order by username "
|
||||||
"limit %(Limit)d offset %(Offset)d")).
|
"limit %(Limit)d offset %(Offset)d")).
|
||||||
|
|
||||||
@ -235,12 +235,12 @@ users_number(LServer) ->
|
|||||||
|
|
||||||
users_number(LServer, [{prefix, Prefix}])
|
users_number(LServer, [{prefix, Prefix}])
|
||||||
when is_binary(Prefix) ->
|
when is_binary(Prefix) ->
|
||||||
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
|
SPrefix = ejabberd_sql:escape_like_arg(Prefix),
|
||||||
SPrefix2 = <<SPrefix/binary, $%>>,
|
SPrefix2 = <<SPrefix/binary, $%>>,
|
||||||
ejabberd_sql:sql_query(
|
ejabberd_sql:sql_query(
|
||||||
LServer,
|
LServer,
|
||||||
?SQL("select @(count(*))d from users "
|
?SQL("select @(count(*))d from users "
|
||||||
"where username like %(SPrefix2)s escape '^' and %(LServer)H"));
|
"where username like %(SPrefix2)s %ESCAPE and %(LServer)H"));
|
||||||
users_number(LServer, []) ->
|
users_number(LServer, []) ->
|
||||||
users_number(LServer).
|
users_number(LServer).
|
||||||
|
|
||||||
|
@ -227,6 +227,8 @@ escape_like_arg(S) when is_binary(S) ->
|
|||||||
escape_like_arg($%) -> <<"\\%">>;
|
escape_like_arg($%) -> <<"\\%">>;
|
||||||
escape_like_arg($_) -> <<"\\_">>;
|
escape_like_arg($_) -> <<"\\_">>;
|
||||||
escape_like_arg($\\) -> <<"\\\\">>;
|
escape_like_arg($\\) -> <<"\\\\">>;
|
||||||
|
escape_like_arg($[) -> <<"\\[">>; % For MSSQL
|
||||||
|
escape_like_arg($]) -> <<"\\]">>;
|
||||||
escape_like_arg(C) when is_integer(C), C >= 0, C =< 255 -> <<C>>.
|
escape_like_arg(C) when is_integer(C), C >= 0, C =< 255 -> <<C>>.
|
||||||
|
|
||||||
escape_like_arg_circumflex(S) when is_binary(S) ->
|
escape_like_arg_circumflex(S) when is_binary(S) ->
|
||||||
@ -718,7 +720,8 @@ generic_escape() ->
|
|||||||
boolean = fun(true) -> <<"1">>;
|
boolean = fun(true) -> <<"1">>;
|
||||||
(false) -> <<"0">>
|
(false) -> <<"0">>
|
||||||
end,
|
end,
|
||||||
in_array_string = fun(X) -> <<"'", (escape(X))/binary, "'">> end
|
in_array_string = fun(X) -> <<"'", (escape(X))/binary, "'">> end,
|
||||||
|
like_escape = fun() -> <<"">> end
|
||||||
}.
|
}.
|
||||||
|
|
||||||
pgsql_sql_query(SQLQuery) ->
|
pgsql_sql_query(SQLQuery) ->
|
||||||
@ -736,7 +739,8 @@ pgsql_escape() ->
|
|||||||
boolean = fun(true) -> <<"1">>;
|
boolean = fun(true) -> <<"1">>;
|
||||||
(false) -> <<"0">>
|
(false) -> <<"0">>
|
||||||
end,
|
end,
|
||||||
in_array_string = fun(X) -> <<"E'", (escape(X))/binary, "'">> end
|
in_array_string = fun(X) -> <<"E'", (escape(X))/binary, "'">> end,
|
||||||
|
like_escape = fun() -> <<"">> end
|
||||||
}.
|
}.
|
||||||
|
|
||||||
sqlite_sql_query(SQLQuery) ->
|
sqlite_sql_query(SQLQuery) ->
|
||||||
@ -754,7 +758,8 @@ sqlite_escape() ->
|
|||||||
boolean = fun(true) -> <<"1">>;
|
boolean = fun(true) -> <<"1">>;
|
||||||
(false) -> <<"0">>
|
(false) -> <<"0">>
|
||||||
end,
|
end,
|
||||||
in_array_string = fun(X) -> <<"'", (standard_escape(X))/binary, "'">> end
|
in_array_string = fun(X) -> <<"'", (standard_escape(X))/binary, "'">> end,
|
||||||
|
like_escape = fun() -> <<"ESCAPE '\\'">> end
|
||||||
}.
|
}.
|
||||||
|
|
||||||
standard_escape(S) ->
|
standard_escape(S) ->
|
||||||
@ -767,9 +772,18 @@ mssql_sql_query(SQLQuery) ->
|
|||||||
sqlite_sql_query(SQLQuery).
|
sqlite_sql_query(SQLQuery).
|
||||||
|
|
||||||
pgsql_prepare(SQLQuery, State) ->
|
pgsql_prepare(SQLQuery, State) ->
|
||||||
Escape = #sql_escape{_ = fun(X) -> X end},
|
Escape = #sql_escape{_ = fun(_) -> arg end,
|
||||||
N = length((SQLQuery#sql_query.args)(Escape)),
|
like_escape = fun() -> escape end},
|
||||||
Args = [<<$$, (integer_to_binary(I))/binary>> || I <- lists:seq(1, N)],
|
{RArgs, _} =
|
||||||
|
lists:foldl(
|
||||||
|
fun(arg, {Acc, I}) ->
|
||||||
|
{[<<$$, (integer_to_binary(I))/binary>> | Acc], I + 1};
|
||||||
|
(escape, {Acc, I}) ->
|
||||||
|
{[<<"">> | Acc], I}
|
||||||
|
end, {[], 1}, (SQLQuery#sql_query.args)(Escape)),
|
||||||
|
Args = lists:reverse(RArgs),
|
||||||
|
%N = length((SQLQuery#sql_query.args)(Escape)),
|
||||||
|
%Args = [<<$$, (integer_to_binary(I))/binary>> || I <- lists:seq(1, N)],
|
||||||
Query = (SQLQuery#sql_query.format_query)(Args),
|
Query = (SQLQuery#sql_query.format_query)(Args),
|
||||||
pgsql:prepare(State#state.db_ref, SQLQuery#sql_query.hash, Query).
|
pgsql:prepare(State#state.db_ref, SQLQuery#sql_query.hash, Query).
|
||||||
|
|
||||||
@ -779,13 +793,15 @@ pgsql_execute_escape() ->
|
|||||||
boolean = fun(true) -> "1";
|
boolean = fun(true) -> "1";
|
||||||
(false) -> "0"
|
(false) -> "0"
|
||||||
end,
|
end,
|
||||||
in_array_string = fun(X) -> <<"\"", (escape(X))/binary, "\"">> end
|
in_array_string = fun(X) -> <<"\"", (escape(X))/binary, "\"">> end,
|
||||||
|
like_escape = fun() -> ignore end
|
||||||
}.
|
}.
|
||||||
|
|
||||||
pgsql_execute_sql_query(SQLQuery, State) ->
|
pgsql_execute_sql_query(SQLQuery, State) ->
|
||||||
Args = (SQLQuery#sql_query.args)(pgsql_execute_escape()),
|
Args = (SQLQuery#sql_query.args)(pgsql_execute_escape()),
|
||||||
|
Args2 = lists:filter(fun(ignore) -> false; (_) -> true end, Args),
|
||||||
ExecuteRes =
|
ExecuteRes =
|
||||||
pgsql:execute(State#state.db_ref, SQLQuery#sql_query.hash, Args),
|
pgsql:execute(State#state.db_ref, SQLQuery#sql_query.hash, Args2),
|
||||||
% {T, ExecuteRes} =
|
% {T, ExecuteRes} =
|
||||||
% timer:tc(pgsql, execute, [State#state.db_ref, SQLQuery#sql_query.hash, Args]),
|
% timer:tc(pgsql, execute, [State#state.db_ref, SQLQuery#sql_query.hash, Args]),
|
||||||
% io:format("T ~ts ~p~n", [SQLQuery#sql_query.hash, T]),
|
% io:format("T ~ts ~p~n", [SQLQuery#sql_query.hash, T]),
|
||||||
|
@ -354,6 +354,22 @@ parse1([$%, $( | S], Acc, State) ->
|
|||||||
used_vars = [Name | State2#state.used_vars]}
|
used_vars = [Name | State2#state.used_vars]}
|
||||||
end,
|
end,
|
||||||
parse1(S1, [], State4);
|
parse1(S1, [], State4);
|
||||||
|
parse1("%ESCAPE" ++ S, Acc, State) ->
|
||||||
|
State1 = append_string(lists:reverse(Acc), State),
|
||||||
|
Convert =
|
||||||
|
erl_syntax:application(
|
||||||
|
erl_syntax:record_access(
|
||||||
|
erl_syntax:variable(?ESCAPE_VAR),
|
||||||
|
erl_syntax:atom(?ESCAPE_RECORD),
|
||||||
|
erl_syntax:atom(like_escape)),
|
||||||
|
[]),
|
||||||
|
Var = State1#state.param_pos,
|
||||||
|
State2 =
|
||||||
|
State1#state{'query' = [{var, Var} | State1#state.'query'],
|
||||||
|
args = [Convert | State1#state.args],
|
||||||
|
params = [Var | State1#state.params],
|
||||||
|
param_pos = State1#state.param_pos + 1},
|
||||||
|
parse1(S, [], State2);
|
||||||
parse1([C | S], Acc, State) ->
|
parse1([C | S], Acc, State) ->
|
||||||
parse1(S, [C | Acc], State).
|
parse1(S, [C | Acc], State).
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ get_entity_subscriptions(Host, Owner) ->
|
|||||||
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
"from pubsub_state i, pubsub_node n "
|
"from pubsub_state i, pubsub_node n "
|
||||||
"where i.nodeid = n.nodeid and "
|
"where i.nodeid = n.nodeid and "
|
||||||
"(jid=%(GJ)s or jid like %(GJLike)s escape '^') and host=%(H)s");
|
"(jid=%(GJ)s or jid like %(GJLike)s %ESCAPE) and host=%(H)s");
|
||||||
_ ->
|
_ ->
|
||||||
SJ = encode_jid(SubKey),
|
SJ = encode_jid(SubKey),
|
||||||
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
@ -436,7 +436,7 @@ get_entity_subscriptions_for_send_last(Host, Owner) ->
|
|||||||
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
||||||
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
||||||
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
||||||
"(jid=%(GJ)s or jid like %(GJLike)s escape '^') and host=%(H)s");
|
"(jid=%(GJ)s or jid like %(GJLike)s %ESCAPE) and host=%(H)s");
|
||||||
_ ->
|
_ ->
|
||||||
SJ = encode_jid(SubKey),
|
SJ = encode_jid(SubKey),
|
||||||
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
@ -869,7 +869,7 @@ itemids(Nidx, {_U, _S, _R} = JID) ->
|
|||||||
ejabberd_sql:sql_query_t(
|
ejabberd_sql:sql_query_t(
|
||||||
?SQL("select @(itemid)s from pubsub_item where "
|
?SQL("select @(itemid)s from pubsub_item where "
|
||||||
"nodeid=%(Nidx)d and (publisher=%(SJID)s"
|
"nodeid=%(Nidx)d and (publisher=%(SJID)s"
|
||||||
" or publisher like %(SJIDLike)s escape '^') "
|
" or publisher like %(SJIDLike)s %ESCAPE) "
|
||||||
"order by modification desc"))
|
"order by modification desc"))
|
||||||
of
|
of
|
||||||
{selected, RItems} ->
|
{selected, RItems} ->
|
||||||
@ -968,16 +968,16 @@ encode_jid(JID) ->
|
|||||||
|
|
||||||
-spec encode_jid_like(JID :: ljid()) -> binary().
|
-spec encode_jid_like(JID :: ljid()) -> binary().
|
||||||
encode_jid_like(JID) ->
|
encode_jid_like(JID) ->
|
||||||
ejabberd_sql:escape_like_arg_circumflex(jid:encode(JID)).
|
ejabberd_sql:escape_like_arg(jid:encode(JID)).
|
||||||
|
|
||||||
-spec encode_host(Host :: host()) -> binary().
|
-spec encode_host(Host :: host()) -> binary().
|
||||||
encode_host({_U, _S, _R} = LJID) -> encode_jid(LJID);
|
encode_host({_U, _S, _R} = LJID) -> encode_jid(LJID);
|
||||||
encode_host(Host) -> Host.
|
encode_host(Host) -> Host.
|
||||||
|
|
||||||
-spec encode_host_like(Host :: host()) -> binary().
|
-spec encode_host_like(Host :: host()) -> binary().
|
||||||
encode_host_like({_U, _S, _R} = LJID) -> ejabberd_sql:escape(encode_jid_like(LJID));
|
encode_host_like({_U, _S, _R} = LJID) -> encode_jid_like(LJID);
|
||||||
encode_host_like(Host) ->
|
encode_host_like(Host) ->
|
||||||
ejabberd_sql:escape(ejabberd_sql:escape_like_arg_circumflex(Host)).
|
ejabberd_sql:escape_like_arg(Host).
|
||||||
|
|
||||||
-spec encode_affiliation(Arg :: atom()) -> binary().
|
-spec encode_affiliation(Arg :: atom()) -> binary().
|
||||||
encode_affiliation(owner) -> <<"o">>;
|
encode_affiliation(owner) -> <<"o">>;
|
||||||
|
@ -125,13 +125,13 @@ get_entity_subscriptions(_Host, Owner) ->
|
|||||||
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
"from pubsub_state i, pubsub_node n "
|
"from pubsub_state i, pubsub_node n "
|
||||||
"where i.nodeid = n.nodeid and "
|
"where i.nodeid = n.nodeid and "
|
||||||
"(jid=%(GJ)s or jid like %(GJLike)s escape '^') and host like %(HLike)s escape '^'");
|
"(jid=%(GJ)s or jid like %(GJLike)s %ESCAPE) and host like %(HLike)s %ESCAPE");
|
||||||
_ ->
|
_ ->
|
||||||
SJ = node_flat_sql:encode_jid(SubKey),
|
SJ = node_flat_sql:encode_jid(SubKey),
|
||||||
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
"from pubsub_state i, pubsub_node n "
|
"from pubsub_state i, pubsub_node n "
|
||||||
"where i.nodeid = n.nodeid and "
|
"where i.nodeid = n.nodeid and "
|
||||||
"jid in (%(SJ)s,%(GJ)s) and host like %(HLike)s escape '^'")
|
"jid in (%(SJ)s,%(GJ)s) and host like %(HLike)s %ESCAPE")
|
||||||
end,
|
end,
|
||||||
{result,
|
{result,
|
||||||
case ejabberd_sql:sql_query_t(Query) of
|
case ejabberd_sql:sql_query_t(Query) of
|
||||||
@ -162,14 +162,14 @@ get_entity_subscriptions_for_send_last(_Host, Owner) ->
|
|||||||
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
||||||
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
||||||
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
||||||
"(jid=%(GJ)s or jid like %(GJLike)s escape '^') and host like %(HLike)s escape '^'");
|
"(jid=%(GJ)s or jid like %(GJLike)s %ESCAPE) and host like %(HLike)s %ESCAPE");
|
||||||
_ ->
|
_ ->
|
||||||
SJ = node_flat_sql:encode_jid(SubKey),
|
SJ = node_flat_sql:encode_jid(SubKey),
|
||||||
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
?SQL("select @(host)s, @(node)s, @(plugin)s, @(i.nodeid)d, @(jid)s, @(subscriptions)s "
|
||||||
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
|
||||||
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and "
|
||||||
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
"name='send_last_published_item' and val='on_sub_and_presence' and "
|
||||||
"jid in (%(SJ)s,%(GJ)s) and host like %(HLike)s escape '^'")
|
"jid in (%(SJ)s,%(GJ)s) and host like %(HLike)s %ESCAPE")
|
||||||
end,
|
end,
|
||||||
{result,
|
{result,
|
||||||
case ejabberd_sql:sql_query_t(Query) of
|
case ejabberd_sql:sql_query_t(Query) of
|
||||||
|
@ -220,12 +220,12 @@ get_subnodes_tree(Host, Node) ->
|
|||||||
Rec ->
|
Rec ->
|
||||||
Type = Rec#pubsub_node.type,
|
Type = Rec#pubsub_node.type,
|
||||||
H = node_flat_sql:encode_host(Host),
|
H = node_flat_sql:encode_host(Host),
|
||||||
N = <<(ejabberd_sql:escape_like_arg_circumflex(Node))/binary, "/%">>,
|
N = <<(ejabberd_sql:escape_like_arg(Node))/binary, "/%">>,
|
||||||
Sub = case catch
|
Sub = case catch
|
||||||
ejabberd_sql:sql_query_t(
|
ejabberd_sql:sql_query_t(
|
||||||
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d from pubsub_node "
|
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d from pubsub_node "
|
||||||
"where host=%(H)s and plugin=%(Type)s and"
|
"where host=%(H)s and plugin=%(Type)s and"
|
||||||
" (parent=%(Node)s or parent like %(N)s escape '^')"))
|
" (parent=%(Node)s or parent like %(N)s %ESCAPE)"))
|
||||||
of
|
of
|
||||||
{selected, RItems} ->
|
{selected, RItems} ->
|
||||||
[raw_to_node(Host, Item) || Item <- RItems];
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
|
Loading…
Reference in New Issue
Block a user