From e7a18c780591673592b2a5eb1e129fcceb17f0fe Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Sun, 21 Apr 2024 14:19:32 +0200
Subject: [PATCH 1/2] createdb: compare strategy case-insensitive

When specifying the createdb strategy, the documentation suggests valid
options are FILE_COPY and WAL_LOG, but the code does case-sensitive
comparison and accepts only "file_copy" and "wal_log" as valid.

Fixed by doing a case-insensitive comparison using pg_strcasecmp(), same
as for other string parameters.

While at it, apply fmtId() to a nearby "locale_provider". This already
did the comparison in case-insensitive way, but the value would not be
double-quoted, confusing the parser and the error message.

Backpatch to 15, where the strategy was introduced.

Backpatch-through: 15
---
 src/backend/commands/dbcommands.c |  6 +++---
 src/bin/scripts/createdb.c        |  2 +-
 src/bin/scripts/t/020_createdb.pl | 10 ++++++++++
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 8229dfa1f22..cd06d1270c5 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1018,15 +1018,15 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 		char	   *strategy;
 
 		strategy = defGetString(dstrategy);
-		if (strcmp(strategy, "wal_log") == 0)
+		if (pg_strcasecmp(strategy, "wal_log") == 0)
 			dbstrategy = CREATEDB_WAL_LOG;
-		else if (strcmp(strategy, "file_copy") == 0)
+		else if (pg_strcasecmp(strategy, "file_copy") == 0)
 			dbstrategy = CREATEDB_FILE_COPY;
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("invalid create database strategy \"%s\"", strategy),
-					 errhint("Valid strategies are \"wal_log\", and \"file_copy\".")));
+					 errhint("Valid strategies are \"wal_log\" and \"file_copy\".")));
 	}
 
 	/* If encoding or locales are defaulted, use source's setting */
diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c
index 007061e756f..30426860efa 100644
--- a/src/bin/scripts/createdb.c
+++ b/src/bin/scripts/createdb.c
@@ -237,7 +237,7 @@ main(int argc, char *argv[])
 		appendStringLiteralConn(&sql, lc_ctype, conn);
 	}
 	if (locale_provider)
-		appendPQExpBuffer(&sql, " LOCALE_PROVIDER %s", locale_provider);
+		appendPQExpBuffer(&sql, " LOCALE_PROVIDER %s", fmtId(locale_provider));
 	if (icu_locale)
 	{
 		appendPQExpBufferStr(&sql, " ICU_LOCALE ");
diff --git a/src/bin/scripts/t/020_createdb.pl b/src/bin/scripts/t/020_createdb.pl
index 512b55c48a9..4a0e2c883a1 100644
--- a/src/bin/scripts/t/020_createdb.pl
+++ b/src/bin/scripts/t/020_createdb.pl
@@ -255,11 +255,21 @@ $node->issues_sql_like(
 	qr/statement: CREATE DATABASE foobar6 STRATEGY wal_log TEMPLATE foobar2/,
 	'create database with WAL_LOG strategy');
 
+$node->issues_sql_like(
+	[ 'createdb', '-T', 'foobar2', '-S', 'WAL_LOG', 'foobar6s' ],
+	qr/statement: CREATE DATABASE foobar6s STRATEGY "WAL_LOG" TEMPLATE foobar2/,
+	'create database with WAL_LOG strategy');
+
 $node->issues_sql_like(
 	[ 'createdb', '-T', 'foobar2', '-S', 'file_copy', 'foobar7' ],
 	qr/statement: CREATE DATABASE foobar7 STRATEGY file_copy TEMPLATE foobar2/,
 	'create database with FILE_COPY strategy');
 
+$node->issues_sql_like(
+	[ 'createdb', '-T', 'foobar2', '-S', 'FILE_COPY', 'foobar7s' ],
+	qr/statement: CREATE DATABASE foobar7s STRATEGY "FILE_COPY" TEMPLATE foobar2/,
+	'create database with FILE_COPY strategy');
+
 # Create database owned by role_foobar.
 $node->issues_sql_like(
 	[ 'createdb', '-T', 'foobar2', '-O', 'role_foobar', 'foobar8' ],
-- 
2.44.0

