This is an automated email from the ASF dual-hosted git repository.

tuhaihe pushed a commit to branch add-behave-test-ci
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 93d141d18382c59682c52945244a85ae21a8f499
Author: Dianjin Wang <[email protected]>
AuthorDate: Fri Sep 11 12:56:47 2026 +0800

    gpinitsystem: import system collations after the cluster is up
    
    A freshly initialised cluster had no system collations at all, and the
    two halves of that are in different layers.
    
    initdb deliberately skips pg_import_system_collations(): the call has to
    be dispatched to the segments, so it cannot run before the cluster
    exists. Greenplum makes up for that in gpinitsystem; Cloudberry had
    dropped the function. Add IMPORT_COLLATION, called once the coordinator
    is up in production mode, importing into template0, template1 and
    postgres, each followed by ANALYZE and VACUUM FREEZE so the built-in
    databases end up as initdb would have left them.
    
    That alone is not enough, because pg_import_system_collations() itself
    only half worked. Every collation has to exist on the segments with the
    same OID; the alias and ICU paths dispatch CREATE COLLATION to arrange
    that, but the path for the locale names themselves did not -- the
    PostgreSQL 16 merge moved that code into create_collation_from_locale()
    and dropped the DispatchCollationCreate() call. The result is a
    pg_collation populated on the coordinator only, which gpcheckcat duly
    reports as inconsistent_pg_collation. Nothing noticed until now because
    nothing ever called the function.
    
    Skip locales whose encoding differs from the database encoding before
    creating anything, rather than after: such a collation is unusable in
    this database and a segment rejects CREATE COLLATION for it with
    "encoding UTF8 does not match locale en_AU", so creating it on the
    coordinator alone would reintroduce the very inconsistency being fixed.
---
 gpMgmt/bin/gpinitsystem              | 39 ++++++++++++++++++++++++++++++++++++
 src/backend/commands/collationcmds.c | 20 ++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/gpMgmt/bin/gpinitsystem b/gpMgmt/bin/gpinitsystem
index fa85d42ae3f..a4569e913cc 100755
--- a/gpMgmt/bin/gpinitsystem
+++ b/gpMgmt/bin/gpinitsystem
@@ -1621,6 +1621,44 @@ CREATE_GPEXTENSIONS() {
                done
 }
 
+# Import system collations through pg_import_system_collations, and leave the
+# built-in databases in the state initdb would have left them (borrowed from
+# initdb.c:setup_collation() and initdb.c:vacuum_db()).
+#
+# initdb cannot do this itself: pg_import_system_collations() has to be
+# dispatched to the segments, so it can only run once the cluster is up.
+IMPORT_COLLATION () {
+               LOG_MSG "[INFO]:-Start Function $FUNCNAME"
+               LOG_MSG "[INFO]:-Importing system collations" 1
+
+               # temporarily allow connections to template0, so we can import 
collations to it.
+               $PSQL -p $GP_PORT -d postgres -A -t -c "ALTER DATABASE 
template0 ALLOW_CONNECTIONS on" >> $LOG_FILE 2>&1;
+               $PSQL -p $GP_PORT -d template0 -A -t -c "SELECT 
pg_import_system_collations('pg_catalog')" >> $LOG_FILE 2>&1;
+               ERROR_CHK $? "importing system collations to 'template0' 
database" 1
+               $PSQL -p $GP_PORT -d template0 -A -t -c "ANALYZE" >> $LOG_FILE 
2>&1;
+               ERROR_CHK $? "ANALYZE 'template0' database" 1
+               $PSQL -p $GP_PORT -d template0 -A -t -c "VACUUM FREEZE" >> 
$LOG_FILE 2>&1;
+               ERROR_CHK $? "VACUUM FREEZE 'template0' database" 1
+               $PSQL -p $GP_PORT -d postgres -A -t -c "ALTER DATABASE 
template0 ALLOW_CONNECTIONS off" >> $LOG_FILE 2>&1;
+
+               # import to template1
+               $PSQL -p $GP_PORT -d template1 -A -t -c "SELECT 
pg_import_system_collations('pg_catalog')" >> $LOG_FILE 2>&1;
+               ERROR_CHK $? "importing system collations to 'template1' 
database" 1
+               $PSQL -p $GP_PORT -d template1 -A -t -c "ANALYZE" >> $LOG_FILE 
2>&1;
+               ERROR_CHK $? "ANALYZE 'template1' database" 1
+               $PSQL -p $GP_PORT -d template1 -A -t -c "VACUUM FREEZE" >> 
$LOG_FILE 2>&1;
+               ERROR_CHK $? "VACUUM FREEZE 'template1' database" 1
+
+               # import to postgres
+               $PSQL -p $GP_PORT -d postgres -A -t -c "SELECT 
pg_import_system_collations('pg_catalog')" >> $LOG_FILE 2>&1;
+               ERROR_CHK $? "importing system collations to 'postgres' 
database" 1
+               $PSQL -p $GP_PORT -d postgres -A -t -c "ANALYZE" >> $LOG_FILE 
2>&1;
+               ERROR_CHK $? "ANALYZE 'postgres' database" 1
+               $PSQL -p $GP_PORT -d postgres -A -t -c "VACUUM FREEZE" >> 
$LOG_FILE 2>&1;
+               ERROR_CHK $? "VACUUM FREEZE 'postgres' database" 1
+               LOG_MSG "[INFO]:-End Function $FUNCNAME"
+}
+
 
 FORCE_FTS_PROBE () {
     LOG_MSG "[INFO]:-Start Function $FUNCNAME"
@@ -2249,6 +2287,7 @@ STOP_QD_PRODUCTION
 START_QD_PRODUCTION
 
 CREATE_GPEXTENSIONS
+IMPORT_COLLATION
 
 if [ x"" != x"$DATABASE_NAME" ]; then
        CREATE_DATABASE
diff --git a/src/backend/commands/collationcmds.c 
b/src/backend/commands/collationcmds.c
index 69fa630ee02..ede18b0442d 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -755,6 +755,17 @@ create_collation_from_locale(const char *locale, int nspid,
        /* count valid locales found in operating system */
        (*nvalidp)++;
 
+       /*
+        * A collation whose encoding differs from the database encoding cannot 
be
+        * used in this database, and CREATE COLLATION on a segment would reject
+        * it ("encoding X does not match locale Y"). Creating it on the
+        * coordinator alone would leave pg_collation inconsistent across the
+        * cluster, so skip it entirely. The caller skips it as well, for the
+        * purpose of generating aliases.
+        */
+       if (enc != GetDatabaseEncoding())
+               return enc;
+
        /*
         * Create a collation named the same as the locale, but quietly doing
         * nothing if it already exists.  This is the behavior we need even at
@@ -770,6 +781,15 @@ create_collation_from_locale(const char *locale, int nspid,
                                                         true, true);
        if (OidIsValid(collid))
        {
+               /*
+                * The collation has to exist on the segments too, with the 
same OID.
+                * Dispatching CREATE COLLATION with the OID just assigned here 
is how
+                * the alias and ICU paths do it; this path must do the same, or
+                * pg_collation ends up populated on the coordinator only and
+                * gpcheckcat reports pg_collation as inconsistent.
+                */
+               DispatchCollationCreate(unconstify(char *, locale),
+                                                               unconstify(char 
*, locale), nspid, "libc");
                (*ncreatedp)++;
 
                /* Must do CCI between inserts to handle duplicates correctly */


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to