./ct_report/coverage/mongoose_rdbms_mysql.COVER.html

1 %%==============================================================================
2 %% Copyright 2016 Erlang Solutions Ltd.
3 %%
4 %% Licensed under the Apache License, Version 2.0 (the "License");
5 %% you may not use this file except in compliance with the License.
6 %% You may obtain a copy of the License at
7 %%
8 %% http://www.apache.org/licenses/LICENSE-2.0
9 %%
10 %% Unless required by applicable law or agreed to in writing, software
11 %% distributed under the License is distributed on an "AS IS" BASIS,
12 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 %% See the License for the specific language governing permissions and
14 %% limitations under the License.
15 %%==============================================================================
16
17 -module(mongoose_rdbms_mysql).
18 -author('konrad.zemek@erlang-solutions.com').
19 -behaviour(mongoose_rdbms_backend).
20
21 -type options() :: #{host := string(),
22 port := inet:port_number(),
23 database := string(),
24 username := string(),
25 password := string(),
26 atom() => any()}.
27
28 -export([escape_binary/1, unescape_binary/1, connect/2, disconnect/1,
29 query/3, prepare/5, execute/4]).
30
31 %% API
32
33 -spec escape_binary(binary()) -> iodata().
34 escape_binary(Bin) when is_binary(Bin) ->
35 90 [<<"X'">>, base16:encode(Bin), <<"'">>].
36
37 -spec unescape_binary(binary()) -> binary().
38 unescape_binary(Bin) when is_binary(Bin) ->
39 6352 Bin.
40
41 -spec connect(options(), QueryTimeout :: non_neg_integer()) ->
42 {ok, Connection :: term()} | {error, Reason :: any()}.
43 connect(Options, QueryTimeout) ->
44 210 case mysql:start_link([{query_timeout, QueryTimeout} | db_opts(Options)]) of
45 {ok, Ref} ->
46 210 mysql:query(Ref, <<"set names 'utf8mb4';">>),
47 210 mysql:query(Ref, <<"SET SESSION query_cache_type=1;">>),
48 210 {ok, Ref};
49 Error ->
50
:-(
Error
51 end.
52
53 -spec disconnect(Connection :: term()) -> any().
54 disconnect(Connection) ->
55 195 gen_server:stop(Connection).
56
57 -spec query(Connection :: term(), Query :: any(),
58 Timeout :: infinity | non_neg_integer()) -> mongoose_rdbms:query_result().
59 query(Connection, Query, _Timeout) ->
60 33735 mysql_to_rdbms(mysql:query(Connection, Query), Connection).
61
62 -spec prepare(Connection :: term(), Name :: atom(), Table :: binary(),
63 Fields :: [binary()], Statement :: iodata()) ->
64 {ok, term()} | {error, any()}.
65 prepare(Connection, Name, _Table, _Fields, Statement) ->
66 2387 mysql:prepare(Connection, Name, Statement).
67
68 -spec execute(Connection :: term(), StatementRef :: term(), Params :: [term()],
69 Timeout :: infinity | non_neg_integer()) -> mongoose_rdbms:query_result().
70 execute(Connection, StatementRef, Params, _Timeout) ->
71 130641 Params2 = booleans_as_integers(Params),
72 130641 mysql_to_rdbms(mysql:execute(Connection, StatementRef, Params2), Connection).
73
74 %% Helpers
75
76 -spec db_opts(options()) -> [mysql:option()].
77 db_opts(Options) ->
78 210 FilteredOpts = maps:with([host, port, database, username, password, tls], Options),
79 210 [{found_rows, true} | lists:map(fun process_opt/1, maps:to_list(FilteredOpts))].
80
81 210 process_opt({tls, TLSOpts}) -> {ssl, just_tls:make_ssl_opts(TLSOpts)};
82 210 process_opt({username, UserName}) -> {user, UserName};
83 840 process_opt(Opt) -> Opt.
84
85 %% @doc Convert MySQL query result to Erlang RDBMS result formalism
86 -spec mysql_to_rdbms(mysql:query_result(), Conn :: term()) -> mongoose_rdbms:query_result().
87 mysql_to_rdbms(ok, Conn) ->
88 90395 {updated, mysql:affected_rows(Conn)};
89 mysql_to_rdbms({ok, _ColumnNames, Rows}, _Conn) ->
90 73763 {selected, [list_to_tuple(Row) || Row <- Rows]};
91 mysql_to_rdbms({ok, Results}, Conn) ->
92
:-(
[mysql_to_rdbms({ok, Cols, Rows}, Conn) || {Cols, Rows} <- Results];
93 mysql_to_rdbms({error, {1062, _SQLState, _Message}}, _Conn) ->
94 217 {error, duplicate_key};
95 mysql_to_rdbms({error, {_Code, _SQLState, Message}}, _Conn) ->
96 1 {error, unicode:characters_to_list(Message)}.
97
98 booleans_as_integers([H|T]) when is_boolean(H) ->
99 14 [boolean_to_integer(H)|booleans_as_integers(T)];
100 booleans_as_integers([H|T]) ->
101 352346 [H|booleans_as_integers(T)];
102 booleans_as_integers([]) ->
103 130641 [].
104
105
:-(
boolean_to_integer(true) -> 1;
106 14 boolean_to_integer(false) -> 0.
Line Hits Source