From d86be54e6ddf6785fff34d5415d1c53cdfaca130 Mon Sep 17 00:00:00 2001 From: Yury Yantsevich Date: Fri, 30 Dec 2022 10:45:50 +0100 Subject: [PATCH 01/12] handle messages gracefully when command is not set --- src/epgsql_command.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/epgsql_command.erl b/src/epgsql_command.erl index e15586fe..739a232f 100644 --- a/src/epgsql_command.erl +++ b/src/epgsql_command.erl @@ -67,5 +67,7 @@ execute(Command, PgSock, CmdState) -> -spec handle_message(command(), Type :: byte(), Payload :: binary() | epgsql:query_error(), epgsql_sock:pg_sock(), state()) -> handle_message_return(). +handle_message(undefined = _Command, _Type, _Payload, _PgSock, _State) -> + unknown; handle_message(Command, Type, Payload, PgSock, State) -> Command:handle_message(Type, Payload, PgSock, State). From d4247d12a8e7bb9208684496f5436417077fb180 Mon Sep 17 00:00:00 2001 From: Yury Yantsevich Date: Fri, 30 Dec 2022 13:58:52 +0100 Subject: [PATCH 02/12] Add a test for the unexpected message handling --- test/epgsql_ct.erl | 1 + test/epgsql_replication_SUITE.erl | 59 +++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/test/epgsql_ct.erl b/test/epgsql_ct.erl index 9a16ada7..bedae9f0 100644 --- a/test/epgsql_ct.erl +++ b/test/epgsql_ct.erl @@ -5,6 +5,7 @@ -export([ connection_data/1, connect/1, + connect/3, connect_only/2, with_connection/2, with_connection/3, diff --git a/test/epgsql_replication_SUITE.erl b/test/epgsql_replication_SUITE.erl index d8ff1eef..036941f2 100644 --- a/test/epgsql_replication_SUITE.erl +++ b/test/epgsql_replication_SUITE.erl @@ -15,6 +15,7 @@ replication_async_active_n_socket/1, replication_sync_active_n_socket/1, replication_async_active_n_ssl/1, + two_replications_on_same_slot/1, %% Callbacks handle_x_log_data/4 @@ -33,7 +34,8 @@ all() -> replication_sync, replication_async_active_n_socket, replication_sync_active_n_socket, - replication_async_active_n_ssl + replication_async_active_n_ssl, + two_replications_on_same_slot ]. connect_in_repl_mode(Config) -> @@ -75,6 +77,37 @@ replication_async_active_n_ssl(Config) -> noop. -endif. +two_replications_on_same_slot(Config) -> + Module = ?config(module, Config), + User = "epgsql_test_replication", + Parent = self(), + epgsql_ct:with_connection( + Config, + fun(C) -> + create_replication_slot(Config, C), + Res1 = Module:start_replication(C, "epgsql_test", Parent, {C, Parent}, "0/0"), + ?assertEqual(ok, Res1), + spawn( + fun() -> + %% This connection will be terminated due to an unexpected message: + %% EmptyQueryResponse (B), Byte1('I'), Int32(4) + %% https://www.postgresql.org/docs/current/protocol-message-formats.html + process_flag(trap_exit, true), + C2 = epgsql_ct:connect(Config, User, [{replication, "database"}]), + Res2 = Module:start_replication(C2, "epgsql_test", self(), {C2, self()}, "0/0"), + ?assertMatch({error, _}, Res2), + cleanup_and_notify(Parent) + end), + receive + Result -> ?assertEqual(terminated, Result) + after + 1000 -> ?assert(false, "Second connection hasn't been closed") + end + end, + User, + [{replication, "database"}]), + drop_replication_slot(Config). + replication_test_run(Config, Callback) -> replication_test_run(Config, Callback, []). @@ -99,11 +132,7 @@ replication_test_run(Config, Callback, ExtOpts) -> "epgsql_test_replication", [{replication, "database"} | ExtOpts]), %% cleanup - epgsql_ct:with_connection( - Config, - fun(C) -> drop_replication_slot(Config, C) end, - "epgsql_test_replication", - [{replication, "database"}]). + drop_replication_slot(Config). create_replication_slot(Config, Connection) -> Module = ?config(module, Config), @@ -118,6 +147,13 @@ create_replication_slot(Config, Connection) -> Cols), ?assertMatch([{<<"epgsql_test">>, _, _, <<"test_decoding">>}], Rows). +drop_replication_slot(Config) -> + epgsql_ct:with_connection( + Config, + fun(C) -> drop_replication_slot(Config, C) end, + "epgsql_test_replication", + [{replication, "database"}]). + drop_replication_slot(Config, Connection) -> Module = ?config(module, Config), Result = Module:squery(Connection, "DROP_REPLICATION_SLOT ""epgsql_test"""), @@ -174,6 +210,17 @@ ensure_no_socket_passive_msgs(Module, Pid) -> ok end. +cleanup_and_notify(Parent) -> + receive + {'EXIT', _Pid, {error, _}} -> + Parent ! terminated; + Msg -> + Parent ! Msg + after + 100 -> + Parent ! no_messages_received + end. + handle_x_log_data(StartLSN, EndLSN, Data, CbState) -> {C, Pid} = CbState, Pid ! {epgsql, C, {x_log_data, StartLSN, EndLSN, Data}}, From e7e24873163b1ad478183a8a0d4c565fc3839023 Mon Sep 17 00:00:00 2001 From: Yury Yantsevich Date: Mon, 2 Jan 2023 12:19:52 +0100 Subject: [PATCH 03/12] Handle ReadyForQuery when a replication slot is in use by another process --- src/commands/epgsql_cmd_start_replication.erl | 8 ++++++++ src/epgsql_command.erl | 2 -- test/epgsql_replication_SUITE.erl | 20 +++++-------------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/commands/epgsql_cmd_start_replication.erl b/src/commands/epgsql_cmd_start_replication.erl index 92f10d50..ec694ca3 100644 --- a/src/commands/epgsql_cmd_start_replication.erl +++ b/src/commands/epgsql_cmd_start_replication.erl @@ -65,8 +65,16 @@ execute(Sock, #start_repl{slot = ReplicationSlot, callback = Callback, %% CopyBothResponse handle_message(?COPY_BOTH_RESPONSE, _Data, Sock, _State) -> {finish, ok, ok, epgsql_sock:set_packet_handler(on_replication, Sock)}; +handle_message(?ERROR, #error{codename = object_in_use} = Error, Sock, State) -> + %% A replication slot is in use already. In this case, protocol sends a ReadyForQuery message. + %% Adds an error to results to handle it later in the ?READY_FOR_QUERY branch. + Result = {error, Error}, + {add_result, Result, Result, Sock, State}; handle_message(?ERROR, Error, _Sock, _State) -> Result = {error, Error}, {sync_required, Result}; +handle_message(?READY_FOR_QUERY, _Data, Sock, _State) -> + [Error = {error, _}] = epgsql_sock:get_results(Sock), % assert a single error response + {sync_required, Error}; handle_message(_, _, _, _) -> unknown. diff --git a/src/epgsql_command.erl b/src/epgsql_command.erl index 739a232f..e15586fe 100644 --- a/src/epgsql_command.erl +++ b/src/epgsql_command.erl @@ -67,7 +67,5 @@ execute(Command, PgSock, CmdState) -> -spec handle_message(command(), Type :: byte(), Payload :: binary() | epgsql:query_error(), epgsql_sock:pg_sock(), state()) -> handle_message_return(). -handle_message(undefined = _Command, _Type, _Payload, _PgSock, _State) -> - unknown; handle_message(Command, Type, Payload, PgSock, State) -> Command:handle_message(Type, Payload, PgSock, State). diff --git a/test/epgsql_replication_SUITE.erl b/test/epgsql_replication_SUITE.erl index 036941f2..61db6831 100644 --- a/test/epgsql_replication_SUITE.erl +++ b/test/epgsql_replication_SUITE.erl @@ -90,18 +90,19 @@ two_replications_on_same_slot(Config) -> spawn( fun() -> %% This connection will be terminated due to an unexpected message: - %% EmptyQueryResponse (B), Byte1('I'), Int32(4) + %% ReadyForQuery (B), Byte1('Z'), Int32(5), Byte1 %% https://www.postgresql.org/docs/current/protocol-message-formats.html process_flag(trap_exit, true), C2 = epgsql_ct:connect(Config, User, [{replication, "database"}]), Res2 = Module:start_replication(C2, "epgsql_test", self(), {C2, self()}, "0/0"), ?assertMatch({error, _}, Res2), - cleanup_and_notify(Parent) + Parent ! error_received end), receive - Result -> ?assertEqual(terminated, Result) + Result -> ?assertEqual(error_received, Result) after - 1000 -> ?assert(false, "Second connection hasn't been closed") + 1000 -> ?assert(false, "Error hasn't been received when establishing " + "a second connection to the same replication slot") end end, User, @@ -210,17 +211,6 @@ ensure_no_socket_passive_msgs(Module, Pid) -> ok end. -cleanup_and_notify(Parent) -> - receive - {'EXIT', _Pid, {error, _}} -> - Parent ! terminated; - Msg -> - Parent ! Msg - after - 100 -> - Parent ! no_messages_received - end. - handle_x_log_data(StartLSN, EndLSN, Data, CbState) -> {C, Pid} = CbState, Pid ! {epgsql, C, {x_log_data, StartLSN, EndLSN, Data}}, From 790ec73cd3620cd2127b4df98371b96afb0b11ca Mon Sep 17 00:00:00 2001 From: Yury Yantsevich Date: Tue, 3 Jan 2023 09:21:24 +0100 Subject: [PATCH 04/12] Wait for ReadyForQuery in case of any error in replication command --- src/commands/epgsql_cmd_start_replication.erl | 10 +++---- test/epgsql_ct.erl | 1 - test/epgsql_replication_SUITE.erl | 27 ++++++++++++------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/commands/epgsql_cmd_start_replication.erl b/src/commands/epgsql_cmd_start_replication.erl index ec694ca3..a35bb8b7 100644 --- a/src/commands/epgsql_cmd_start_replication.erl +++ b/src/commands/epgsql_cmd_start_replication.erl @@ -12,7 +12,6 @@ -type response() :: ok | {error, epgsql:query_error()}. --include("epgsql.hrl"). -include("protocol.hrl"). -include("../epgsql_replication.hrl"). @@ -65,16 +64,13 @@ execute(Sock, #start_repl{slot = ReplicationSlot, callback = Callback, %% CopyBothResponse handle_message(?COPY_BOTH_RESPONSE, _Data, Sock, _State) -> {finish, ok, ok, epgsql_sock:set_packet_handler(on_replication, Sock)}; -handle_message(?ERROR, #error{codename = object_in_use} = Error, Sock, State) -> - %% A replication slot is in use already. In this case, protocol sends a ReadyForQuery message. +handle_message(?ERROR, Error, Sock, State) -> + %% In the case of error, Postgresql replication protocol sends a ReadyForQuery message. %% Adds an error to results to handle it later in the ?READY_FOR_QUERY branch. Result = {error, Error}, {add_result, Result, Result, Sock, State}; -handle_message(?ERROR, Error, _Sock, _State) -> - Result = {error, Error}, - {sync_required, Result}; handle_message(?READY_FOR_QUERY, _Data, Sock, _State) -> [Error = {error, _}] = epgsql_sock:get_results(Sock), % assert a single error response - {sync_required, Error}; + {finish, Error, done, Sock}; handle_message(_, _, _, _) -> unknown. diff --git a/test/epgsql_ct.erl b/test/epgsql_ct.erl index bedae9f0..9a16ada7 100644 --- a/test/epgsql_ct.erl +++ b/test/epgsql_ct.erl @@ -5,7 +5,6 @@ -export([ connection_data/1, connect/1, - connect/3, connect_only/2, with_connection/2, with_connection/3, diff --git a/test/epgsql_replication_SUITE.erl b/test/epgsql_replication_SUITE.erl index 61db6831..261f11fd 100644 --- a/test/epgsql_replication_SUITE.erl +++ b/test/epgsql_replication_SUITE.erl @@ -80,29 +80,36 @@ replication_async_active_n_ssl(Config) -> two_replications_on_same_slot(Config) -> Module = ?config(module, Config), User = "epgsql_test_replication", + SlotName = "epgsql_test", Parent = self(), epgsql_ct:with_connection( Config, fun(C) -> create_replication_slot(Config, C), - Res1 = Module:start_replication(C, "epgsql_test", Parent, {C, Parent}, "0/0"), + Res1 = Module:start_replication(C, SlotName, Parent, {C, Parent}, "0/0"), ?assertEqual(ok, Res1), + ErrorReceivedMsg = error_received, spawn( fun() -> - %% This connection will be terminated due to an unexpected message: + %% Test that the second connection receives the ReadyForQuery message from PG + %% synchronously after getting an error that the slot is occupied: %% ReadyForQuery (B), Byte1('Z'), Int32(5), Byte1 %% https://www.postgresql.org/docs/current/protocol-message-formats.html - process_flag(trap_exit, true), - C2 = epgsql_ct:connect(Config, User, [{replication, "database"}]), - Res2 = Module:start_replication(C2, "epgsql_test", self(), {C2, self()}, "0/0"), - ?assertMatch({error, _}, Res2), - Parent ! error_received + epgsql_ct:with_connection( + Config, + fun(C2) -> + Res2 = Module:start_replication(C2, SlotName, self(), {C2, self()}, "0/0"), + ?assertMatch({error, #error{codename = object_in_use}}, Res2), + Parent ! ErrorReceivedMsg + end, + User, + [{replication, "database"}]) end), receive - Result -> ?assertEqual(error_received, Result) + Result -> ?assertEqual(ErrorReceivedMsg, Result) after - 1000 -> ?assert(false, "Error hasn't been received when establishing " - "a second connection to the same replication slot") + 1000 -> ?assert(false, "Expected answer hasn't been received in 1000ms when " + "establishing a second connection to the same replication slot") end end, User, From db2f46450b6a594279f8857abeaa3209f6411c2a Mon Sep 17 00:00:00 2001 From: Yury Yantsevich Date: Tue, 3 Jan 2023 09:27:33 +0100 Subject: [PATCH 05/12] Add test which tries to start replication on an undefined slot --- test/epgsql_replication_SUITE.erl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/epgsql_replication_SUITE.erl b/test/epgsql_replication_SUITE.erl index 261f11fd..a532ea86 100644 --- a/test/epgsql_replication_SUITE.erl +++ b/test/epgsql_replication_SUITE.erl @@ -10,6 +10,7 @@ connect_in_repl_mode/1, create_drop_replication_slot/1, + no_replication_slot/1, replication_sync/1, replication_async/1, replication_async_active_n_socket/1, @@ -30,6 +31,7 @@ end_per_suite(_Config) -> all() -> [connect_in_repl_mode, create_drop_replication_slot, + no_replication_slot, replication_async, replication_sync, replication_async_active_n_socket, @@ -116,6 +118,17 @@ two_replications_on_same_slot(Config) -> [{replication, "database"}]), drop_replication_slot(Config). +no_replication_slot(Config) -> + Module = ?config(module, Config), + epgsql_ct:with_connection( + Config, + fun(C) -> + Res = Module:start_replication(C, "epgsql_test", self(), {C, self()}, "0/0"), + ?assertMatch({error, #error{codename = undefined_object}}, Res) + end, + "epgsql_test_replication", + [{replication, "database"}]). + replication_test_run(Config, Callback) -> replication_test_run(Config, Callback, []). From a217b0008080cc26fbc1f4e7bfc2efdb7a44e3e1 Mon Sep 17 00:00:00 2001 From: Yakov Kozlov Date: Wed, 19 Apr 2023 12:48:52 +0300 Subject: [PATCH 06/12] Fix issue with columns in multiple squery response --- src/commands/epgsql_cmd_squery.erl | 2 +- test/epgsql_SUITE.erl | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/commands/epgsql_cmd_squery.erl b/src/commands/epgsql_cmd_squery.erl index b324a2b5..57b2d416 100644 --- a/src/commands/epgsql_cmd_squery.erl +++ b/src/commands/epgsql_cmd_squery.erl @@ -63,7 +63,7 @@ handle_message(?COMMAND_COMPLETE, Bin, Sock, #squery{columns = Cols} = St) -> _ -> {ok, Cols, Rows} end, - {add_result, Result, {complete, Complete}, Sock, St}; + {add_result, Result, {complete, Complete}, Sock, St#squery{columns = []}}; handle_message(?EMPTY_QUERY, _, Sock, St) -> {add_result, {ok, [], []}, {complete, empty}, Sock, St}; handle_message(?READY_FOR_QUERY, _Status, Sock, _State) -> diff --git a/test/epgsql_SUITE.erl b/test/epgsql_SUITE.erl index 4ac90035..07e40578 100644 --- a/test/epgsql_SUITE.erl +++ b/test/epgsql_SUITE.erl @@ -530,8 +530,14 @@ cursor(Config) -> multiple_result(Config) -> Module = ?config(module, Config), epgsql_ct:with_connection(Config, fun(C) -> + Module:squery(C, "delete test_table1 where id = 3;"), [{ok, _, [{<<"1">>}]}, {ok, _, [{<<"2">>}]}] = Module:squery(C, "select 1; select 2"), - [{ok, _, [{<<"1">>}]}, {error, #error{}}] = Module:squery(C, "select 1; select foo;") + [{ok, _, [{<<"1">>}]}, {error, #error{}}] = Module:squery(C, "select 1; select foo;"), + [{ok, _, [{<<"one">>}]}, {ok, 1}, {ok, 1}] = + Module:squery(C, + "select value from test_table1 where id = 1; " + "insert into test_table1 (id, value) values (3, 'three');" + "delete from test_table1 where id = 3;") end). execute_batch(Config) -> From 80d68157715284a0d388bc3dda0f3cf8e509a96e Mon Sep 17 00:00:00 2001 From: Yakov Kozlov Date: Wed, 19 Apr 2023 16:11:16 +0300 Subject: [PATCH 07/12] Reset decoder in epgsql_cmd_squery state --- src/commands/epgsql_cmd_squery.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/epgsql_cmd_squery.erl b/src/commands/epgsql_cmd_squery.erl index 57b2d416..17b01e6f 100644 --- a/src/commands/epgsql_cmd_squery.erl +++ b/src/commands/epgsql_cmd_squery.erl @@ -32,7 +32,7 @@ -record(squery, {query :: iodata(), columns = [], - decoder}). + decoder = undefined :: epgsql_wire:row_decoder() | undefined}). init(Sql) -> #squery{query = Sql}. @@ -63,7 +63,8 @@ handle_message(?COMMAND_COMPLETE, Bin, Sock, #squery{columns = Cols} = St) -> _ -> {ok, Cols, Rows} end, - {add_result, Result, {complete, Complete}, Sock, St#squery{columns = []}}; + {add_result, Result, {complete, Complete}, Sock, St#squery{columns = [], + decoder = undefined}}; handle_message(?EMPTY_QUERY, _, Sock, St) -> {add_result, {ok, [], []}, {complete, empty}, Sock, St}; handle_message(?READY_FOR_QUERY, _Status, Sock, _State) -> From 4801c0050663aaeb9876e5c15e3ed9e47b21ff13 Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Tue, 16 May 2023 15:46:56 +0200 Subject: [PATCH 08/12] Add OTP-26 to CI --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47057c83..c835bda9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,8 @@ jobs: postgis: - "3" otp: - - "25.2" + - "26.0" + - "25.3" - "24.3" rebar3: - "3.20.0" From 71a6b904398b26c37021f79a4f793643f323121c Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Wed, 17 May 2023 16:24:53 +0200 Subject: [PATCH 09/12] Make it compatible with OTP-26 * Don't call `prim_inet` port directly * Add `verify=verify_none` option in SSL tests --- src/epgsql_sock.erl | 15 ++++++++++++--- test/epgsql_SUITE.erl | 9 ++++++--- test/epgsql_replication_SUITE.erl | 4 +++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/epgsql_sock.erl b/src/epgsql_sock.erl index 3a61d7b6..9d3e74be 100644 --- a/src/epgsql_sock.erl +++ b/src/epgsql_sock.erl @@ -488,6 +488,15 @@ send_multi(#state{mod = Mod, sock = Sock}, List) -> end, List)). do_send(gen_tcp, Sock, Bin) -> + gen_tcp_send(Sock, Bin); +do_send(ssl, Sock, Bin) -> + ssl:send(Sock, Bin). + +-if(?OTP_RELEASE >= 26). +gen_tcp_send(Sock, Bin) -> + gen_tcp:send(Sock, Bin). +-else. +gen_tcp_send(Sock, Bin) -> %% Why not gen_tcp:send/2? %% See https://github.com/rabbitmq/rabbitmq-common/blob/v3.7.4/src/rabbit_writer.erl#L367-L384 %% Since `epgsql' uses `{active, true}' socket option by-default, it may potentially quickly @@ -496,15 +505,15 @@ do_send(gen_tcp, Sock, Bin) -> %% `{active, true}' is still the default. %% %% Because we use `inet' driver directly, we also have `handle_info({inet_reply, ...` + %% This `gen_tcp:send/2' problem have been solved in OTP-26, so this hack is no longer needed. try erlang:port_command(Sock, Bin) of true -> ok catch error:_Error -> {error, einval} - end; -do_send(ssl, Sock, Bin) -> - ssl:send(Sock, Bin). + end. +-endif. loop(#state{data = Data, handler = Handler, subproto_state = Repl} = State) -> case epgsql_wire:decode_message(Data) of diff --git a/test/epgsql_SUITE.erl b/test/epgsql_SUITE.erl index 4ac90035..40a842d5 100644 --- a/test/epgsql_SUITE.erl +++ b/test/epgsql_SUITE.erl @@ -306,7 +306,7 @@ connect_with_ssl(Config) -> {ok, _Cols, [{true}]} = Module:equery(C, "select ssl_is_used()") end, "epgsql_test", - [{ssl, true}]). + [{ssl, true}, {ssl_opts, [{verify, verify_none}]}]). cancel_query_for_connection_with_ssl(Config) -> Module = ?config(module, Config), @@ -314,6 +314,7 @@ cancel_query_for_connection_with_ssl(Config) -> Module = ?config(module, Config), Args2 = [ {port, Port}, {database, "epgsql_test_db1"} | [ {ssl, true} + , {ssl_opts, [{verify, verify_none}]} , {timeout, 1000} ] ], {ok, C} = Module:connect(Host, "epgsql_test", Args2), @@ -377,7 +378,8 @@ connect_with_client_cert(Config) -> end, "epgsql_test_cert", [{ssl, true}, {ssl_opts, [{keyfile, File("client.key")}, - {certfile, File("client.crt")}]}]). + {certfile, File("client.crt")}, + {verify, verify_none}]}]). connect_with_invalid_client_cert(Config) -> {Host, Port} = epgsql_ct:connection_data(Config), @@ -407,6 +409,7 @@ connect_with_invalid_client_cert(Config) -> ssl_opts => [{keyfile, File("bad-client.key")}, {certfile, File("bad-client.crt")}, + {verify, verify_none}, %% TLS-1.3 seems to connect fine, but then sends alert asynchronously {versions, ['tlsv1.2']} ]} @@ -1649,7 +1652,7 @@ incremental_sock_active_n_ssl(Config) -> ?assertEqual(10241, length(Rows)) end, "epgsql_test", - [{ssl, true}, {socket_active, 2}]). + [{ssl, true}, {ssl_opts, [{verify, verify_none}]}, {socket_active, 2}]). -else. %% {active, N} for SSL is only supported on OTP-21+ incremental_sock_active_n_ssl(_Config) -> diff --git a/test/epgsql_replication_SUITE.erl b/test/epgsql_replication_SUITE.erl index a532ea86..d0510d4c 100644 --- a/test/epgsql_replication_SUITE.erl +++ b/test/epgsql_replication_SUITE.erl @@ -72,7 +72,9 @@ replication_sync_active_n_socket(Config) -> -ifdef(OTP_RELEASE). replication_async_active_n_ssl(Config) -> - replication_test_run(Config, self(), [{socket_active, 1}, {ssl, require}]). + replication_test_run(Config, self(), [{socket_active, 1}, + {ssl, require}, + {ssl_opts, [{verify, verify_none}]}]). -else. %% {active, N} for SSL is only supported on OTP-21+ replication_async_active_n_ssl(Config) -> From 6d043123b1d5a7eb9f4c9fa51c4aa129cd69c8bf Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Wed, 17 May 2023 16:30:42 +0200 Subject: [PATCH 10/12] Drop OTP-20 So OTP_RELEASE macro could be freely used --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c835bda9..e6ae880d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,11 +43,6 @@ jobs: rebar3: "3.15.2" pg: "12" postgis: "3" - - os: "ubuntu-20.04" - otp: "20.3" - rebar3: "3.15.2" - pg: "12" - postgis: "3" # env: # PATH: ".:/usr/lib/postgresql/12/bin:$PATH" From 71255821c7c7f1c49539cea920f43c10a44ad44f Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Fri, 26 May 2023 11:56:07 +0200 Subject: [PATCH 11/12] Bump version to 4.7.1 --- CHANGES | 6 ++++++ src/epgsql.app.src | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 55b935ff..206a597c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +In 4.7.1 + +* Handle `ReadyForQuery` after `Error` in replication mode #279 +* Fix the issue with columns in multi-squery response #283 +* Fix compatibility with OTP-26 #284 + In 4.7.0 * Flow control `{socket_active, N}` option in streaming replication #271 diff --git a/src/epgsql.app.src b/src/epgsql.app.src index bce2cd49..46b36b86 100644 --- a/src/epgsql.app.src +++ b/src/epgsql.app.src @@ -1,6 +1,6 @@ {application, epgsql, [{description, "PostgreSQL Client"}, - {vsn, "4.7.0"}, + {vsn, "4.7.1"}, {modules, []}, {registered, []}, {applications, [kernel, From 7ba52768cf0ea7d084df24d4275a88eef4db13c2 Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Fri, 26 May 2023 12:16:13 +0200 Subject: [PATCH 12/12] Update apt cache before install --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6ae880d..09b12c65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: rebar3-version: ${{ matrix.rebar3 }} - name: Setup postgresql server with postgis - run: sudo apt install postgresql-${{matrix.pg}} postgresql-contrib-${{matrix.pg}} postgresql-${{matrix.pg}}-postgis-${{matrix.postgis}} postgresql-${{matrix.pg}}-postgis-${{matrix.postgis}}-scripts + run: sudo apt update && sudo apt install postgresql-${{matrix.pg}} postgresql-contrib-${{matrix.pg}} postgresql-${{matrix.pg}}-postgis-${{matrix.postgis}} postgresql-${{matrix.pg}}-postgis-${{matrix.postgis}}-scripts - name: elvis run: make elvis