Greetings!

If you configure PostgreSQL with --without-readline, test authentication/t/001_password.pl fails due to timeout

This can be reproduced on any branch that contains commit 8b886a4 (so, on PostgreSQL 13-19)

I've looked through debug info using IPCRUNDEBUG = "data" or "details"

Here's some output:

This is with readline:
    [18:31:45.030](0.027s) ok 22 - scram_iterations in server side ROLE
    IPC::Run 0001 [#15(253566)]: ** pumping
IPC::Run 0001 [#15(253566)]: write( 10, '\echo background_psql: ready
    IPC::Run 0001 [#15(253566)]: \warn background_psql: ready
    IPC::Run 0001 [#15(253566)]: ' ) = 58
    IPC::Run 0001 [#15(253566)]: ** pumping
IPC::Run 0001 [#15(253566)]: read( 10 ) = 60 chars '\echo background_psql: ready
    IPC::Run 0001 [#15(253566)]: \warn background_psql: ready
    IPC::Run 0001 [#15(253566)]: '
    IPC::Run 0001 [#15(253566)]: ** pumping
    IPC::Run 0001 [#15(253566)]: read( 10 ) = 41 chars 'psql (19devel)
    IPC::Run 0001 [#15(253566)]: Type "help" for help.
    IPC::Run 0001 [#15(253566)]:
    IPC::Run 0001 [#15(253566)]: '
    IPC::Run 0001 [#15(253566)]: ** pumping
    IPC::Run 0001 [#15(253566)]: read( 10 ) = 11 chars 'postgres=# '
    IPC::Run 0001 [#15(253566)]: ** pumping
IPC::Run 0001 [#15(253566)]: read( 10 ) = 65 chars '\echo background_psql: ready
    IPC::Run 0001 [#15(253566)]: background_psql: ready
    IPC::Run 0001 [#15(253566)]: postgres=# '
    IPC::Run 0001 [#15(253566)]: ** pumping
IPC::Run 0001 [#15(253566)]: read( 10 ) = 41 chars '\warn background_psql: ready
    IPC::Run 0001 [#15(253566)]: postgres=# '
IPC::Run 0001 [#15(253566)]: read( 12 ) = 23 chars 'background_psql: ready
    IPC::Run 0001 [#15(253566)]: '
    [18:31:45.042](0.013s) # connect output:

And this is without readline:
    [18:34:32.050](0.029s) ok 22 - scram_iterations in server side ROLE
    IPC::Run 0001 [#15(263802)]: ** pumping
IPC::Run 0001 [#15(263802)]: write( 10, '\echo background_psql: ready
    IPC::Run 0001 [#15(263802)]: \warn background_psql: ready
    IPC::Run 0001 [#15(263802)]: ' ) = 58
    IPC::Run 0001 [#15(263802)]: ** pumping
IPC::Run 0001 [#15(263802)]: read( 10 ) = 60 chars '\echo background_psql: ready
    IPC::Run 0001 [#15(263802)]: \warn background_psql: ready
    IPC::Run 0001 [#15(263802)]: '
    IPC::Run 0001 [#15(263802)]: ** pumping
    IPC::Run 0001 [#15(263802)]: read( 10 ) = 98 chars 'psql (19devel)
    IPC::Run 0001 [#15(263802)]: Type "help" for help.
    IPC::Run 0001 [#15(263802)]:
    IPC::Run 0001 [#15(263802)]: postgres=# background_psql: ready
    IPC::Run 0001 [#15(263802)]: postgres=# postgres=# '
    IPC::Run 0001 [#15(263802)]: ** pumping
IPC::Run 0001 [#15(263802)]: read( 12 ) = 23 chars 'background_psql: ready
    IPC::Run 0001 [#15(263802)]: '
    IPC::Run 0001 [#15(263802)]: ** pumping

As you can see, those outputs are different

1) In readline output commands \echo and \warn are re-read (that's why banner_match in BackgroundPsql.pm has checks for \n or start of line), but in no-readline output both \echo and \warn are read only once, when they are first send to psql

2) In readline ouput stdout is re-read multiple times, and banner (background_psql: ready) is placed neatly on it's own line, while in no-readline output banner in stdout is mixed with "postgres=#" prompts, and they are read as one batch

Those differences are probably an effect of inner workings of readline, turning input echoing off.

Also, without readline, stdout during query exectution can look like this
    # \\echo background_psql: QUERY_SEPARATOR 1:
    # \\warn background_psql: QUERY_SEPARATOR 1:
    # SET
    # postgres=# postgres=# background_psql: QUERY_SEPARATOR 1:
    # postgres=# '

So, there are some ways to handle this situation

1) Skip this test if Postgres is configured without readline support. I don't think this is a good way, since this test doesn't really test anything that needs readline to work

2) Modify variable banner_match depending on having readline or not. Something like the attached

I'm interested to hear your thoughts on this

Oleg Tselebrovskiy, PostgresPro
diff --git a/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm b/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm
index 60bbd5dd445..dce7ccd64d0 100644
--- a/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm
+++ b/src/test/perl/PostgreSQL/Test/BackgroundPsql.pm
@@ -156,6 +156,13 @@ sub wait_connect
 	# See query() for details about why/how the banner is used.
 	my $banner = "background_psql: ready";
 	my $banner_match = qr/(^|\n)$banner\r?\n/;
+
+	# See comment on similar check in query()
+	if (!defined($ENV{with_readline}) || $ENV{with_readline} ne 'yes')
+	{
+		$banner_match = qr/postgres=# $banner\r?\n/;
+	}
+
 	$self->{stdin} .= "\\echo $banner\n\\warn $banner\n";
 	$self->{run}->pump()
 	  until ($self->{stdout} =~ /$banner_match/
@@ -265,14 +272,22 @@ sub query
 	# to be careful that we don't e.g. match the echoed \echo command, rather
 	# than its output.
 	my $banner = "background_psql: QUERY_SEPARATOR $query_cnt:";
-	my $banner_match = qr/(^|\n)$banner\r?\n/;
+	my $banner_match_stdout = qr/(^|\n)$banner\r?\n/;
+	my $banner_match_stderr = $banner_match_stdout;
+	# If we are built without readline, normal regex doesn't work, since stdout
+	# is read all at once, and the banner is preceeded by "postgres#= ".
+	# stderr still contains only the banner.
+	if (!defined($ENV{with_readline}) || $ENV{with_readline} ne 'yes')
+	{
+		$banner_match_stdout = qr/postgres=# $banner\r?\n/;
+	}
 	$self->{stdin} .= "$query\n;\n\\echo $banner\n\\warn $banner\n";
 	pump_until(
 		$self->{run}, $self->{timeout},
-		\$self->{stdout}, qr/$banner_match/);
+		\$self->{stdout}, qr/$banner_match_stdout/);
 	pump_until(
 		$self->{run}, $self->{timeout},
-		\$self->{stderr}, qr/$banner_match/);
+		\$self->{stderr}, qr/$banner_match_stderr/);
 
 	die "psql query timed out" if $self->{timeout}->is_expired;
 
@@ -286,8 +301,8 @@ sub query
 	# first newline is optional, as there would not be one if consuming an
 	# empty query result.
 	$output = $self->{stdout};
-	$output =~ s/$banner_match//;
-	$self->{stderr} =~ s/$banner_match//;
+	$output =~ s/$banner_match_stdout//;
+	$self->{stderr} =~ s/$banner_match_stdout//;
 
 	# clear out output for the next query
 	$self->{stdout} = '';

Reply via email to