agora inbox for pgsql-bugs@postgresql.org  
help / color / mirror / Atom feed
COPY TO regression with psql -c
7+ messages / 3 participants
[nested] [flat]

* COPY TO regression with psql -c
@ 2026-08-11 19:32  Zsolt Parragi <zsolt.parragi@percona.com>
  0 siblings, 2 replies; 7+ messages in thread

From: Zsolt Parragi @ 2026-08-11 19:32 UTC (permalink / raw)
  To: pgsql-bugs@lists.postgresql.org

Hello

The recent COPY ... FROM STDIN improvement caused a regression in COPY
TO ... FROM STDIN when used together with psql -c: it only considers
the first statement, so the copy fails if multiple commands are
specified. A very simple example is:

psql -c "SELECT 1; COPY t FROM STDIN;"

now fails with unexpected COPY_IN.

This is probably an uncommon use case, but it has a few legitimate
uses in scripts, such as:

gzip -dc data.csv.gz | psql -c 'TRUNCATE t; COPY t FROM STDIN WITH (FORMAT CSV)'

to (re)load a table's data.

I attached a proposed patch with a tap test case that showcases the issue.

Attachments:

  [application/octet-stream] 0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-que.patch (4.8K, ../../CAN4CZFPqa6c+u4uX5jJ8LANHTQ4dxM3m4_8G9WmX_A4-2wuv2A@mail.gmail.com/2-0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-que.patch)
  download | inline diff:
From 1008093a2b76cb57bee12df7223d100bab49eded Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Tue, 11 Aug 2026 18:16:28 +0000
Subject: [PATCH] psql: count every COPY FROM STDIN when scanning a query
 string

When SendQuery() is not told how many COPY FROM STDIN commands the query
string contains (num_copy_from_stdin < 0, as for -c, \gexec and forced
sends), it scanned the string to count them itself.  But it called
psql_scan() only once, which stops at the first semicolon, so any COPY
FROM STDIN past the first sub-command was not counted.  psql then treated
the server's COPY_IN response as unexpected and closed the connection
with "unexpected COPY_IN result, aborting connection", e.g. for

    psql -c "SELECT 1; COPY tab FROM STDIN" < data

which worked before the counting was added.

Loop psql_scan() over the whole string so the count accumulates across
all sub-commands.  Add a TAP test covering a lone COPY, a COPY after
another command, and two COPYs in one string.

Oversight in commit 3045a25ba81.
---
 src/bin/psql/common.c                  | 12 +++-
 src/bin/psql/meson.build               |  1 +
 src/bin/psql/t/040_copy_stdin_count.pl | 78 ++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/psql/t/040_copy_stdin_count.pl

diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 314bf2388ac..e5a37d7073f 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -1796,13 +1796,23 @@ ExecQueryAndProcessResults(const char *query,
 		PsqlScanState scan_state;
 		PQExpBuffer query_buf;
 		promptStatus_t prompt_tmp;
+		PsqlScanResult scan_result;
 
 		scan_state = psql_scan_create(&psqlscan_callbacks);
 		psql_scan_setup(scan_state, query, strlen(query),
 						pset.encoding, standard_strings());
 		query_buf = createPQExpBuffer();
 
-		(void) psql_scan(scan_state, query_buf, &prompt_tmp);
+		/*
+		 * A semicolon ends only one sub-command; keep scanning so that COPY
+		 * FROM STDIN commands past the first semicolon are counted too.  The
+		 * count accumulates in scan_state across the psql_scan() calls.
+		 */
+		do
+		{
+			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
+			resetPQExpBuffer(query_buf);
+		} while (scan_result == PSCAN_SEMICOLON);
 
 		num_copy_from_stdin = psql_scan_count_copy_from_stdin(scan_state);
 
diff --git a/src/bin/psql/meson.build b/src/bin/psql/meson.build
index 922b2845267..d6a671d0017 100644
--- a/src/bin/psql/meson.build
+++ b/src/bin/psql/meson.build
@@ -78,6 +78,7 @@ tests += {
       't/010_tab_completion.pl',
       't/020_cancel.pl',
       't/030_pager.pl',
+      't/040_copy_stdin_count.pl',
     ],
   },
 }
diff --git a/src/bin/psql/t/040_copy_stdin_count.pl b/src/bin/psql/t/040_copy_stdin_count.pl
new file mode 100644
index 00000000000..7eee668535e
--- /dev/null
+++ b/src/bin/psql/t/040_copy_stdin_count.pl
@@ -0,0 +1,78 @@
+
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test that psql counts every COPY ... FROM STDIN in a query string when it has
+# to scan the string itself (the -c / \gexec / forced-send paths).  A COPY that
+# is not the first sub-command must still be recognized, otherwise psql treats
+# the server's COPY_IN response as unexpected and aborts the connection.
+
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->start;
+
+$node->safe_psql('postgres', 'CREATE TABLE t (a int)');
+
+# Run "psql -c $sql" with $stdin fed to psql's stdin (so COPY FROM STDIN reads
+# it).  Returns (success, stdout, stderr).
+sub psql_c_stdin
+{
+	my ($sql, $stdin) = @_;
+	my ($stdout, $stderr) = ('', '');
+
+	my $ret = IPC::Run::run(
+		[
+			'psql', '-X', '-v' => 'ON_ERROR_STOP=1',
+			'-d' => $node->connstr('postgres'),
+			'-c' => $sql
+		],
+		'<' => \$stdin,
+		'>' => \$stdout,
+		'2>' => \$stderr);
+
+	return ($ret, $stdout, $stderr);
+}
+
+my @cases = (
+	{
+		name => 'single COPY FROM STDIN',
+		sql => 'COPY t FROM STDIN',
+		data => "10\n20\n\\.\n",
+		rows => 2,
+	},
+	{
+		name => 'COPY FROM STDIN after another command',
+		sql => 'SELECT 1; COPY t FROM STDIN',
+		data => "30\n40\n\\.\n",
+		rows => 2,
+	},
+	{
+		name => 'two COPY FROM STDIN in one string',
+		sql => 'COPY t FROM STDIN; COPY t FROM STDIN',
+		data => "50\n\\.\n60\n\\.\n",
+		rows => 2,
+	});
+
+foreach my $c (@cases)
+{
+	$node->safe_psql('postgres', 'TRUNCATE t');
+
+	my ($ok, $stdout, $stderr) = psql_c_stdin($c->{sql}, $c->{data});
+
+	ok($ok, "$c->{name}: psql exits 0");
+	unlike($stderr, qr/unexpected COPY_IN result/,
+		"$c->{name}: connection not aborted");
+
+	my $count = $node->safe_psql('postgres', 'SELECT count(*) FROM t');
+	is($count, $c->{rows}, "$c->{name}: all rows loaded");
+}
+
+$node->stop;
+
+done_testing();
-- 
2.54.0



^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-12 08:37  Christoph Berg <myon@debian.org>
  parent: Zsolt Parragi <zsolt.parragi@percona.com>
  1 sibling, 0 replies; 7+ messages in thread

From: Christoph Berg @ 2026-08-12 08:37 UTC (permalink / raw)
  To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: pgsql-bugs@lists.postgresql.org

Re: Zsolt Parragi
> psql -c "SELECT 1; COPY t FROM STDIN;"

The Debian package tests are also tripping over this. The test case
there is (in the encoding test file, hence the weird chars):

printf '���' | psql -qc "set client_encoding='iso-8859-5'; create table t (x varchar); copy t from stdin"
SET
CREATE TABLE
unexpected COPY_IN result, aborting connection

2026-08-12 10:31:46.434 CEST [77760] ERROR:  unexpected EOF on client connection with an open transaction
2026-08-12 10:31:46.434 CEST [77760] CONTEXT:  COPY t, line 1
2026-08-12 10:31:46.434 CEST [77760] STATEMENT:  set client_encoding='iso-8859-5'; create table t (x varchar); copy t from stdin
2026-08-12 10:31:46.434 CEST [77760] LOG:  could not send data to client: Broken pipe
2026-08-12 10:31:46.434 CEST [77760] STATEMENT:  set client_encoding='iso-8859-5'; create table t (x varchar); copy t from stdin
2026-08-12 10:31:46.434 CEST [77760] FATAL:  terminating connection because protocol synchronization was lost

> This is probably an uncommon use case, but it has a few legitimate
> uses in scripts, such as:
> 
> gzip -dc data.csv.gz | psql -c 'TRUNCATE t; COPY t FROM STDIN WITH (FORMAT CSV)'

I think that's a pretty common case. This "create and copy" is another example.

Christoph






^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-12 17:58  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Zsolt Parragi <zsolt.parragi@percona.com>
  1 sibling, 1 reply; 7+ messages in thread

From: Tom Lane @ 2026-08-12 17:58 UTC (permalink / raw)
  To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: pgsql-bugs@lists.postgresql.org

Zsolt Parragi <zsolt.parragi@percona.com> writes:
> The recent COPY ... FROM STDIN improvement caused a regression in COPY
> TO ... FROM STDIN when used together with psql -c: it only considers
> the first statement, so the copy fails if multiple commands are
> specified. A very simple example is:

Yeah, this is clearly an oversight.

> I attached a proposed patch with a tap test case that showcases the issue.

I took a brief look at this.  The question the code immediately raises
is "what to do if we get PSCAN_BACKSLASH?".  For example, someone
might try
	psql postgres -c 'select 1; \echo hello\\ select 2;'
which is syntax that'd work just fine at a command prompt.  As things
stand today, we'll ship the whole string to the server, which will
throw a syntax error and do nothing.  (You could imagine improving the
-c option parser to split the string into pieces and make this work
like it does at a command prompt, but that's surely not something
we'd back-patch.)  Where the rubber meets the road for the current
problem is
	psql postgres -c 'select 1; \echo hello\\ copy tab from stdin;'
Should we act as though we expect PGRES_COPY_IN from this?  How about
	psql postgres -c 'copy tab from stdin; \echo hello'
?

Thinking about it, I think it's probably a non-problem in practice:
all of these forms will result in server errors with no PGRES_COPY_IN
issued, and since these don't attempt to consume data from the rest
of the -c string, there's not really a hazard of failing to skip over
data.  But I think the issue deserves explanation in a comment.

Also, I'd drop the resetPQExpBuffer(query_buf); line.  That's a false
analogy: since we're not sending the string-so-far to the server,
this situation is more like "\;" than like ";", and we'd not clear
query_buf for that.  It probably makes no difference right now, but
perhaps future lexer behavior would notice the difference.

On the test case: I don't love adding a new TAP script for this.
That implies spinning up a new server, making this very expensive
for the amount of actual testing it's doing.  Is there a reason not
to fold this into psql/t/001_basic.pl ?

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-12 19:53  Zsolt Parragi <zsolt.parragi@percona.com>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  0 siblings, 1 reply; 7+ messages in thread

From: Zsolt Parragi @ 2026-08-12 19:53 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org

> I took a brief look at this. The question the code immediately raises
> is "what to do if we get PSCAN_BACKSLASH?" ...

Yeah, I forgot to mention this in the email / commit but I checked
this and decided that it's a non-issue because we don't support it. I
added a comment about it, if support for that gets implemented in the
future, we can also extend this logic.

I dropped the reset buffer call and moved the test to the btasic est -
there's no reason to keep it separate. I just keep forgetting that I
should extend existing tests instead of adding new. Attached v2.

Attachments:

  [application/octet-stream] v2-0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-.patch (4.3K, ../../CAN4CZFOY3Z3zH4r0hfWt6Tvvkc4GGz6VR2b_6uCdLfb3U4AJ9A@mail.gmail.com/2-v2-0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-.patch)
  download | inline diff:
From 2636c7ca9ae3b921b4078e4735597a8d053e1974 Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Tue, 11 Aug 2026 18:16:28 +0000
Subject: [PATCH v2] psql: count every COPY FROM STDIN when scanning a query
 string

When SendQuery() is not told how many COPY FROM STDIN commands the query
string contains (num_copy_from_stdin < 0, as for -c, \gexec and forced
sends), it scanned the string to count them itself.  But it called
psql_scan() only once, which stops at the first semicolon, so any COPY
FROM STDIN past the first sub-command was not counted.  psql then treated
the server's COPY_IN response as unexpected and closed the connection
with "unexpected COPY_IN result, aborting connection", e.g. for

    psql -c "SELECT 1; COPY tab FROM STDIN" < data

which worked before the counting was added.

Loop psql_scan() over the whole string so the count accumulates across
all sub-commands.  Add a TAP test covering a lone COPY, a COPY after
another command, and two COPYs in one string.

Oversight in commit 3045a25ba81.
---
 src/bin/psql/common.c       | 17 ++++++++++++-
 src/bin/psql/t/001_basic.pl | 50 +++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 314bf2388ac..d0dfd206e84 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -1796,13 +1796,28 @@ ExecQueryAndProcessResults(const char *query,
 		PsqlScanState scan_state;
 		PQExpBuffer query_buf;
 		promptStatus_t prompt_tmp;
+		PsqlScanResult scan_result;
 
 		scan_state = psql_scan_create(&psqlscan_callbacks);
 		psql_scan_setup(scan_state, query, strlen(query),
 						pset.encoding, standard_strings());
 		query_buf = createPQExpBuffer();
 
-		(void) psql_scan(scan_state, query_buf, &prompt_tmp);
+		/*
+		 * A semicolon ends only one sub-command; keep scanning so that COPY
+		 * FROM STDIN commands past the first semicolon are counted too.  The
+		 * count accumulates in scan_state across the psql_scan() calls.
+		 *
+		 * The scan stops early if it hits a backslash command, leaving the
+		 * rest of the string uncounted.  That's fine: backslash commands are
+		 * not supported in query strings sent through this path, so the
+		 * server will fail to parse such a string before any COPY data
+		 * transfer can start.
+		 */
+		do
+		{
+			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
+		} while (scan_result == PSCAN_SEMICOLON);
 
 		num_copy_from_stdin = psql_scan_count_copy_from_stdin(scan_state);
 
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl
index 04644f2fdfc..b1b9432cc1d 100644
--- a/src/bin/psql/t/001_basic.pl
+++ b/src/bin/psql/t/001_basic.pl
@@ -533,6 +533,56 @@ psql_fails_like(
 	qr/COPY in a pipeline is not supported, aborting connection/,
 	'\copy to in pipeline: fails');
 
+# Test that psql counts every COPY FROM STDIN in a query string when it has
+# to scan the string itself (as for -c).  A COPY that is not the first
+# sub-command must still be recognized, otherwise psql treats the server's
+# COPY_IN response as unexpected and aborts the connection.
+$node->safe_psql('postgres', 'CREATE TABLE copy_stdin_count (a int)');
+
+my @copy_stdin_cases = (
+	{
+		name => 'single COPY FROM STDIN',
+		sql => 'COPY copy_stdin_count FROM STDIN',
+		data => "10\n20\n\\.\n",
+		rows => 2,
+	},
+	{
+		name => 'COPY FROM STDIN after another command',
+		sql => 'SELECT 1; COPY copy_stdin_count FROM STDIN',
+		data => "30\n40\n\\.\n",
+		rows => 2,
+	},
+	{
+		name => 'two COPY FROM STDIN in one string',
+		sql => 'COPY copy_stdin_count FROM STDIN; COPY copy_stdin_count FROM STDIN',
+		data => "50\n\\.\n60\n\\.\n",
+		rows => 2,
+	});
+
+foreach my $c (@copy_stdin_cases)
+{
+	$node->safe_psql('postgres', 'TRUNCATE copy_stdin_count');
+
+	my ($stdout, $stderr) = ('', '');
+	my $ret = IPC::Run::run(
+		[
+			'psql', '-X', '-v' => 'ON_ERROR_STOP=1',
+			'-d' => $node->connstr('postgres'),
+			'-c' => $c->{sql}
+		],
+		'<' => \$c->{data},
+		'>' => \$stdout,
+		'2>' => \$stderr);
+
+	ok($ret, "$c->{name}: psql exits 0");
+	unlike($stderr, qr/unexpected COPY_IN result/,
+		"$c->{name}: connection not aborted");
+
+	my $count =
+	  $node->safe_psql('postgres', 'SELECT count(*) FROM copy_stdin_count');
+	is($count, $c->{rows}, "$c->{name}: all rows loaded");
+}
+
 psql_fails_like(
 	$node,
 	qq{\\restrict test
-- 
2.54.0



^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-13 20:44  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Zsolt Parragi <zsolt.parragi@percona.com>
  0 siblings, 1 reply; 7+ messages in thread

From: Tom Lane @ 2026-08-13 20:44 UTC (permalink / raw)
  To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: pgsql-bugs@lists.postgresql.org

After thinking some more about how to handle cases where we stop with
PSCAN_BACKSLASH or PSCAN_INCOMPLETE, I feel that the safest answer is
to set num_copy_from_stdin = 0 in those cases.  This is consistent
with the fact that we know we won't get a PGRES_COPY_IN message,
even if there was a valid COPY FROM STDIN in the string before the
syntax error.  This might prevent us from skipping following data
in cases where it'd be best to do that, but here are two arguments
against trying to do so:

* The ambition of the security patch extended only to handling
syntactically-valid cases, which these aren't.  Trying to do more
leads into a guessing game, eg should we skip data after "COPY
mytable FRPM STDIN"?

* Not trying to skip data ensures that the behavior of such cases
is the same as it was before the security patch, which seems like
the right direction to err in.

So v3 attached does it like that.  I also simplified the test
script.  The two-COPY-commands case seems like it covers everything
we want to test; the other cases just add cycles and complicate
the script.

			regards, tom lane

Attachments:

  [text/x-diff] v3-0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-.patch (4.1K, ../../3598003.1786653875@sss.pgh.pa.us/2-v3-0001-psql-count-every-COPY-FROM-STDIN-when-scanning-a-.patch)
  download | inline diff:
From 45fbd29420928f6230762f99e1901b1a45ff1c4b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 13 Aug 2026 16:26:08 -0400
Subject: [PATCH v3] psql: count every COPY FROM STDIN when scanning a query
 string.

When SendQuery() is not told how many COPY FROM STDIN commands the
query string contains (as for -c, \gexec, and \watch), it scans the
string to count them itself.  But it called psql_scan() only once,
which stops at the first semicolon, so any COPY FROM STDIN past the
first sub-command was not counted, causing failure of cases that used
to work.  Oversight in commit 3045a25ba.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAN4CZFPqa6c+u4uX5jJ8LANHTQ4dxM3m4_8G9WmX_A4-2wuv2A@mail.gmail.com
Backpatch-through: 14
---
 src/bin/psql/common.c       | 25 +++++++++++++++++++++++--
 src/bin/psql/t/001_basic.pl | 30 ++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 314bf2388ac..f220344daaf 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -1796,15 +1796,36 @@ ExecQueryAndProcessResults(const char *query,
 		PsqlScanState scan_state;
 		PQExpBuffer query_buf;
 		promptStatus_t prompt_tmp;
+		PsqlScanResult scan_result;
 
 		scan_state = psql_scan_create(&psqlscan_callbacks);
 		psql_scan_setup(scan_state, query, strlen(query),
 						pset.encoding, standard_strings());
 		query_buf = createPQExpBuffer();
 
-		(void) psql_scan(scan_state, query_buf, &prompt_tmp);
+		/*
+		 * A semicolon ends only one sub-command; keep scanning so that COPY
+		 * FROM STDIN commands past the first semicolon are counted too.  The
+		 * count accumulates in scan_state across the psql_scan() calls.
+		 */
+		do
+		{
+			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
+		} while (scan_result == PSCAN_SEMICOLON);
 
-		num_copy_from_stdin = psql_scan_count_copy_from_stdin(scan_state);
+		/*
+		 * We expect the result now to be PSCAN_EOL.  If it is PSCAN_BACKSLASH
+		 * or PSCAN_INCOMPLETE, the server will get a parse error and refuse
+		 * to execute any part of the command string, so don't expect any
+		 * PGRES_COPY_IN results.  (This will mean that we don't attempt to
+		 * discard any following data, but this seems consistent with the
+		 * general contract of psql_scan_count_copy_from_stdin, which is that
+		 * it only promises to count syntactically-valid COPY commands.)
+		 */
+		if (scan_result == PSCAN_EOL)
+			num_copy_from_stdin = psql_scan_count_copy_from_stdin(scan_state);
+		else
+			num_copy_from_stdin = 0;
 
 		destroyPQExpBuffer(query_buf);
 		psql_scan_destroy(scan_state);
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl
index 04644f2fdfc..028df33ce8a 100644
--- a/src/bin/psql/t/001_basic.pl
+++ b/src/bin/psql/t/001_basic.pl
@@ -533,6 +533,36 @@ psql_fails_like(
 	qr/COPY in a pipeline is not supported, aborting connection/,
 	'\copy to in pipeline: fails');
 
+# Test execution of COPY FROM STDIN in -c.  This case is a bit weird
+# because it will read from psql's stdin not from the command source.
+# To make it even weirder, try two such commands, to stress psql's logic
+# that counts them.  Also test both \. and EOF termination.
+{
+	$node->safe_psql('postgres', 'CREATE TABLE copy_stdin_count (a int)');
+	my ($stdin, $stdout, $stderr) = ("50\n\\.\n60\n", '', '');
+	my $ret = IPC::Run::run(
+		[
+			'psql', '--no-psqlrc',
+			'--set' => 'ON_ERROR_STOP=1',
+			'--dbname' => $node->connstr('postgres'),
+			'--command' =>
+			  'COPY copy_stdin_count FROM STDIN; COPY copy_stdin_count FROM STDIN',
+		],
+		'<' => \$stdin,
+		'>' => \$stdout,
+		'2>' => \$stderr);
+
+	ok($ret, '-c COPY FROM STDIN: psql exits 0');
+	unlike(
+		$stderr,
+		qr/unexpected COPY_IN result/,
+		'-c COPY FROM STDIN: unexpected COPY_IN result');
+
+	my $data = $node->safe_psql('postgres', 'SELECT * FROM copy_stdin_count');
+	is($data, "50\n60", '-c COPY FROM STDIN: correct data loaded');
+}
+
+# Test \restrict and \unrestrict.
 psql_fails_like(
 	$node,
 	qq{\\restrict test
-- 
2.52.0

^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-13 22:52  Zsolt Parragi <zsolt.parragi@percona.com>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  0 siblings, 1 reply; 7+ messages in thread

From: Zsolt Parragi @ 2026-08-13 22:52 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org

The changes look good to me.

> The two-COPY-commands case seems like it covers everything
> we want to test

It does, it's just not as realistic use case as the other two, but
that's fine for a test.






^ permalink  raw  reply  [nested|flat] 7+ messages in thread

* Re: COPY TO regression with psql -c
@ 2026-08-14 16:15  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Zsolt Parragi <zsolt.parragi@percona.com>
  0 siblings, 0 replies; 7+ messages in thread

From: Tom Lane @ 2026-08-14 16:15 UTC (permalink / raw)
  To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: pgsql-bugs@lists.postgresql.org

Zsolt Parragi <zsolt.parragi@percona.com> writes:
> The changes look good to me.

Thanks, pushed.

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 7+ messages in thread


end of thread, other threads:[~2026-08-14 16:15 UTC | newest]

Thread overview: 7+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-08-11 19:32 COPY TO regression with psql -c Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-12 08:37 ` Christoph Berg <myon@debian.org>
2026-08-12 17:58 ` Tom Lane <tgl@sss.pgh.pa.us>
2026-08-12 19:53   ` Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-13 20:44     ` Tom Lane <tgl@sss.pgh.pa.us>
2026-08-13 22:52       ` Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-14 16:15         ` Tom Lane <tgl@sss.pgh.pa.us>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox