Change collate and ctype fields to type text
authorPeter Eisentraut <peter@eisentraut.org>
Thu, 27 Jan 2022 07:44:31 +0000 (08:44 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Thu, 27 Jan 2022 07:54:25 +0000 (08:54 +0100)
This changes the data type of the catalog fields datcollate, datctype,
collcollate, and collctype from name to text.  There wasn't ever a
really good reason for them to be of type name; presumably this was
just carried over from when they were fixed-size fields in pg_control,
first into the corresponding pg_database fields, and then to
pg_collation.  The values are not identifiers or object names, and we
don't ever look them up that way.

Changing to type text saves space in the typical case, since locale
names are typically only a few bytes long.  But it is also possible
that an ICU locale name with several customization options appended
could be longer than 63 bytes, so this also enables that case, which
was previously probably broken.

Reviewed-by: Julien Rouhaud <rjuju123@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/5e756dd6-0e91-d778-96fd-b1bcb06c161a@2ndquadrant.com

doc/src/sgml/catalogs.sgml
src/backend/catalog/pg_collation.c
src/backend/commands/collationcmds.c
src/backend/commands/dbcommands.c
src/backend/utils/adt/pg_locale.c
src/backend/utils/init/postinit.c
src/include/catalog/catversion.h
src/include/catalog/pg_collation.h
src/include/catalog/pg_database.h
src/include/utils/pg_locale.h

index 1e65c426b28eac5aa20cf16f78dc3623cd9e84dd..7d5b0b1656c996d5337a966ba5d59769a9b9c355 100644 (file)
@@ -2368,7 +2368,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>collcollate</structfield> <type>name</type>
+       <structfield>collcollate</structfield> <type>text</type>
       </para>
       <para>
        <symbol>LC_COLLATE</symbol> for this collation object
@@ -2377,7 +2377,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>collctype</structfield> <type>name</type>
+       <structfield>collctype</structfield> <type>text</type>
       </para>
       <para>
        <symbol>LC_CTYPE</symbol> for this collation object
@@ -2951,24 +2951,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>datcollate</structfield> <type>name</type>
-      </para>
-      <para>
-       LC_COLLATE for this database
-      </para></entry>
-     </row>
-
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>datctype</structfield> <type>name</type>
-      </para>
-      <para>
-       LC_CTYPE for this database
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>datistemplate</structfield> <type>bool</type>
@@ -3043,6 +3025,24 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>datcollate</structfield> <type>text</type>
+      </para>
+      <para>
+       LC_COLLATE for this database
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>datctype</structfield> <type>text</type>
+      </para>
+      <para>
+       LC_CTYPE for this database
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>datacl</structfield> <type>aclitem[]</type>
index 5be6600652294f73f1ddcc157b04c64829efba58..bfc02d303849ae0e5b928f1a32ef9f65ae7b5075 100644 (file)
@@ -58,9 +58,7 @@ CollationCreate(const char *collname, Oid collnamespace,
    HeapTuple   tup;
    Datum       values[Natts_pg_collation];
    bool        nulls[Natts_pg_collation];
-   NameData    name_name,
-               name_collate,
-               name_ctype;
+   NameData    name_name;
    Oid         oid;
    ObjectAddress myself,
                referenced;
@@ -163,10 +161,8 @@ CollationCreate(const char *collname, Oid collnamespace,
    values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider);
    values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic);
    values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding);
-   namestrcpy(&name_collate, collcollate);
-   values[Anum_pg_collation_collcollate - 1] = NameGetDatum(&name_collate);
-   namestrcpy(&name_ctype, collctype);
-   values[Anum_pg_collation_collctype - 1] = NameGetDatum(&name_ctype);
+   values[Anum_pg_collation_collcollate - 1] = CStringGetTextDatum(collcollate);
+   values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype);
    if (collversion)
        values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion);
    else
index 56748551ded080a1455d130b4c614a91db307077..12fc2316f974c51b43e5c044085a477367bce291 100644 (file)
@@ -129,18 +129,30 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
    {
        Oid         collid;
        HeapTuple   tp;
+       Datum       datum;
+       bool        isnull;
 
        collid = get_collation_oid(defGetQualifiedName(fromEl), false);
        tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
        if (!HeapTupleIsValid(tp))
            elog(ERROR, "cache lookup failed for collation %u", collid);
 
-       collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
-       collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype));
        collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
        collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
        collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
 
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
+       if (!isnull)
+           collcollate = TextDatumGetCString(datum);
+       else
+           collcollate = NULL;
+
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
+       if (!isnull)
+           collctype = TextDatumGetCString(datum);
+       else
+           collctype = NULL;
+
        ReleaseSysCache(tp);
 
        /*
@@ -314,7 +326,7 @@ AlterCollation(AlterCollationStmt *stmt)
    Oid         collOid;
    HeapTuple   tup;
    Form_pg_collation collForm;
-   Datum       collversion;
+   Datum       datum;
    bool        isnull;
    char       *oldversion;
    char       *newversion;
@@ -332,11 +344,12 @@ AlterCollation(AlterCollationStmt *stmt)
        elog(ERROR, "cache lookup failed for collation %u", collOid);
 
    collForm = (Form_pg_collation) GETSTRUCT(tup);
-   collversion = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion,
-                                 &isnull);
-   oldversion = isnull ? NULL : TextDatumGetCString(collversion);
+   datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
+   oldversion = isnull ? NULL : TextDatumGetCString(datum);
 
-   newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
+   datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collcollate, &isnull);
+   Assert(!isnull);
+   newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
 
    /* cannot change from NULL to non-NULL or vice versa */
    if ((!oldversion && newversion) || (oldversion && !newversion))
@@ -383,8 +396,9 @@ pg_collation_actual_version(PG_FUNCTION_ARGS)
 {
    Oid         collid = PG_GETARG_OID(0);
    HeapTuple   tp;
-   char       *collcollate;
    char        collprovider;
+   Datum       datum;
+   bool        isnull;
    char       *version;
 
    tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
@@ -393,12 +407,13 @@ pg_collation_actual_version(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("collation with OID %u does not exist", collid)));
 
-   collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
    collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
 
-   ReleaseSysCache(tp);
+   datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
+   Assert(!isnull);
+   version = get_collation_actual_version(collprovider, TextDatumGetCString(datum));
 
-   version = get_collation_actual_version(collprovider, collcollate);
+   ReleaseSysCache(tp);
 
    if (version)
        PG_RETURN_TEXT_P(cstring_to_text(version));
@@ -546,7 +561,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
 #ifdef READ_LOCALE_A_OUTPUT
    {
        FILE       *locale_a_handle;
-       char        localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */
+       char        localebuf[LOCALE_NAME_BUFLEN];
        int         nvalid = 0;
        Oid         collid;
        CollAliasData *aliases;
@@ -570,7 +585,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
        {
            size_t      len;
            int         enc;
-           char        alias[NAMEDATALEN];
+           char        alias[LOCALE_NAME_BUFLEN];
 
            len = strlen(localebuf);
 
index e950e4c458a1543532c4b02bea5867ec3afca814..5a6c9beaa4765862280b8029521cd45daf448320 100644 (file)
@@ -570,10 +570,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
        DirectFunctionCall1(namein, CStringGetDatum(dbname));
    new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba);
    new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
-   new_record[Anum_pg_database_datcollate - 1] =
-       DirectFunctionCall1(namein, CStringGetDatum(dbcollate));
-   new_record[Anum_pg_database_datctype - 1] =
-       DirectFunctionCall1(namein, CStringGetDatum(dbctype));
+   new_record[Anum_pg_database_datcollate - 1] = CStringGetTextDatum(dbcollate);
+   new_record[Anum_pg_database_datctype - 1] = CStringGetTextDatum(dbctype);
    new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(dbistemplate);
    new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(dballowconnections);
    new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
@@ -1867,6 +1865,9 @@ get_db_info(const char *name, LOCKMODE lockmode,
 
            if (strcmp(name, NameStr(dbform->datname)) == 0)
            {
+               Datum       datum;
+               bool        isnull;
+
                /* oid of the database */
                if (dbIdP)
                    *dbIdP = dbOid;
@@ -1893,9 +1894,17 @@ get_db_info(const char *name, LOCKMODE lockmode,
                    *dbTablespace = dbform->dattablespace;
                /* default locale settings for this database */
                if (dbCollate)
-                   *dbCollate = pstrdup(NameStr(dbform->datcollate));
+               {
+                   datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datcollate, &isnull);
+                   Assert(!isnull);
+                   *dbCollate = TextDatumGetCString(datum);
+               }
                if (dbCtype)
-                   *dbCtype = pstrdup(NameStr(dbform->datctype));
+               {
+                   datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datctype, &isnull);
+                   Assert(!isnull);
+                   *dbCtype = TextDatumGetCString(datum);
+               }
                ReleaseSysCache(tuple);
                result = true;
                break;
index 33cccc5c6c726510383812dd1e91192ca68d9f37..aefa0818d0a3ab2ef60f0cf1bbf49492abcd3558 100644 (file)
@@ -179,7 +179,7 @@ pg_perm_setlocale(int category, const char *locale)
     */
    if (category == LC_CTYPE)
    {
-       static char save_lc_ctype[NAMEDATALEN + 20];
+       static char save_lc_ctype[LOCALE_NAME_BUFLEN];
 
        /* copy setlocale() return value before callee invokes it again */
        strlcpy(save_lc_ctype, result, sizeof(save_lc_ctype));
@@ -1288,17 +1288,21 @@ lookup_collation_cache(Oid collation, bool set_flags)
    {
        /* Attempt to set the flags */
        HeapTuple   tp;
-       Form_pg_collation collform;
+       Datum       datum;
+       bool        isnull;
        const char *collcollate;
        const char *collctype;
 
        tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
        if (!HeapTupleIsValid(tp))
            elog(ERROR, "cache lookup failed for collation %u", collation);
-       collform = (Form_pg_collation) GETSTRUCT(tp);
 
-       collcollate = NameStr(collform->collcollate);
-       collctype = NameStr(collform->collctype);
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
+       Assert(!isnull);
+       collcollate = TextDatumGetCString(datum);
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
+       Assert(!isnull);
+       collctype = TextDatumGetCString(datum);
 
        cache_entry->collate_is_c = ((strcmp(collcollate, "C") == 0) ||
                                     (strcmp(collcollate, "POSIX") == 0));
@@ -1484,7 +1488,7 @@ pg_newlocale_from_collation(Oid collid)
        const char *collctype pg_attribute_unused();
        struct pg_locale_struct result;
        pg_locale_t resultp;
-       Datum       collversion;
+       Datum       datum;
        bool        isnull;
 
        tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
@@ -1492,8 +1496,12 @@ pg_newlocale_from_collation(Oid collid)
            elog(ERROR, "cache lookup failed for collation %u", collid);
        collform = (Form_pg_collation) GETSTRUCT(tp);
 
-       collcollate = NameStr(collform->collcollate);
-       collctype = NameStr(collform->collctype);
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
+       Assert(!isnull);
+       collcollate = TextDatumGetCString(datum);
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
+       Assert(!isnull);
+       collctype = TextDatumGetCString(datum);
 
        /* We'll fill in the result struct locally before allocating memory */
        memset(&result, 0, sizeof(result));
@@ -1587,13 +1595,15 @@ pg_newlocale_from_collation(Oid collid)
 #endif                         /* not USE_ICU */
        }
 
-       collversion = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
+       datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
                                      &isnull);
        if (!isnull)
        {
            char       *actual_versionstr;
            char       *collversionstr;
 
+           collversionstr = TextDatumGetCString(datum);
+
            actual_versionstr = get_collation_actual_version(collform->collprovider, collcollate);
            if (!actual_versionstr)
            {
@@ -1606,7 +1616,6 @@ pg_newlocale_from_collation(Oid collid)
                        (errmsg("collation \"%s\" has no actual version, but a version was specified",
                                NameStr(collform->collname))));
            }
-           collversionstr = TextDatumGetCString(collversion);
 
            if (strcmp(actual_versionstr, collversionstr) != 0)
                ereport(WARNING,
index 0236165f60fa00c6d02329833aaaf5a6c6f5a04b..d046caabd7d8b3dd07a623bca74768cff4bba112 100644 (file)
@@ -53,6 +53,7 @@
 #include "storage/sync.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
+#include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
@@ -306,6 +307,8 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
 {
    HeapTuple   tup;
    Form_pg_database dbform;
+   Datum       datum;
+   bool        isnull;
    char       *collate;
    char       *ctype;
 
@@ -389,8 +392,12 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
                    PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
 
    /* assign locale variables */
-   collate = NameStr(dbform->datcollate);
-   ctype = NameStr(dbform->datctype);
+   datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datcollate, &isnull);
+   Assert(!isnull);
+   collate = TextDatumGetCString(datum);
+   datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datctype, &isnull);
+   Assert(!isnull);
+   ctype = TextDatumGetCString(datum);
 
    if (pg_perm_setlocale(LC_COLLATE, collate) == NULL)
        ereport(FATAL,
index 2f32ae169671267b9d87cd43fdf273c823217f34..656b6c8f00e4895bacfab1df27ccd713d4f2d3e0 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202201201
+#define CATALOG_VERSION_NO 202201271
 
 #endif
index bc746537c1ce4aad4e0406eaacedc64fc177f75a..8763dd40807d5b001ce4c5d95d182f9f47068bdd 100644 (file)
@@ -39,9 +39,9 @@ CATALOG(pg_collation,3456,CollationRelationId)
    char        collprovider;   /* see constants below */
    bool        collisdeterministic BKI_DEFAULT(t);
    int32       collencoding;   /* encoding for this collation; -1 = "all" */
-   NameData    collcollate;    /* LC_COLLATE setting */
-   NameData    collctype;      /* LC_CTYPE setting */
 #ifdef CATALOG_VARLEN          /* variable-length fields start here */
+   text        collcollate BKI_FORCE_NOT_NULL;     /* LC_COLLATE setting */
+   text        collctype BKI_FORCE_NOT_NULL;       /* LC_CTYPE setting */
    text        collversion BKI_DEFAULT(_null_);    /* provider-dependent
                                                     * version of collation
                                                     * data */
index 1ff6d3e50c81fc69b8d05c4b2c9a4f83d21e82bf..90b43a4ecc98ba31ee02e611af710823b873a84b 100644 (file)
@@ -40,12 +40,6 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
    /* character encoding */
    int32       encoding;
 
-   /* LC_COLLATE setting */
-   NameData    datcollate;
-
-   /* LC_CTYPE setting */
-   NameData    datctype;
-
    /* allowed as CREATE DATABASE template? */
    bool        datistemplate;
 
@@ -65,6 +59,12 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
    Oid         dattablespace BKI_LOOKUP(pg_tablespace);
 
 #ifdef CATALOG_VARLEN          /* variable-length fields start here */
+   /* LC_COLLATE setting */
+   text        datcollate BKI_FORCE_NOT_NULL;
+
+   /* LC_CTYPE setting */
+   text        datctype BKI_FORCE_NOT_NULL;
+
    /* access permissions */
    aclitem     datacl[1];
 #endif
index b4a27659837eeb202c74023c8a0a3b3c13b8d732..30e423af0eb2f6d68bbeb7a42aefd06d0a464c1e 100644 (file)
@@ -34,6 +34,8 @@
 #endif
 #endif
 
+/* use for libc locale names */
+#define LOCALE_NAME_BUFLEN 128
 
 /* GUC settings */
 extern char *locale_messages;