Re: [HACKERS] initdb initalization failure for collation "ja_JP"

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: [HACKERS] initdb initalization failure for collation "ja_JP"
Дата
Msg-id 15254.1498256420@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: [HACKERS] initdb initalization failure for collation "ja_JP"  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
I wrote:
>> One question that I've got is why the ICU portion refuses to load
>> any entries unless is_encoding_supported_by_icu(GetDatabaseEncoding()).
>> Surely this is completely wrong?  I should think that what we load into
>> pg_collation ought to be independent of template1's encoding, the same
>> as it is for libc collations, and the right place to be making a test
>> like that is where somebody attempts to use an ICU collation.

Pursuant to the second part of that: I checked on what happens if you
try to use an ICU collation in a database with a not-supported-by-ICU
encoding.  We have to cope with that scenario even with the current
(broken IMO) initdb behavior, because even if template1 has a supported
encoding, it's possible to create another database that doesn't.
It does fail more or less cleanly; you get an "encoding "foo" not
supported by ICU" message at runtime (out of get_encoding_name_for_icu).
But that's quite a bit unlike the behavior for libc collations: with
those, you get an error in collation name lookup, along the lines of

collation "en_DK.utf8" for encoding "SQL_ASCII" does not exist

The attached proposed patch makes the behavior for ICU collations the
same, by dint of injecting the is_encoding_supported_by_icu() check
into collation name lookup.

            regards, tom lane

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 64f6fee..029a132 100644
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
*************** OpfamilyIsVisible(Oid opfid)
*** 1915,1923 ****
--- 1915,1974 ----
  }

  /*
+  * lookup_collation
+  *        If there's a collation of the given name/namespace, and it works
+  *        with the given encoding, return its OID.  Else return InvalidOid.
+  */
+ static Oid
+ lookup_collation(const char *collname, Oid collnamespace, int32 encoding)
+ {
+     Oid            collid;
+     HeapTuple    colltup;
+     Form_pg_collation collform;
+
+     /* Check for encoding-specific entry (exact match) */
+     collid = GetSysCacheOid3(COLLNAMEENCNSP,
+                              PointerGetDatum(collname),
+                              Int32GetDatum(encoding),
+                              ObjectIdGetDatum(collnamespace));
+     if (OidIsValid(collid))
+         return collid;
+
+     /*
+      * Check for any-encoding entry.  This takes a bit more work: while libc
+      * collations with collencoding = -1 do work with all encodings, ICU
+      * collations only work with certain encodings, so we have to check that
+      * aspect before deciding it's a match.
+      */
+     colltup = SearchSysCache3(COLLNAMEENCNSP,
+                               PointerGetDatum(collname),
+                               Int32GetDatum(-1),
+                               ObjectIdGetDatum(collnamespace));
+     if (!HeapTupleIsValid(colltup))
+         return InvalidOid;
+     collform = (Form_pg_collation) GETSTRUCT(colltup);
+     if (collform->collprovider == COLLPROVIDER_ICU)
+     {
+         if (is_encoding_supported_by_icu(encoding))
+             collid = HeapTupleGetOid(colltup);
+         else
+             collid = InvalidOid;
+     }
+     else
+     {
+         collid = HeapTupleGetOid(colltup);
+     }
+     ReleaseSysCache(colltup);
+     return collid;
+ }
+
+ /*
   * CollationGetCollid
   *        Try to resolve an unqualified collation name.
   *        Returns OID if collation found in search path, else InvalidOid.
+  *
+  * Note that this will only find collations that work with the current
+  * database's encoding.
   */
  Oid
  CollationGetCollid(const char *collname)
*************** CollationGetCollid(const char *collname)
*** 1935,1953 ****
          if (namespaceId == myTempNamespace)
              continue;            /* do not look in temp namespace */

!         /* Check for database-encoding-specific entry */
!         collid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                  PointerGetDatum(collname),
!                                  Int32GetDatum(dbencoding),
!                                  ObjectIdGetDatum(namespaceId));
!         if (OidIsValid(collid))
!             return collid;
!
!         /* Check for any-encoding entry */
!         collid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                  PointerGetDatum(collname),
!                                  Int32GetDatum(-1),
!                                  ObjectIdGetDatum(namespaceId));
          if (OidIsValid(collid))
              return collid;
      }
--- 1986,1992 ----
          if (namespaceId == myTempNamespace)
              continue;            /* do not look in temp namespace */

!         collid = lookup_collation(collname, namespaceId, dbencoding);
          if (OidIsValid(collid))
              return collid;
      }
*************** CollationGetCollid(const char *collname)
*** 1961,1966 ****
--- 2000,2008 ----
   *        Determine whether a collation (identified by OID) is visible in the
   *        current search path.  Visible means "would be found by searching
   *        for the unqualified collation name".
+  *
+  * Note that only collations that work with the current database's encoding
+  * will be considered visible.
   */
  bool
  CollationIsVisible(Oid collid)
*************** CollationIsVisible(Oid collid)
*** 1990,1998 ****
      {
          /*
           * If it is in the path, it might still not be visible; it could be
!          * hidden by another conversion of the same name earlier in the path.
!          * So we must do a slow check to see if this conversion would be found
!          * by CollationGetCollid.
           */
          char       *collname = NameStr(collform->collname);

--- 2032,2041 ----
      {
          /*
           * If it is in the path, it might still not be visible; it could be
!          * hidden by another collation of the same name earlier in the path,
!          * or it might not work with the current DB encoding.  So we must do a
!          * slow check to see if this collation would be found by
!          * CollationGetCollid.
           */
          char       *collname = NameStr(collform->collname);

*************** PopOverrideSearchPath(void)
*** 3442,3447 ****
--- 3485,3493 ----

  /*
   * get_collation_oid - find a collation by possibly qualified name
+  *
+  * Note that this will only find collations that work with the current
+  * database's encoding.
   */
  Oid
  get_collation_oid(List *name, bool missing_ok)
*************** get_collation_oid(List *name, bool missi
*** 3463,3479 ****
          if (missing_ok && !OidIsValid(namespaceId))
              return InvalidOid;

!         /* first try for encoding-specific entry, then any-encoding */
!         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                   PointerGetDatum(collation_name),
!                                   Int32GetDatum(dbencoding),
!                                   ObjectIdGetDatum(namespaceId));
!         if (OidIsValid(colloid))
!             return colloid;
!         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                   PointerGetDatum(collation_name),
!                                   Int32GetDatum(-1),
!                                   ObjectIdGetDatum(namespaceId));
          if (OidIsValid(colloid))
              return colloid;
      }
--- 3509,3515 ----
          if (missing_ok && !OidIsValid(namespaceId))
              return InvalidOid;

!         colloid = lookup_collation(collation_name, namespaceId, dbencoding);
          if (OidIsValid(colloid))
              return colloid;
      }
*************** get_collation_oid(List *name, bool missi
*** 3489,3504 ****
              if (namespaceId == myTempNamespace)
                  continue;        /* do not look in temp namespace */

!             colloid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                       PointerGetDatum(collation_name),
!                                       Int32GetDatum(dbencoding),
!                                       ObjectIdGetDatum(namespaceId));
!             if (OidIsValid(colloid))
!                 return colloid;
!             colloid = GetSysCacheOid3(COLLNAMEENCNSP,
!                                       PointerGetDatum(collation_name),
!                                       Int32GetDatum(-1),
!                                       ObjectIdGetDatum(namespaceId));
              if (OidIsValid(colloid))
                  return colloid;
          }
--- 3525,3531 ----
              if (namespaceId == myTempNamespace)
                  continue;        /* do not look in temp namespace */

!             colloid = lookup_collation(collation_name, namespaceId, dbencoding);
              if (OidIsValid(colloid))
                  return colloid;
          }

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: [HACKERS] Logical replication: stuck spinlock at ReplicationSlotRelease
Следующее
От: Peter Geoghegan
Дата:
Сообщение: Re: [HACKERS] Can ICU be used for a database's default sort order?