Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgu2s-006Uxr-26 for pgsql-hackers@arkaria.postgresql.org; Sat, 17 Jan 2026 00:20:03 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vgu2q-005lw2-0Q for pgsql-hackers@arkaria.postgresql.org; Sat, 17 Jan 2026 00:20:00 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgu2p-005lvo-2h for pgsql-hackers@lists.postgresql.org; Sat, 17 Jan 2026 00:20:00 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgu2n-000uI6-2C for pgsql-hackers@postgresql.org; Sat, 17 Jan 2026 00:19:59 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 60H0JcAc1892299; Fri, 16 Jan 2026 19:19:38 -0500 From: Tom Lane To: Soumya S Murali cc: Oleg Tselebrovskiy , pgsql-hackers@postgresql.org Subject: Re: 001_password.pl fails with --without-readline In-reply-to: <1718312.1768603611@sss.pgh.pa.us> References: <1768548191.602324347@fmail2.qdit> <1718312.1768603611@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Fri, 16 Jan 2026 17:46:51 -0500" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <1892274.1768609173.0@sss.pgh.pa.us> Date: Fri, 16 Jan 2026 19:19:38 -0500 Message-ID: <1892298.1768609178@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1892274.1768609173.1@sss.pgh.pa.us> I wrote: > There are various ways that could be done, but what I propose in the > attached v3 is to break the banner into two psql variables, like so: > \set part1 something > \set part2 else > \echo :part1 :part2 > Then, if we match for "something else", there is no possibility > whatsoever that that will match echoed commands, only the real > output of the \echo. On second thought, that's far more complicated than necessary. It should be sufficient to insert quote marks in the echo commands. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="v4-0001-background-psql-without-readline.patch"; charset="us-ascii" Content-ID: <1892274.1768609173.2@sss.pgh.pa.us> Content-Description: v4-0001-background-psql-without-readline.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm b/src/test/pe= rl/PostgreSQL/Test/BackgroundPsql.pm index 5bd41a278dd..eb2a252a7d7 100644 --- a/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm +++ b/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm @@ -100,7 +100,7 @@ sub new "Forbidden caller of constructor: package: $package, file: $file:$line= " unless $package->isa('PostgreSQL::Test::Cluster'); = - $psql->{timeout} =3D IPC::Run::timeout( + $psql->{timeout} =3D IPC::Run::timer( defined($timeout) ? $timeout : $PostgreSQL::Test::Utils::timeout_default); @@ -155,11 +155,11 @@ sub wait_connect # # See query() for details about why/how the banner is used. my $banner =3D "background_psql: ready"; - my $banner_match =3D qr/(^|\n)$banner\r?\n/; - $self->{stdin} .=3D "\\echo $banner\n\\warn $banner\n"; + my $banner_match =3D qr/$banner\r?\n/; + $self->{stdin} .=3D "\\echo '$banner'\n\\warn '$banner'\n"; $self->{run}->pump() until ($self->{stdout} =3D~ /$banner_match/ - && $self->{stderr} =3D~ /$banner\r?\n/) + && $self->{stderr} =3D~ /$banner_match/) || $self->{timeout}->is_expired; = note "connect output:\n", @@ -264,22 +264,17 @@ sub query # stderr (or vice versa), even if psql printed them in the opposite # order. We therefore wait on both. # - # We need to match for the newline, because we try to remove it below, a= nd - # it's possible to consume just the input *without* the newline. In - # interactive psql we emit \r\n, so we need to allow for that. Also need - # to be careful that we don't e.g. match the echoed \echo command, rathe= r - # than its output. + # In interactive psql we emit \r\n, so we need to allow for that. + # Also, include quotes around the banner string in the \echo and \warn + # commands, not because the string needs quoting but so that $banner_mat= ch + # can't match readline's echoing of these commands. my $banner =3D "background_psql: QUERY_SEPARATOR $query_cnt:"; - my $banner_match =3D qr/(^|\n)$banner\r?\n/; - $self->{stdin} .=3D "$query\n;\n\\echo $banner\n\\warn $banner\n"; - pump_until( - $self->{run}, $self->{timeout}, - \$self->{stdout}, qr/$banner_match/); - pump_until( - $self->{run}, $self->{timeout}, - \$self->{stderr}, qr/$banner_match/); - - die "psql query timed out" if $self->{timeout}->is_expired; + my $banner_match =3D qr/$banner\r?\n/; + $self->{stdin} .=3D "$query\n;\n\\echo '$banner'\n\\warn '$banner'\n"; + $self->{run}->pump() + until ($self->{stdout} =3D~ /$banner_match/ + && $self->{stderr} =3D~ /$banner_match/) + || $self->{timeout}->is_expired; = note "results query $query_cnt:\n", explain { @@ -287,9 +282,12 @@ sub query stderr =3D> $self->{stderr}, } unless !$params{verbose}; = - # Remove banner from stdout and stderr, our caller doesn't care. The - # first newline is optional, as there would not be one if consuming an - # empty query result. + die "psql query timed out" if $self->{timeout}->is_expired; + + # Remove banner from stdout and stderr, our caller doesn't want it. + # Also remove the query output's trailing newline, if present (there + # would not be one if consuming an empty query result). + $banner_match =3D qr/\r?\n?$banner\r?\n/; $output =3D $self->{stdout}; $output =3D~ s/$banner_match//; $self->{stderr} =3D~ s/$banner_match//; ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="v4-0002-030-pager-fix.patch"; charset="us-ascii" Content-ID: <1892274.1768609173.3@sss.pgh.pa.us> Content-Description: v4-0002-030-pager-fix.patch diff --git a/src/bin/psql/t/030_pager.pl b/src/bin/psql/t/030_pager.pl index cf81fb1603c..a35f2b26293 100644 --- a/src/bin/psql/t/030_pager.pl +++ b/src/bin/psql/t/030_pager.pl @@ -40,6 +40,36 @@ my $node = PostgreSQL::Test::Cluster->new('main'); $node->init; $node->start; +# create a view we'll use below +$node->safe_psql( + 'postgres', 'create view public.view_030_pager as select +1 as a, +2 as b, +3 as c, +4 as d, +5 as e, +6 as f, +7 as g, +8 as h, +9 as i, +10 as j, +11 as k, +12 as l, +13 as m, +14 as n, +15 as o, +16 as p, +17 as q, +18 as r, +19 as s, +20 as t, +21 as u, +22 as v, +23 as w, +24 as x, +25 as y, +26 as z'); + # fire up an interactive psql session my $h = $node->interactive_psql('postgres'); @@ -77,25 +107,28 @@ sub do_command # # Note that interactive_psql starts psql with --no-align --tuples-only, # and that the output string will include psql's prompts and command echo. +# So we have to test for patterns that can't match the command itself, +# and we can't assume the match will extend across a whole line (there +# might be a prompt ahead of it in the output). do_command( "SELECT 'test' AS t FROM generate_series(1,23);\n", - qr/^test\r?$/m, + qr/test\r?$/m, "execute SELECT query that needs no pagination"); do_command( "SELECT 'test' AS t FROM generate_series(1,24);\n", - qr/^ *24\r?$/m, + qr/24\r?$/m, "execute SELECT query that needs pagination"); do_command( "\\pset expanded\nSELECT generate_series(1,20) as g;\n", - qr/^ *39\r?$/m, + qr/39\r?$/m, "execute SELECT query that needs pagination in expanded mode"); do_command( - "\\pset tuples_only off\n\\d+ information_schema.referential_constraints\n", - qr/^ *\d+\r?$/m, + "\\pset tuples_only off\n\\d+ public.view_030_pager\n", + qr/55\r?$/m, "execute command with footer that needs pagination"); # send psql an explicit \q to shut it down, else pty won't close properly ------- =_aaaaaaaaaa0--