v20-0001-pg_dumpall-deal-witth-newline-or-carriage-ret.no-cfbot

application/octet-stream

Filename: v20-0001-pg_dumpall-deal-witth-newline-or-carriage-ret.no-cfbot
Type: application/octet-stream
Part: 0
Message: Re: Non-text mode for pg_dumpall
From bf0db3afb9cb7d34033fe500315be8033efff49e Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Mon, 10 Mar 2025 15:27:32 +0800
Subject: [PATCH v20 1/1] pg_dumpall deal witth newline or carriage return

pg_dumpall: fail earlier if any database name contain new line.
we may also need deal with role name have newline or carriage return.

also see comments in appendShellString.
---
 src/bin/pg_dump/common_dumpall_restore.c | 18 ++++++++++++++++++
 src/bin/pg_dump/common_dumpall_restore.h |  2 ++
 src/bin/pg_dump/pg_dumpall.c             | 13 +++++++++++++
 3 files changed, 33 insertions(+)

diff --git a/src/bin/pg_dump/common_dumpall_restore.c b/src/bin/pg_dump/common_dumpall_restore.c
index 92f52b7239a..4e81142373f 100644
--- a/src/bin/pg_dump/common_dumpall_restore.c
+++ b/src/bin/pg_dump/common_dumpall_restore.c
@@ -287,3 +287,21 @@ executeQuery(PGconn *conn, const char *query)
 
 	return res;
 }
+
+/*
+ * append str to buf, exit if string contain newline or carriage return
+*/
+void
+string_contain_lfcr(PQExpBuffer buf, const char *str, const char *kind)
+{
+	Assert(kind != NULL);
+	if (!appendShellStringNoError(buf, str))
+	{
+
+		pg_log_error("%s contains a newline or carriage return: \"%s\"", kind, str);
+		pg_log_error_hint("If you want to dump data on \"%s\", "
+						  "you may need rename it to make sure it does contain newline or carriage return",
+						  str);
+		exit_nicely(1);
+	}
+}
diff --git a/src/bin/pg_dump/common_dumpall_restore.h b/src/bin/pg_dump/common_dumpall_restore.h
index 7fe1c00ab71..c458abd0eef 100644
--- a/src/bin/pg_dump/common_dumpall_restore.h
+++ b/src/bin/pg_dump/common_dumpall_restore.h
@@ -15,10 +15,12 @@
 #define COMMON_DUMPALL_RESTORE_H
 
 #include "pg_backup.h"
+#include "pqexpbuffer.h"
 
 extern PGconn *connectDatabase(const char *dbname, const char *connection_string, const char *pghost,
 							   const char *pgport, const char *pguser,
 							   trivalue prompt_password, bool fail_on_error,
 							   const char *progname, const char **connstr, int *server_version);
 extern  PGresult *executeQuery(PGconn *conn, const char *query);
+extern  void string_contain_lfcr(PQExpBuffer buf, const char *str, const char *kind);
 #endif                          /* COMMON_DUMPALL_RESTORE_H */
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 0752c44896f..f6614ce3bc2 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1601,6 +1601,7 @@ dumpDatabases(PGconn *conn, ArchiveFormat archDumpFormat)
 	char		db_subdir[MAXPGPATH];
 	char		dbfilepath[MAXPGPATH];
 	FILE       *map_file = NULL;
+	PQExpBufferData test_dbname;
 
 	/*
 	 * Skip databases marked not datallowconn, since we'd be unable to connect
@@ -1622,6 +1623,18 @@ dumpDatabases(PGconn *conn, ArchiveFormat archDumpFormat)
 	if (PQntuples(res) > 0)
 		fprintf(OPF, "--\n-- Databases\n--\n\n");
 
+	/*
+	 * exit earlier if database name contain newline or carriage return.
+	 * also see appendShellString comments.
+	*/
+	initPQExpBuffer(&test_dbname);
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		char	   *dbname = PQgetvalue(res, i, 0);
+		string_contain_lfcr(&test_dbname, dbname, "database name");
+	}
+	termPQExpBuffer(&test_dbname);
+
 	/*
 	 * If directory/tar/custom format is specified then create a subdirectory
 	 * under the main directory and each database dump file subdirectory will
-- 
2.34.1