Skip to content

Commit a89b1f3

Browse files
committed
Use INSERT ... ON DUPLICATE KEY UPDATE for upsert on mysql
This can be used for all upsert expressions (where REPLACE INTO used previously were only possible to use for subset of queries), and may potentially help with deadlocks reported by mysql when we issues multiple querier for same key in quick succession.
1 parent a6101cc commit a89b1f3

File tree

1 file changed

+52
-45
lines changed

1 file changed

+52
-45
lines changed

src/ejabberd_sql_pt.erl

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -570,43 +570,33 @@ parse_upsert_field1([C | S], Acc, ParamPos, Loc) ->
570570

571571
make_sql_upsert(Table, ParseRes, Pos) ->
572572
check_upsert(ParseRes, Pos),
573-
HasInsertOnlyFields = lists:any(
574-
fun({_, {false}, _}) -> true;
575-
(_) -> false
576-
end, ParseRes),
577-
MySqlReplace = case HasInsertOnlyFields of
578-
false ->
579-
[erl_syntax:clause(
580-
[erl_syntax:atom(mysql), erl_syntax:underscore()],
581-
[],
582-
[make_sql_upsert_mysql(Table, ParseRes),
583-
erl_syntax:atom(ok)])];
584-
_ ->
585-
[]
586-
end,
587573
erl_syntax:fun_expr(
588-
[erl_syntax:clause(
589-
[erl_syntax:atom(pgsql), erl_syntax:variable("__Version")],
590-
[erl_syntax:infix_expr(
591-
erl_syntax:variable("__Version"),
592-
erl_syntax:operator('>='),
593-
erl_syntax:integer(90500))],
594-
[make_sql_upsert_pgsql905(Table, ParseRes),
595-
erl_syntax:atom(ok)]),
596-
erl_syntax:clause(
597-
[erl_syntax:atom(pgsql), erl_syntax:variable("__Version")],
598-
[erl_syntax:infix_expr(
599-
erl_syntax:variable("__Version"),
600-
erl_syntax:operator('>='),
601-
erl_syntax:integer(90100))],
602-
[make_sql_upsert_pgsql901(Table, ParseRes),
603-
erl_syntax:atom(ok)])] ++
604-
MySqlReplace ++
605-
[erl_syntax:clause(
606-
[erl_syntax:underscore(), erl_syntax:underscore()],
607-
none,
608-
[make_sql_upsert_generic(Table, ParseRes)])
609-
]).
574+
[erl_syntax:clause(
575+
[erl_syntax:atom(pgsql), erl_syntax:variable("__Version")],
576+
[erl_syntax:infix_expr(
577+
erl_syntax:variable("__Version"),
578+
erl_syntax:operator('>='),
579+
erl_syntax:integer(90500))],
580+
[make_sql_upsert_pgsql905(Table, ParseRes),
581+
erl_syntax:atom(ok)]),
582+
erl_syntax:clause(
583+
[erl_syntax:atom(pgsql), erl_syntax:variable("__Version")],
584+
[erl_syntax:infix_expr(
585+
erl_syntax:variable("__Version"),
586+
erl_syntax:operator('>='),
587+
erl_syntax:integer(90100))],
588+
[make_sql_upsert_pgsql901(Table, ParseRes),
589+
erl_syntax:atom(ok)]),
590+
erl_syntax:clause(
591+
[erl_syntax:atom(mysql), erl_syntax:underscore()],
592+
[],
593+
[make_sql_upsert_mysql(Table, ParseRes),
594+
erl_syntax:atom(ok)]),
595+
erl_syntax:clause(
596+
[erl_syntax:underscore(), erl_syntax:underscore()],
597+
none,
598+
[make_sql_upsert_generic(Table, ParseRes)])
599+
]).
610600

611601
make_sql_upsert_generic(Table, ParseRes) ->
612602
Update = make_sql_query(make_sql_upsert_update(Table, ParseRes)),
@@ -672,9 +662,6 @@ make_sql_upsert_update(Table, ParseRes) ->
672662
State.
673663

674664
make_sql_upsert_insert(Table, ParseRes) ->
675-
make_sql_upsert_insert_replace(Table, ParseRes, "INSERT").
676-
677-
make_sql_upsert_insert_replace(Table, ParseRes, Keyword) ->
678665
Vals =
679666
lists:map(
680667
fun({_Field, _, ST}) ->
@@ -687,23 +674,43 @@ make_sql_upsert_insert_replace(Table, ParseRes, Keyword) ->
687674
end, ParseRes),
688675
State =
689676
concat_states(
690-
[#state{'query' = [{str, Keyword ++" INTO "}, {str, Table}, {str, "("}]},
677+
[#state{'query' = [{str, "INSERT INTO "}, {str, Table}, {str, "("}]},
691678
join_states(Fields, ", "),
692679
#state{'query' = [{str, ") VALUES ("}]},
693680
join_states(Vals, ", "),
694681
#state{'query' = [{str, ");"}]}
695682
]),
696683
State.
697684

698-
make_sql_upsert_replace(Table, ParseRes) ->
699-
make_sql_upsert_insert_replace(Table, ParseRes, "REPLACE").
700-
701685
make_sql_upsert_mysql(Table, ParseRes) ->
702-
Replace = make_sql_query(make_sql_upsert_replace(Table, ParseRes)),
686+
Vals =
687+
lists:map(
688+
fun({_Field, _, ST}) ->
689+
ST
690+
end, ParseRes),
691+
{Fields, Set} =
692+
lists:foldr(
693+
fun({Field, key, _ST}, {F, S}) ->
694+
{[#state{'query' = [{str, Field}]} | F], S};
695+
({Field, {false}, _ST}, {F, S}) ->
696+
{[#state{'query' = [{str, Field}]} | F], S};
697+
({Field, {true}, _ST}, {F, S}) ->
698+
{[#state{'query' = [{str, Field}]} | F],
699+
[#state{'query' = [{str, Field}, {str, "=VALUES("}, {str, Field}, {str, ")"}]} | S]}
700+
end, {[], []}, ParseRes),
701+
Insert =
702+
concat_states(
703+
[#state{'query' = [{str, "INSERT INTO "}, {str, Table}, {str, "("}]},
704+
join_states(Fields, ", "),
705+
#state{'query' = [{str, ") VALUES ("}]},
706+
join_states(Vals, ", "),
707+
#state{'query' = [{str, ") ON DUPLICATE KEY UPDATE "}]},
708+
join_states(Set, ", ")
709+
]),
703710
erl_syntax:application(
704711
erl_syntax:atom(ejabberd_sql),
705712
erl_syntax:atom(sql_query_t),
706-
[Replace]).
713+
[make_sql_query(Insert)]).
707714

708715
make_sql_upsert_pgsql901(Table, ParseRes0) ->
709716
ParseRes = lists:map(

0 commit comments

Comments
 (0)