Current section
18 Versions
Jump to
Current section
18 Versions
Compare versions
11
files changed
+217
additions
-87
deletions
| @@ -1,3 +1,7 @@ | |
| 1 | + [](https://github.com/epgsql/epgsql/actions/workflows/ci.yml) |
| 2 | + [](https://hex.pm/packages/epgsql) |
| 3 | + [](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 | - [](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…