Current section

18 Versions

Jump to

Compare versions

11 files changed
+217 additions
-87 deletions
  @@ -1,3 +1,7 @@
1 + [![CI](https://github.com/epgsql/epgsql/workflows/CI/badge.svg)](https://github.com/epgsql/epgsql/actions/workflows/ci.yml)
2 + [![Hex version](https://img.shields.io/hexpm/v/epgsql.svg "Hex version")](https://hex.pm/packages/epgsql)
3 + [![License](https://img.shields.io/badge/License-BSD_3_Clause-blue.svg?logo=bsd&logoColor=red)](https://opensource.org/licenses/BSD-3-Clause)
4 +
1 5 # Erlang PostgreSQL Database Client
2 6
3 7 Asynchronous fork of [wg/epgsql](https://github.com/wg/epgsql) originally here:
  @@ -764,4 +768,3 @@ NOTE 2: It's possible to run tests on exact postgres version by changing $PATH l
764 768
765 769 `PATH=$PATH:/usr/lib/postgresql/12/bin/ make test`
766 770
767 - [![CI](https://github.com/epgsql/epgsql/actions/workflows/ci.yml/badge.svg)](https://github.com/epgsql/epgsql/actions/workflows/ci.yml)
  @@ -2,9 +2,10 @@
2 2 {<<"build_tools">>,[<<"rebar3">>]}.
3 3 {<<"description">>,<<"PostgreSQL Client">>}.
4 4 {<<"files">>,
5 - [<<"LICENSE">>,<<"README.md">>,<<"include/epgsql.hrl">>,
5 + [<<"LICENSE">>,<<"README.md">>,<<"include">>,<<"include/epgsql.hrl">>,
6 6 <<"include/epgsql_geometry.hrl">>,<<"include/protocol.hrl">>,
7 - <<"rebar.config">>,<<"rebar.lock">>,<<"src/commands/epgsql_cmd_batch.erl">>,
7 + <<"rebar.config">>,<<"rebar.lock">>,<<"src">>,<<"src/commands">>,
8 + <<"src/commands/epgsql_cmd_batch.erl">>,
8 9 <<"src/commands/epgsql_cmd_bind.erl">>,
9 10 <<"src/commands/epgsql_cmd_close.erl">>,
10 11 <<"src/commands/epgsql_cmd_connect.erl">>,
  @@ -19,7 +20,7 @@
19 20 <<"src/commands/epgsql_cmd_squery.erl">>,
20 21 <<"src/commands/epgsql_cmd_start_replication.erl">>,
21 22 <<"src/commands/epgsql_cmd_sync.erl">>,
22 - <<"src/commands/epgsql_cmd_update_type_cache.erl">>,
23 + <<"src/commands/epgsql_cmd_update_type_cache.erl">>,<<"src/datatypes">>,
23 24 <<"src/datatypes/epgsql_codec_boolean.erl">>,
24 25 <<"src/datatypes/epgsql_codec_bpchar.erl">>,
25 26 <<"src/datatypes/epgsql_codec_datetime.erl">>,
  @@ -47,4 +48,4 @@
47 48 {<<"links">>,[{<<"Github">>,<<"https://github.com/epgsql/epgsql">>}]}.
48 49 {<<"name">>,<<"epgsql">>}.
49 50 {<<"requirements">>,[]}.
50 - {<<"version">>,<<"4.7.1">>}.
51 + {<<"version">>,<<"4.8.0">>}.
  @@ -11,7 +11,7 @@
11 11 ]}
12 12 ]},
13 13 {lint, [
14 - {plugins, [{rebar3_lint, "0.2.0"}]}
14 + {plugins, [{rebar3_lint, "3.2.5"}]}
15 15 ]}
16 16 ]}.
17 17
  @@ -25,10 +25,19 @@
25 25 filter => "*.erl",
26 26 ruleset => erl_files,
27 27 rules =>
28 - [{elvis_style, line_length, #{limit => 120}},
28 + [{elvis_text_style, line_length, #{limit => 120}},
29 29 {elvis_style, god_modules, #{ignore => [epgsql, epgsqla, epgsqli, epgsql_sock, epgsql_wire]}},
30 30 {elvis_style, dont_repeat_yourself, #{min_complexity => 11}},
31 - {elvis_style, state_record_and_type, disable} % epgsql_sock
31 + {elvis_style, state_record_and_type, disable}, % epgsql_sock
32 + {elvis_style, export_used_types, disable},
33 + {elvis_style, no_space, disable},
34 + {elvis_style, atom_naming_convention, disable},
35 + {elvis_style, operator_spaces, disable},
36 + {elvis_style, private_data_types, disable},
37 + {elvis_style, param_pattern_matching, disable},
38 + {elvis_style, consistent_variable_casing, disable},
39 + {elvis_style, no_catch_expressions, disable},
40 + {elvis_style, behaviour_spelling, disable}
32 41 ]}
33 42 ]
34 43 }.
  @@ -48,6 +48,7 @@ init(Batch) when is_list(Batch) ->
48 48 #batch{batch = Batch}.
49 49
50 50 execute(Sock, #batch{batch = Batch, statement = undefined} = State) ->
51 + %% Each query has it's own statement
51 52 Codec = epgsql_sock:get_codec(Sock),
52 53 Commands =
53 54 lists:foldr(
  @@ -56,7 +57,9 @@ execute(Sock, #batch{batch = Batch, statement = undefined} = State) ->
56 57 columns = Columns,
57 58 types = Types} = Statement,
58 59 BinFormats = epgsql_wire:encode_formats(Columns),
59 - add_command(StatementName, Types, Parameters, BinFormats, Codec, Acc)
60 + TypedParameters = lists:zip(Types, Parameters),
61 + BinParams = epgsql_wire:encode_parameters(TypedParameters, Codec),
62 + add_command(StatementName, BinParams, BinFormats, Acc)
60 63 end,
61 64 [epgsql_wire:encode_sync()],
62 65 Batch),
  @@ -65,21 +68,22 @@ execute(Sock, #batch{batch = Batch,
65 68 statement = #statement{name = StatementName,
66 69 columns = Columns,
67 70 types = Types}} = State) ->
71 + %% All queries share the same statement
68 72 Codec = epgsql_sock:get_codec(Sock),
69 73 BinFormats = epgsql_wire:encode_formats(Columns),
70 - %% TODO: build some kind of encoder and reuse it for each batch item
74 + %% optimization: builds encoder to reuse it for each batch item
75 + ParamsEncoder = epgsql_wire:build_parameters_encoder(Types, Codec),
71 76 Commands =
72 77 lists:foldr(
73 78 fun(Parameters, Acc) ->
74 - add_command(StatementName, Types, Parameters, BinFormats, Codec, Acc)
79 + BinParams = epgsql_wire:encode_parameters_with_encoder(Parameters, ParamsEncoder, Codec),
80 + add_command(StatementName, BinParams, BinFormats, Acc)
75 81 end,
76 82 [epgsql_wire:encode_sync()],
77 83 Batch),
78 84 {send_multi, Commands, Sock, State}.
79 85
80 - add_command(StmtName, Types, Params, BinFormats, Codec, Acc) ->
81 - TypedParameters = lists:zip(Types, Params),
82 - BinParams = epgsql_wire:encode_parameters(TypedParameters, Codec),
86 + add_command(StmtName, BinParams, BinFormats, Acc) ->
83 87 [epgsql_wire:encode_bind("", StmtName, BinParams, BinFormats),
84 88 epgsql_wire:encode_execute("", 0) | Acc].
  @@ -63,7 +63,7 @@ handle_message(?COPY_IN_RESPONSE, <<BinOrText, NumColumns:?int16, Formats/binary
63 63 #copy_stdin{initiator = Initiator, format = RequestedFormat}) ->
64 64 ColumnFormats = [format_to_atom(Format) || <<Format:?int16>> <= Formats],
65 65 length(ColumnFormats) =:= NumColumns orelse error(invalid_copy_in_response),
66 - CopyState = init_copy_state(format_to_atom(BinOrText), RequestedFormat, ColumnFormats, Initiator),
66 + CopyState = init_copy_state(format_to_atom(BinOrText), RequestedFormat, ColumnFormats, Initiator, Sock),
67 67 Sock1 = epgsql_sock:set_attr(subproto_state, CopyState, Sock),
68 68 Res = {ok, ColumnFormats},
69 69 {finish, Res, Res, epgsql_sock:set_packet_handler(on_copy_from_stdin, Sock1)};
  @@ -73,14 +73,14 @@ handle_message(?ERROR, Error, _Sock, _State) ->
73 73 handle_message(_, _, _, _) ->
74 74 unknown.
75 75
76 - init_copy_state(text, text, ColumnFormats, Initiator) ->
76 + init_copy_state(text, text, ColumnFormats, Initiator, _) ->
77 77 %% When BinOrText is `text', all "columns" should be `text' format as well.
78 78 %% See https://www.postgresql.org/docs/current/protocol-message-formats.html
79 79 %% CopyInResponse
80 80 (lists:member(binary, ColumnFormats) == false)
81 81 orelse error(invalid_copy_in_response),
82 82 #copy{initiator = Initiator, format = text};
83 - init_copy_state(binary, {binary, ColumnTypes}, ColumnFormats, Initiator) ->
83 + init_copy_state(binary, {binary, ColumnTypes}, ColumnFormats, Initiator, Sock) ->
84 84 %% https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-COPY
85 85 %% "As of the present implementation, all columns in a given COPY operation will use the same
86 86 %% format, but the message design does not assume this."
  @@ -91,8 +91,10 @@ init_copy_state(binary, {binary, ColumnTypes}, ColumnFormats, Initiator) ->
91 91 %% so number of columns in SQL is not same as number of types in `binary'
92 92 (NumColumns == length(ColumnTypes))
93 93 orelse error({column_count_mismatch, ColumnTypes, NumColumns}),
94 - #copy{initiator = Initiator, format = binary, binary_types = ColumnTypes};
95 - init_copy_state(ServerExpectedFormat, RequestedFormat, _, _Initiator) ->
94 + Codec = epgsql_sock:get_codec(Sock),
95 + Encoder = epgsql_wire:build_copy_row_encoder(ColumnTypes, Codec),
96 + #copy{initiator = Initiator, format = binary, binary_encoder = Encoder};
97 + init_copy_state(ServerExpectedFormat, RequestedFormat, _, _, _) ->
96 98 %% Eg, `epgsql:copy_from_stdin(C, "COPY ... WITH (FORMAT text)", {binary, ...})' or
97 99 %% `epgsql:copy_from_stdin(C, "COPY ... WITH (FORMAT binary)", text)' or maybe PostgreSQL
98 100 %% got some new format epgsql is not aware of
Loading more files…