From a437302c67a912f5f732986182989a22983c8aa6 Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <andreas@proxel.se>
Date: Fri, 29 Nov 2024 05:49:03 +0100
Subject: [PATCH v10 03/11] Move ICU database encoding check into validation
 function

This removes some duplicated code while also makes the code for
validating an ICU collation more similar to the code for built-in
collation.
---
 src/backend/commands/collationcmds.c | 16 ++--------------
 src/backend/commands/dbcommands.c    |  8 +-------
 src/backend/utils/adt/pg_locale.c    | 13 ++++++++++++-
 src/include/utils/pg_locale.h        |  2 +-
 4 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 53b6a479aa4..8001f5ed082 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -297,7 +297,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
 				}
 			}
 
-			icu_validate_locale(colllocale);
+			icu_validate_locale(GetDatabaseEncoding(), colllocale);
 		}
 
 		/*
@@ -322,23 +322,11 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
 		}
 		else if (collprovider == COLLPROVIDER_ICU)
 		{
-#ifdef USE_ICU
 			/*
 			 * We could create ICU collations with collencoding == database
 			 * encoding, but it seems better to use -1 so that it matches the
-			 * way initdb would create ICU collations.  However, only allow
-			 * one to be created when the current database's encoding is
-			 * supported.  Otherwise the collation is useless, plus we get
-			 * surprising behaviors like not being able to drop the collation.
-			 *
-			 * Skip this test when !USE_ICU, because the error we want to
-			 * throw for that isn't thrown till later.
+			 * way initdb would create ICU collations.
 			 */
-			if (!is_encoding_supported_by_icu(GetDatabaseEncoding()))
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("current database's encoding is not supported with this provider")));
-#endif
 			collencoding = -1;
 		}
 		else
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index aa91a396967..fd5e887c3ae 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1116,12 +1116,6 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 	}
 	else if (dblocprovider == COLLPROVIDER_ICU)
 	{
-		if (!(is_encoding_supported_by_icu(encoding)))
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("encoding \"%s\" is not supported with ICU provider",
-							pg_encoding_to_char(encoding))));
-
 		/*
 		 * This would happen if template0 uses the libc provider but the new
 		 * database uses icu.
@@ -1151,7 +1145,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 			}
 		}
 
-		icu_validate_locale(dblocale);
+		icu_validate_locale(encoding, dblocale);
 	}
 
 	/* for libc, locale comes from datcollate and datctype */
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index b2f198314a2..ce255a4b91f 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -1719,7 +1719,7 @@ icu_language_tag(const char *loc_str, int elevel)
  * Perform best-effort check that the locale is a valid one.
  */
 void
-icu_validate_locale(const char *loc_str)
+icu_validate_locale(int encoding, const char *loc_str)
 {
 #ifdef USE_ICU
 	UCollator  *collator;
@@ -1728,6 +1728,17 @@ icu_validate_locale(const char *loc_str)
 	bool		found = false;
 	int			elevel = icu_validation_level;
 
+	/*
+	 * Only allow locales to be created when the encoding is supported.
+	 * Otherwise the collation is useless, plus we get surprising behaviors
+	 * like not being able to drop the collation.
+	 */
+	if (!(is_encoding_supported_by_icu(encoding)))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("encoding \"%s\" is not supported with ICU provider",
+						pg_encoding_to_char(encoding))));
+
 	/* no validation */
 	if (elevel < 0)
 		return;
diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h
index 776f8f6f2fe..be9bb62c4b2 100644
--- a/src/include/utils/pg_locale.h
+++ b/src/include/utils/pg_locale.h
@@ -109,7 +109,7 @@ extern size_t pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src,
 
 extern int	builtin_locale_encoding(const char *locale);
 extern const char *builtin_validate_locale(int encoding, const char *locale);
-extern void icu_validate_locale(const char *loc_str);
+extern void icu_validate_locale(int encoding, const char *loc_str);
 extern char *icu_language_tag(const char *loc_str, int elevel);
 
 #ifdef USE_ICU
-- 
2.34.1

