From ed6f7a0586f79179d12365c258531c726b2cf556 Mon Sep 17 00:00:00 2001
From: Fujii Masao <fujii@postgresql.org>
Date: Sat, 2 Aug 2025 16:15:37 +0900
Subject: [PATCH v1] pg_dump: Fix incorrect parsing of object types in pg_dump
 --filter.

Previously, pg_dump --filter could misinterpret invalid object types
in the filter file as valid ones. For example, the invalid object type
"table-data" (likely a typo for the valid "table_data") could be
mistakenly recognized as "table", causing pg_dump to succeed
when it should have failed.

This happened because pg_dump identified tokens as sequences of
ASCII alphabetic characters, treating non-alphabetic characters
(like hyphens) as token boundaries. As a result, "table-data" was
parsed as "table".

To fix this, pg_dump --filter now treats tokens as strings of
non-space characters separated by spaces or line endings,
ensuring invalid types like "table-data" are correctly rejected.

Back-patch to v17, where the --filter option was introduced.
---
 src/bin/pg_dump/filter.c                    | 26 ++++++++++++---------
 src/bin/pg_dump/t/005_pg_dump_filterfile.pl | 14 +++++++----
 2 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/src/bin/pg_dump/filter.c b/src/bin/pg_dump/filter.c
index 7214d514137..71b4bd9a73a 100644
--- a/src/bin/pg_dump/filter.c
+++ b/src/bin/pg_dump/filter.c
@@ -169,31 +169,35 @@ pg_log_filter_error(FilterStateData *fstate, const char *fmt,...)
 }
 
 /*
- * filter_get_keyword - read the next filter keyword from buffer
+ * filter_get_token - read the next filter token from buffer
  *
- * Search for keywords (limited to ascii alphabetic characters) in
- * the passed in line buffer. Returns NULL when the buffer is empty or the first
- * char is not alpha. The char '_' is allowed, except as the first character.
+ * Search for tokens (strings of non-space characters bounded by
+ * space characters or end of line) in the passed in line buffer.
+ * Returns NULL when the buffer is empty or no token exists.
  * The length of the found keyword is returned in the size parameter.
  */
 static const char *
-filter_get_keyword(const char **line, int *size)
+filter_get_token(const char **line, int *size)
 {
 	const char *ptr = *line;
 	const char *result = NULL;
 
-	/* Set returned length preemptively in case no keyword is found */
+	/* Set returned length preemptively in case no token is found */
 	*size = 0;
 
-	/* Skip initial whitespace */
+	/* Skip initial space characters */
 	while (isspace((unsigned char) *ptr))
 		ptr++;
 
-	if (isalpha((unsigned char) *ptr))
+	/*
+	 * Grab one token that's the string of non-space characters bounded by
+	 * space characters or end of line.
+	 */
+	if (*ptr != '\0' && !isspace((unsigned char) *ptr))
 	{
 		result = ptr++;
 
-		while (isalpha((unsigned char) *ptr) || *ptr == '_')
+		while (*ptr != '\0' && !isspace((unsigned char) *ptr))
 			ptr++;
 
 		*size = ptr - result;
@@ -414,7 +418,7 @@ filter_read_item(FilterStateData *fstate,
 			 * First we expect sequence of two keywords, {include|exclude}
 			 * followed by the object type to operate on.
 			 */
-			keyword = filter_get_keyword(&str, &size);
+			keyword = filter_get_token(&str, &size);
 			if (!keyword)
 			{
 				pg_log_filter_error(fstate,
@@ -433,7 +437,7 @@ filter_read_item(FilterStateData *fstate,
 				fstate->exit_nicely(1);
 			}
 
-			keyword = filter_get_keyword(&str, &size);
+			keyword = filter_get_token(&str, &size);
 			if (!keyword)
 			{
 				pg_log_filter_error(fstate, _("missing filter object type"));
diff --git a/src/bin/pg_dump/t/005_pg_dump_filterfile.pl b/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
index f05e8a20e05..d788406add4 100644
--- a/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
+++ b/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
@@ -418,10 +418,16 @@ command_fails_like(
 	qr/invalid filter command/,
 	"invalid syntax: incorrect filter command");
 
-# Test invalid object type
+# Test invalid object type.
+#
+# This test also verifies that tokens are correctly recognized as sequences of
+# non-space characters separated by spaces or line endings. If the parser
+# incorrectly treats non-space delimiters (like hyphens) as token boundaries,
+# "table-data" might be misread as the valid object type "table". To catch such
+# issues, "table-data" is used here as an intentionally invalid object type.
 open $inputfile, '>', "$tempdir/inputfile.txt"
   or die "unable to open filterfile for writing";
-print $inputfile "include xxx";
+print $inputfile "exclude table-data one";
 close $inputfile;
 
 command_fails_like(
@@ -432,8 +438,8 @@ command_fails_like(
 		'--filter' => "$tempdir/inputfile.txt",
 		'postgres'
 	],
-	qr/unsupported filter object type: "xxx"/,
-	"invalid syntax: invalid object type specified, should be table, schema, foreign_data or data"
+	qr/unsupported filter object type: "table-data"/,
+	"invalid syntax: invalid object type specified"
 );
 
 # Test missing object identifier pattern
-- 
2.50.1

