Re: BackgroundPsql swallowing errors on windows

From: Arseniy Mukhin <arseniy(dot)mukhin(dot)dev(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Noah Misch <noah(at)leadboat(dot)com>, Andres Freund <andres(at)anarazel(dot)de>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: BackgroundPsql swallowing errors on windows
Date: 2025-09-27 18:39:07
Message-ID: CAE7r3MJwj2hMmHK-Fv87uGRkHM4ZFhAMCMk+wciU8+T50iFLGA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

I think I encountered the bug that relates to the patch from this
thread so I decided to write a report here.

version(): PostgreSQL 19devel on x86_64-linux, compiled by gcc-13.3.0,
64-bit. (master)

While writing a TAP test I noticed that background_psql hangs on a
simple query without any reason. The most simple reproducer I came up
with:

my $psql = $node->background_psql('postgres', timeout => 3);
$psql->query(q(\warn AAAAA));
$psql->query("select 1");

Here $psql->query("select 1;") hangs until timeout.

Here what I managed to understand after some investigation:

Just to remind how banner and banner_match look like:

my $banner = "background_psql: QUERY_SEPARATOR $query_cnt:";
my $banner_match = qr/(^|\n)$banner\r?\n/;

psql->query() hangs in an endless loop in pump_until() as the
termination condition (last if $$stream =~ /$until/) is never met.
Unfortunately, logs don't show the reason why we are stuck here (maybe
I do something wrong but it seems that [0] explains why pump_until()
timeout diag code doesn't work), so to get more information we need to
add some additional logging in pump_until(). If we add logging of
$$stream and $until then we can see next lines for pump_until() stderr
call:

STREAM: AAAAAbackground_psql: QUERY_SEPARATOR 2:
UNTIL: (?^:(^|\n)background_psql: QUERY_SEPARATOR 2:\r?\n)

STREAM here is what we have in stderr and UNTIL is just a banner_match.

You can see that we have stderr from the previous query ('AAAAA')
concatenated with the banner on the same line. So it doesn't match
what we have in $until pattern as it requires (^|\n) to be before the
banner. This way we have an endless loop. It seems that the reason we
don't have line separator after 'AAAAA' is a difference between how we
inject and remove the banner:

Here is a how we inject banner:

$self->{stdin} .= "$query\n;\n\\echo $banner\n\\warn $banner\n";

How we remove banner from stderr

$self->{stderr} =~ s/$banner_match//;

We remove from stderr not only the banner we previously injected with
warn, but also the line separator before the banner.

[0] https://www.postgresql.org/message-id/flat/1100715(dot)1712265845(at)sss(dot)pgh(dot)pa(dot)us

Best regards,
Arseniy Mukhin

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Kapila 2025-09-27 21:13:39 Re: Proposal: Conflict log history table for Logical Replication
Previous Message Vik Fearing 2025-09-27 18:14:58 Re: [PATCH] GROUP BY ALL