From 14db9fc7157b0b7d935dfd025a37d9a0839aa9c7 Mon Sep 17 00:00:00 2001
From: Mahendra Singh Thalor <mahi6run@gmail.com>
Date: Thu, 10 Apr 2025 23:47:45 +0530
Subject: [PATCH] pg_upgrade : add alert for invalid database names

When any database has \n or \r in database name, then dump will report
shell command error. so better, we will give alert to user to fix it.
---
 src/bin/pg_upgrade/check.c | 67 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 18c2d652bb6..be5db5ddae5 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -31,6 +31,7 @@ static void check_new_cluster_logical_replication_slots(void);
 static void check_new_cluster_subscription_configuration(void);
 static void check_old_cluster_for_valid_slots(void);
 static void check_old_cluster_subscription_state(void);
+static void check_database_names_in_old_cluser(ClusterInfo *cluster);
 
 /*
  * DataTypesUsageChecks - definitions of data type checks for the old cluster
@@ -598,6 +599,9 @@ check_and_dump_old_cluster(void)
 	 */
 	check_for_connection_status(&old_cluster);
 
+	/* Validate database names from old cluser. */
+	check_database_names_in_old_cluser(&old_cluster);
+
 	/*
 	 * Extract a list of databases, tables, and logical replication slots from
 	 * the old cluster.
@@ -2269,3 +2273,66 @@ check_old_cluster_subscription_state(void)
 	else
 		check_ok();
 }
+
+/*
+ * check_database_names_in_old_cluser()
+ *
+ * If any database name has newline or carriage return character in name,
+ * then this will report those as these special characters are not allowed
+ * for database names in dump. See appendShellStringNoError
+ */
+static void
+check_database_names_in_old_cluser(ClusterInfo *cluster)
+{
+	int			i;
+	PGconn		*conn_template1;
+	PGresult	*res;
+	int			ntups;
+	FILE		*script = NULL;
+	char		output_path[MAXPGPATH];
+	int			count = 0;
+
+	prep_status("Checking database names");
+
+	snprintf(output_path, sizeof(output_path), "%s/%s",
+			log_opts.basedir,
+			"invalid_db_names.txt");
+
+	conn_template1 = connectToServer(cluster, "template1");
+
+	/* Get database names from cluster. */
+	res = executeQueryOrDie(conn_template1,
+			"SELECT datname "
+			"FROM pg_catalog.pg_database");
+
+	ntups = PQntuples(res);
+	for (i = 0; i < ntups; i++)
+	{
+		char	*dbname = PQgetvalue(res, i, 0);
+
+		/* If name has \n or \r, then report it. */
+		if (strpbrk(dbname, "\n\r"))
+		{
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %m", output_path);
+
+			fprintf(script, "%d : database name = \"%s\"\n", ++count, dbname);
+		}
+	}
+
+	PQclear(res);
+	PQfinish(conn_template1);
+
+	if (script)
+	{
+		fclose(script);
+		pg_log(PG_REPORT, "fatal");
+		pg_fatal("All the database names should have only valid characters. A newline or a carriage\n"
+				"return character is not allowed in these database names.  To fix this, please rename\n"
+				"these names with valid names. \n"
+				"To see all %d invalid database names, refer invalid_db_names.txt file. \n"
+				"    %s", count, output_path);
+	}
+	else
+		check_ok();
+}
-- 
2.39.3

