mirror of
https://github.com/processone/ejabberd
synced 2025-10-05 10:39:29 +02:00
Add alternate version of mysql upsert
This one works by issuing select and then insert or update or skip depending on what select returns. We use this on mysql 5.7.26 and 8.0.20 where previous implementation using 'replace' or 'on conflict update' can cause excessive deadlocks.
This commit is contained in:
parent
3eecf4ae8a
commit
bb8e892323
2 changed files with 95 additions and 2 deletions
|
@ -567,7 +567,6 @@ parse_upsert_field1([$= | S], Acc, ParamPos, Loc) ->
|
|||
parse_upsert_field1([C | S], Acc, ParamPos, Loc) ->
|
||||
parse_upsert_field1(S, [C | Acc], ParamPos, Loc).
|
||||
|
||||
|
||||
make_sql_upsert(Table, ParseRes, Pos) ->
|
||||
check_upsert(ParseRes, Pos),
|
||||
erl_syntax:fun_expr(
|
||||
|
@ -587,6 +586,11 @@ make_sql_upsert(Table, ParseRes, Pos) ->
|
|||
erl_syntax:integer(90100))],
|
||||
[make_sql_upsert_pgsql901(Table, ParseRes),
|
||||
erl_syntax:atom(ok)]),
|
||||
erl_syntax:clause(
|
||||
[erl_syntax:atom(mysql), erl_syntax:tuple([erl_syntax:underscore(), erl_syntax:underscore(), erl_syntax:integer(1)])],
|
||||
[],
|
||||
[make_sql_upsert_mysql_select(Table, ParseRes),
|
||||
erl_syntax:atom(ok)]),
|
||||
erl_syntax:clause(
|
||||
[erl_syntax:atom(mysql), erl_syntax:underscore()],
|
||||
[],
|
||||
|
@ -682,6 +686,66 @@ make_sql_upsert_insert(Table, ParseRes) ->
|
|||
]),
|
||||
State.
|
||||
|
||||
make_sql_upsert_select(Table, ParseRes) ->
|
||||
{Fields0, Where0} =
|
||||
lists:foldl(
|
||||
fun({Field, key, ST}, {Fie, Whe}) ->
|
||||
{Fie, [ST#state{
|
||||
'query' = [{str, Field}, {str, "="}] ++ ST#state.'query'}] ++ Whe};
|
||||
({Field, {true}, ST}, {Fie, Whe}) ->
|
||||
{[ST#state{
|
||||
'query' = [{str, Field}, {str, "="}] ++ ST#state.'query'}] ++ Fie, Whe};
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end, {[], []}, ParseRes),
|
||||
Fields = join_states(Fields0, " AND "),
|
||||
Where = join_states(Where0, " AND "),
|
||||
State =
|
||||
concat_states(
|
||||
[#state{'query' = [{str, "SELECT "}],
|
||||
res_vars = [erl_syntax:variable("__VSel")],
|
||||
res = [erl_syntax:application(
|
||||
erl_syntax:atom(ejabberd_sql),
|
||||
erl_syntax:atom(to_bool),
|
||||
[erl_syntax:variable("__VSel")])]},
|
||||
Fields,
|
||||
#state{'query' = [{str, " FROM "}, {str, Table}, {str, " WHERE "}]},
|
||||
Where
|
||||
]),
|
||||
State.
|
||||
|
||||
make_sql_upsert_mysql_select(Table, ParseRes) ->
|
||||
Select = make_sql_query(make_sql_upsert_select(Table, ParseRes)),
|
||||
Insert = make_sql_query(make_sql_upsert_insert(Table, ParseRes)),
|
||||
Update = make_sql_query(make_sql_upsert_update(Table, ParseRes)),
|
||||
erl_syntax:case_expr(
|
||||
erl_syntax:application(
|
||||
erl_syntax:atom(ejabberd_sql),
|
||||
erl_syntax:atom(sql_query_t),
|
||||
[Select]),
|
||||
[erl_syntax:clause(
|
||||
[erl_syntax:tuple([erl_syntax:atom(selected), erl_syntax:list([])])],
|
||||
none,
|
||||
[erl_syntax:application(
|
||||
erl_syntax:atom(ejabberd_sql),
|
||||
erl_syntax:atom(sql_query_t),
|
||||
[Insert])]),
|
||||
erl_syntax:clause(
|
||||
[erl_syntax:abstract({selected, [{true}]})],
|
||||
[],
|
||||
[erl_syntax:atom(ok)]),
|
||||
erl_syntax:clause(
|
||||
[erl_syntax:tuple([erl_syntax:atom(selected), erl_syntax:underscore()])],
|
||||
none,
|
||||
[erl_syntax:application(
|
||||
erl_syntax:atom(ejabberd_sql),
|
||||
erl_syntax:atom(sql_query_t),
|
||||
[Update])]),
|
||||
erl_syntax:clause(
|
||||
[erl_syntax:variable("__SelectRes")],
|
||||
none,
|
||||
[erl_syntax:variable("__SelectRes")])]).
|
||||
|
||||
make_sql_upsert_mysql(Table, ParseRes) ->
|
||||
Vals =
|
||||
lists:map(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue