From 6bdfce16db32266e2f1586db7489fca1cf398c21 Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Sun, 6 Sep 2026 15:00:55 +0200 Subject: [PATCH] Rearm SimpleConnection after query errors --- lib/postgrex/simple_connection.ex | 9 ++++++++- test/simple_connection_test.exs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/postgrex/simple_connection.ex b/lib/postgrex/simple_connection.ex index 98477d3b..2f663f0b 100644 --- a/lib/postgrex/simple_connection.ex +++ b/lib/postgrex/simple_connection.ex @@ -476,7 +476,14 @@ defmodule Postgrex.SimpleConnection do handle(mod, :handle_result, [results, mod_state], from, state) else {:error, %Postgrex.Error{} = error, protocol} -> - handle(mod, :handle_result, [error, mod_state], from, %{state | protocol: protocol}) + case Protocol.checkin(protocol) do + {:ok, protocol} -> + state = %{state | protocol: protocol} + handle(mod, :handle_result, [error, mod_state], from, state) + + {:disconnect, reason, protocol} -> + reconnect_or_stop(:disconnect, reason, protocol, state) + end {:disconnect, reason, protocol} -> reconnect_or_stop(:disconnect, reason, protocol, state) diff --git a/test/simple_connection_test.exs b/test/simple_connection_test.exs index 33a676cc..aa5ef2dd 100644 --- a/test/simple_connection_test.exs +++ b/test/simple_connection_test.exs @@ -127,6 +127,30 @@ defmodule SimpleConnectionTest do test "relaying query errors", context do assert {:ok, %Postgrex.Error{}} = SC.call(context.conn, {:query, "SELCT"}) end + + @tag opts: [idle_interval: :infinity] + test "rearms the socket after a query error", context do + notifier = start_supervised!({Postgrex, @opts}) + channel = "simple_connection_error_#{System.unique_integer([:positive])}" + + assert {:ok, _result} = + SC.call(context.conn, {:query, ~s(LISTEN "#{channel}")}) + + assert {:ok, _result} = + Postgrex.query(notifier, ~s(NOTIFY "#{channel}", 'before'), []) + + assert_receive {^channel, "before"} + + assert {:ok, %Postgrex.Error{postgres: %{code: :division_by_zero}}} = + SC.call(context.conn, {:query, "SELECT 1/0"}) + + assert {:ok, [active: :once]} = :inet.getopts(socket(context.conn), [:active]) + + assert {:ok, _result} = + Postgrex.query(notifier, ~s(NOTIFY "#{channel}", 'after'), []) + + assert_receive {^channel, "after"} + end end describe "notify/3" do @@ -228,6 +252,12 @@ defmodule SimpleConnectionTest do :gen_tcp.shutdown(sock, :read_write) end + defp socket(conn) do + {_, state} = :sys.get_state(conn) + {:gen_tcp, sock} = state.protocol.sock + sock + end + defp backend_message(type, data) do [type, <>, data] end