v7-0004-Avoid-global-LC_CTYPE-dependency-in-scansup.c.patch
text/x-patch
Filename: v7-0004-Avoid-global-LC_CTYPE-dependency-in-scansup.c.patch
Type: text/x-patch
Part: 3
From ddc5eb689d4d5801778e1f8f5b5a1056a44a001b Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Sun, 26 Oct 2025 15:04:58 -0700
Subject: [PATCH v7 4/9] Avoid global LC_CTYPE dependency in scansup.c.
Call char_tolower() instead of tolower() in downcase_identifier().
The function downcase_identifier() may be called before locale support
is initialized -- e.g. during GUC processing in the postmaster -- so
if the locale is unavailable, char_tolower() uses plain ASCII
semantics.
That can result in a difference in behavior during that early stage of
processing, but previously it would have depended on the postmaster
environment variable LC_CTYPE, which would have been fragile anyway.
---
src/backend/parser/scansup.c | 5 +++--
src/backend/utils/adt/pg_locale.c | 16 ++++++++++++++--
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c
index 2feb2b6cf5a..872075ba220 100644
--- a/src/backend/parser/scansup.c
+++ b/src/backend/parser/scansup.c
@@ -18,6 +18,7 @@
#include "mb/pg_wchar.h"
#include "parser/scansup.h"
+#include "utils/pg_locale.h"
/*
@@ -67,8 +68,8 @@ downcase_identifier(const char *ident, int len, bool warn, bool truncate)
if (ch >= 'A' && ch <= 'Z')
ch += 'a' - 'A';
- else if (enc_is_single_byte && IS_HIGHBIT_SET(ch) && isupper(ch))
- ch = tolower(ch);
+ else if (enc_is_single_byte && IS_HIGHBIT_SET(ch))
+ ch = char_tolower(ch, NULL);
result[i] = (char) ch;
}
result[i] = '\0';
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 9631d274611..7e13c601643 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -1568,11 +1568,17 @@ char_is_cased(char ch, pg_locale_t locale)
*
* Convert single-byte char to lowercase. Not correct for multibyte encodings,
* but needed for historical compatibility purposes.
+ *
+ * If locale is NULL, use the default database locale. This function may be
+ * called before the database locale is initialized, in which case it uses
+ * plain ASCII semantics.
*/
char
char_tolower(unsigned char ch, pg_locale_t locale)
{
- if (locale->ctype == NULL)
+ if (locale == NULL)
+ locale = default_locale;
+ if (locale == NULL || locale->ctype == NULL)
{
if (ch >= 'A' && ch <= 'Z')
return ch + ('a' - 'A');
@@ -1586,11 +1592,17 @@ char_tolower(unsigned char ch, pg_locale_t locale)
*
* Convert single-byte char to uppercase. Not correct for multibyte encodings,
* but needed for historical compatibility purposes.
+ *
+ * If locale is NULL, use the default database locale. This function may be
+ * called before the database locale is initialized, in which case it uses
+ * plain ASCII semantics.
*/
char
char_toupper(unsigned char ch, pg_locale_t locale)
{
- if (locale->ctype == NULL)
+ if (locale == NULL)
+ locale = default_locale;
+ if (locale == NULL || locale->ctype == NULL)
{
if (ch >= 'a' && ch <= 'z')
return ch - ('a' - 'A');
--
2.43.0