Force LC_COLLATE to C in postmaster.
authorJeff Davis <jdavis@postgresql.org>
Wed, 16 Jul 2025 21:13:18 +0000 (14:13 -0700)
committerJeff Davis <jdavis@postgresql.org>
Wed, 16 Jul 2025 21:13:18 +0000 (14:13 -0700)
Avoid dependence on setlocale().

strcoll(), etc., are not called directly; all collation-sensitive
calls should go through pg_locale.c and use the appropriate
provider. By setting LC_COLLATE to C, we avoid accidentally depending
on libc behavior when using a different provider.

No behavior change in the backend, but it's possible that some
extensions will be affected. Such extensions should be updated to use
the pg_locale_t APIs.

Discussion: https://postgr.es/m/9875f7f9-50f1-4b5d-86fc-ee8b03e8c162@eisentraut.org
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
doc/src/sgml/catalogs.sgml
doc/src/sgml/charset.sgml
doc/src/sgml/ref/create_database.sgml
doc/src/sgml/ref/createdb.sgml
src/backend/main/main.c
src/backend/utils/init/postinit.c

index aa5b8772436c6a2f1891cee413b5e7719df16099..0d23bc1b122b622adc91967fce639375dce3d41a 100644 (file)
@@ -3158,7 +3158,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        <structfield>datcollate</structfield> <type>text</type>
       </para>
       <para>
-       LC_COLLATE for this database
+       LC_COLLATE for this database (ignored unless <structfield>datlocprovider</structfield> is <literal>c</literal>)
       </para></entry>
      </row>
 
index 5a0e97f6f31580896bf254b813a35efed066f097..59b27c3c370e2ad1728771845a0e8636ecf1da6c 100644 (file)
@@ -100,7 +100,7 @@ initdb --locale=sv_SE
       <tbody>
        <row>
         <entry><envar>LC_COLLATE</envar></entry>
-        <entry>String sort order</entry>
+        <entry>String sort order (ignored unless the provider is <literal>libc</literal>)</entry>
        </row>
        <row>
         <entry><envar>LC_CTYPE</envar></entry>
index 4da8aeebb50a29e89bd9f68a8deac4b1a3ec7b18..3544b15efdafa5c9bfcff4c4334e906a2625185e 100644 (file)
@@ -150,12 +150,12 @@ CREATE DATABASE <replaceable class="parameter">name</replaceable>
        <para>
         Sets the default collation order and character classification in the
         new database.  Collation affects the sort order applied to strings,
-        e.g., in queries with <literal>ORDER BY</literal>, as well as the order used in indexes
-        on text columns.  Character classification affects the categorization
-        of characters, e.g., lower, upper, and digit.  Also sets the
-        associated aspects of the operating system environment,
-        <literal>LC_COLLATE</literal> and <literal>LC_CTYPE</literal>.  The
-        default is the same setting as the template database.  See <xref
+        e.g., in queries with <literal>ORDER BY</literal>, as well as the
+        order used in indexes on text columns.  Character classification
+        affects the categorization of characters, e.g., lower, upper, and
+        digit.  Also sets the <literal>LC_CTYPE</literal> aspect of the
+        operating system environment.  The default is the same setting as the
+        template database.  See <xref
         linkend="collation-managing-create-libc"/> and <xref
         linkend="collation-managing-create-icu"/> for details.
        </para>
@@ -189,17 +189,16 @@ CREATE DATABASE <replaceable class="parameter">name</replaceable>
       <term><replaceable class="parameter">lc_collate</replaceable></term>
       <listitem>
        <para>
-        Sets <literal>LC_COLLATE</literal> in the database server's operating
-        system environment.  The default is the setting of <xref
-        linkend="create-database-locale"/> if specified, otherwise the same
-        setting as the template database.  See below for additional
-        restrictions.
+        If <xref linkend="create-database-locale-provider"/> is
+        <literal>libc</literal>, sets the default collation order to use in
+        the new database, overriding the setting <xref
+        linkend="create-database-locale"/>. Otherwise, this setting is
+        ignored.
        </para>
        <para>
-        If <xref linkend="create-database-locale-provider"/> is
-        <literal>libc</literal>, also sets the default collation order to use
-        in the new database, overriding the setting <xref
-        linkend="create-database-locale"/>.
+        The default is the setting of <xref linkend="create-database-locale"/>
+        if specified, otherwise the same setting as the template database.
+        See below for additional restrictions.
        </para>
       </listitem>
      </varlistentry>
@@ -208,16 +207,18 @@ CREATE DATABASE <replaceable class="parameter">name</replaceable>
       <listitem>
        <para>
         Sets <literal>LC_CTYPE</literal> in the database server's operating
-        system environment.  The default is the setting of <xref
-        linkend="create-database-locale"/> if specified, otherwise the same
-        setting as the template database.  See below for additional
-        restrictions.
+        system environment.
        </para>
        <para>
         If <xref linkend="create-database-locale-provider"/> is
-        <literal>libc</literal>, also sets the default character
-        classification to use in the new database, overriding the setting
-        <xref linkend="create-database-locale"/>.
+        <literal>libc</literal>, sets the default character classification to
+        use in the new database, overriding the setting <xref
+        linkend="create-database-locale"/>.
+       </para>
+       <para>
+        The default is the setting of <xref linkend="create-database-locale"/>
+        if specified, otherwise the same setting as the template database.
+        See below for additional restrictions.
        </para>
       </listitem>
      </varlistentry>
index 5c4e0465ed9dad35ce097f868e9f8e3c228e5a81..2ccbe13f3900840c2ff9dc2d36c6ec4b817184a1 100644 (file)
@@ -136,7 +136,8 @@ PostgreSQL documentation
       <term><option>--lc-collate=<replaceable class="parameter">locale</replaceable></option></term>
       <listitem>
        <para>
-        Specifies the LC_COLLATE setting to be used in this database.
+        Specifies the LC_COLLATE setting to be used in this database (ignored
+        unless the locale provider is <literal>libc</literal>).
        </para>
       </listitem>
      </varlistentry>
index 7d63cf94a6b44a3e030dfed61642a1d041d4fe52..bdcb5e4f2615984d4a99ba585b0aa10157a164f2 100644 (file)
@@ -125,13 +125,17 @@ main(int argc, char *argv[])
    set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("postgres"));
 
    /*
-    * In the postmaster, absorb the environment values for LC_COLLATE and
-    * LC_CTYPE.  Individual backends will change these later to settings
-    * taken from pg_database, but the postmaster cannot do that.  If we leave
-    * these set to "C" then message localization might not work well in the
-    * postmaster.
+    * Collation is handled by pg_locale.c, and the behavior is dependent on
+    * the provider. strcoll(), etc., should not be called directly.
+    */
+   init_locale("LC_COLLATE", LC_COLLATE, "C");
+
+   /*
+    * In the postmaster, absorb the environment value for LC_CTYPE.
+    * Individual backends will change it later to pg_database.datctype, but
+    * the postmaster cannot do that.  If we leave it set to "C" then message
+    * localization might not work well in the postmaster.
     */
-   init_locale("LC_COLLATE", LC_COLLATE, "");
    init_locale("LC_CTYPE", LC_CTYPE, "");
 
    /*
index c86ceefda940b8f2fb500786253f9f23ffea3f8d..641e535a73c7c0bf2b00f04e1688b4ff8052719f 100644 (file)
@@ -417,12 +417,11 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
    datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datctype);
    ctype = TextDatumGetCString(datum);
 
-   if (pg_perm_setlocale(LC_COLLATE, collate) == NULL)
-       ereport(FATAL,
-               (errmsg("database locale is incompatible with operating system"),
-                errdetail("The database was initialized with LC_COLLATE \"%s\", "
-                          " which is not recognized by setlocale().", collate),
-                errhint("Recreate the database with another locale or install the missing locale.")));
+   /*
+    * Historcally, we set LC_COLLATE from datcollate, as well. That's no
+    * longer necessary because all collation behavior is handled through
+    * pg_locale_t.
+    */
 
    if (pg_perm_setlocale(LC_CTYPE, ctype) == NULL)
        ereport(FATAL,