TODO item: locale per database patch (new iteration) - Mailing list pgsql-patches

From Alexey Slynko
Subject TODO item: locale per database patch (new iteration)
Date
Msg-id 43D3E3A7.10800@tronet.ru
Whole thread Raw
List pgsql-patches
Hi,

it's a renewed locale per database patch. Unfortunately, i've not found
clean way to rebuild database indexes automatically, if locale settings
of two databases (created and template) are differs. Now it's only
raises a NOTICE. So, if anyone has a right notion about it - let will
express. Comment and suggestions are highly appreciated
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.226
diff -u -r1.226 xlog.c
--- src/backend/access/transam/xlog.c    11 Jan 2006 08:43:12 -0000    1.226
+++ src/backend/access/transam/xlog.c    22 Jan 2006 16:41:02 -0000
@@ -3394,7 +3394,6 @@
 {
     int            fd;
     char        buffer[BLCKSZ]; /* need not be aligned */
-    char       *localeptr;

     /*
      * Initialize version and compatibility-check fields
@@ -3418,18 +3417,6 @@
     ControlFile->enableIntTimes = FALSE;
 #endif

-    ControlFile->localeBuflen = LOCALE_NAME_BUFLEN;
-    localeptr = setlocale(LC_COLLATE, NULL);
-    if (!localeptr)
-        ereport(PANIC,
-                (errmsg("invalid LC_COLLATE setting")));
-    StrNCpy(ControlFile->lc_collate, localeptr, LOCALE_NAME_BUFLEN);
-    localeptr = setlocale(LC_CTYPE, NULL);
-    if (!localeptr)
-        ereport(PANIC,
-                (errmsg("invalid LC_CTYPE setting")));
-    StrNCpy(ControlFile->lc_ctype, localeptr, LOCALE_NAME_BUFLEN);
-
     /* Contents are protected with a CRC */
     INIT_CRC32(ControlFile->crc);
     COMP_CRC32(ControlFile->crc,
@@ -3612,34 +3599,6 @@
                " but the server was compiled without HAVE_INT64_TIMESTAMP."),
                  errhint("It looks like you need to recompile or initdb.")));
 #endif
-
-    if (ControlFile->localeBuflen != LOCALE_NAME_BUFLEN)
-        ereport(FATAL,
-                (errmsg("database files are incompatible with server"),
-                 errdetail("The database cluster was initialized with LOCALE_NAME_BUFLEN %d,"
-                  " but the server was compiled with LOCALE_NAME_BUFLEN %d.",
-                           ControlFile->localeBuflen, LOCALE_NAME_BUFLEN),
-                 errhint("It looks like you need to recompile or initdb.")));
-    if (pg_perm_setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
-        ereport(FATAL,
-            (errmsg("database files are incompatible with operating system"),
-             errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
-                       " which is not recognized by setlocale().",
-                       ControlFile->lc_collate),
-             errhint("It looks like you need to initdb or install locale support.")));
-    if (pg_perm_setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
-        ereport(FATAL,
-            (errmsg("database files are incompatible with operating system"),
-        errdetail("The database cluster was initialized with LC_CTYPE \"%s\","
-                  " which is not recognized by setlocale().",
-                  ControlFile->lc_ctype),
-             errhint("It looks like you need to initdb or install locale support.")));
-
-    /* Make the fixed locale settings visible as GUC variables, too */
-    SetConfigOption("lc_collate", ControlFile->lc_collate,
-                    PGC_INTERNAL, PGC_S_OVERRIDE);
-    SetConfigOption("lc_ctype", ControlFile->lc_ctype,
-                    PGC_INTERNAL, PGC_S_OVERRIDE);
 }

 void
Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.175
diff -u -r1.175 dbcommands.c
--- src/backend/commands/dbcommands.c    22 Nov 2005 18:17:08 -0000    1.175
+++ src/backend/commands/dbcommands.c    22 Jan 2006 16:41:03 -0000
@@ -25,6 +25,10 @@
 #include <unistd.h>
 #include <sys/stat.h>

+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catalog.h"
@@ -49,6 +53,7 @@
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
+#include "utils/pg_locale.h"
 #include "utils/syscache.h"


@@ -57,9 +62,11 @@
             int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
             Oid *dbLastSysOidP,
             TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
-            Oid *dbTablespace);
+            Oid *dbTablespace, char **dbCollate, char **dbCtype);
 static bool have_createdb_privilege(void);
 static void remove_dbtablespaces(Oid db_id);
+static char * get_locale_encoding(const char *ctype);
+static int check_locale_encoding(int encid, const char *ctype);


 /*
@@ -73,6 +80,8 @@
     Oid            src_dboid;
     Oid            src_owner;
     int            src_encoding;
+    char            *src_collate;
+    char            *src_ctype;
     bool        src_istemplate;
     bool        src_allowconn;
     Oid            src_lastsysoid;
@@ -92,10 +101,14 @@
     DefElem    *downer = NULL;
     DefElem    *dtemplate = NULL;
     DefElem    *dencoding = NULL;
+    DefElem    *dlc_collate = NULL;
+    DefElem    *dlc_ctype = NULL;
     DefElem    *dconnlimit = NULL;
     char       *dbname = stmt->dbname;
     char       *dbowner = NULL;
     const char *dbtemplate = NULL;
+    char *lc_collate = NULL;
+    char *lc_ctype = NULL;
     volatile int encoding = -1;
     volatile int dbconnlimit = -1;

@@ -139,6 +152,22 @@
                          errmsg("conflicting or redundant options")));
             dencoding = defel;
         }
+        else if (strcmp(defel->defname, "lccollate") == 0)
+        {
+            if (dlc_collate)
+                ereport(ERROR,
+                        (errcode(ERRCODE_SYNTAX_ERROR),
+                        errmsg("conflicting or redundant options")));
+            dlc_collate = defel;
+        }
+        else if (strcmp(defel->defname, "lcctype") == 0)
+        {
+            if (dlc_ctype)
+                ereport(ERROR,
+                        (errcode(ERRCODE_SYNTAX_ERROR),
+                        errmsg("conflicting or redundant options")));
+            dlc_ctype = defel;
+        }
         else if (strcmp(defel->defname, "connectionlimit") == 0)
         {
             if (dconnlimit)
@@ -192,6 +221,22 @@
             elog(ERROR, "unrecognized node type: %d",
                  nodeTag(dencoding->arg));
     }
+    if (dlc_collate && dlc_collate->arg) {
+        lc_collate = strVal(dlc_collate->arg);
+        if ((locale_collate_assign(lc_collate, false, (GucSource)NULL)) == NULL)
+            ereport(ERROR,
+                (errcode(ERRCODE_UNDEFINED_OBJECT),
+                errmsg("%s is not a valid LC_COLLATE name",
+                        lc_collate)));
+    }
+    if (dlc_ctype && dlc_ctype->arg) {
+        lc_ctype = strVal(dlc_ctype->arg);
+        if ((locale_collate_assign(lc_ctype, false, (GucSource)NULL)) == NULL)
+            ereport(ERROR,
+                (errcode(ERRCODE_UNDEFINED_OBJECT),
+                errmsg("%s is not a valid LC_CTYPE name",
+                        lc_ctype)));
+    }
     if (dconnlimit && dconnlimit->arg)
         dbconnlimit = intVal(dconnlimit->arg);

@@ -224,7 +269,7 @@
      * grab the exclusive lock.
      */
     if (get_db_info(dbname, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, NULL))
+                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
         ereport(ERROR,
                 (errcode(ERRCODE_DUPLICATE_DATABASE),
                  errmsg("database \"%s\" already exists", dbname)));
@@ -237,7 +282,8 @@

     if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
                      &src_istemplate, &src_allowconn, &src_lastsysoid,
-                     &src_vacuumxid, &src_frozenxid, &src_deftablespace))
+                     &src_vacuumxid, &src_frozenxid, &src_deftablespace,
+                     &src_collate, &src_ctype))
         ereport(ERROR,
                 (errcode(ERRCODE_UNDEFINED_DATABASE),
              errmsg("template database \"%s\" does not exist", dbtemplate)));
@@ -277,6 +323,21 @@
                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                  errmsg("invalid server encoding %d", encoding)));

+    /* Set database lc_collate and lc_ctype */
+    if (!lc_collate)
+        lc_collate = src_collate;
+    if (!lc_ctype)
+        lc_ctype = src_ctype;
+
+#if defined(HAVE_LANGINFO_H) && defined(CODESET)
+    if (encoding > 0 && check_locale_encoding(encoding, lc_ctype) == -1)
+        ereport(ERROR,
+                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                 errmsg("encoding %s is not suitable for locale %s",
+                            pg_encoding_to_char(encoding),
+                            lc_ctype)));
+#endif
+
     /* Resolve default tablespace for new database */
     if (dtablespacename && dtablespacename->arg)
     {
@@ -441,7 +502,7 @@

         /* Check to see if someone else created same DB name meanwhile. */
         if (get_db_info(dbname, NULL, NULL, NULL,
-                        NULL, NULL, NULL, NULL, NULL, NULL))
+                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
             ereport(ERROR,
                     (errcode(ERRCODE_DUPLICATE_DATABASE),
                      errmsg("database \"%s\" already exists", dbname)));
@@ -459,6 +520,11 @@
             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(lc_collate));
+        new_record[Anum_pg_database_datctype - 1] =
+            DirectFunctionCall1(namein, CStringGetDatum(lc_ctype));
+
         new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
         new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
         new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
@@ -527,6 +593,15 @@
          * Set flag to update flat database file at commit.
          */
         database_file_update_needed();
+
+        /*
+         * Message about reindexing new database
+         */
+        if (lc_collate != src_collate || lc_ctype != src_ctype)
+            ereport(NOTICE,
+                    (errmsg("database \"%s\" need to be reindexed manually (REINDEX DATABASE)",
+                            dbname)));
+
     }
     PG_CATCH();
     {
@@ -584,7 +659,7 @@
     pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock);

     if (!get_db_info(dbname, &db_id, NULL, NULL,
-                     &db_istemplate, NULL, NULL, NULL, NULL, NULL))
+                     &db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
     {
         if (!missing_ok)
         {
@@ -1100,7 +1175,7 @@
             int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
             Oid *dbLastSysOidP,
             TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
-            Oid *dbTablespace)
+            Oid *dbTablespace, char **dbCollate, char **dbCtype)
 {
     Relation    relation;
     ScanKeyData scanKey;
@@ -1155,6 +1230,11 @@
         /* default tablespace for this database */
         if (dbTablespace)
             *dbTablespace = dbform->dattablespace;
+        /* default locale settings for this database */
+        if (dbCollate)
+            *dbCollate = NameStr(dbform->datcollate);
+        if (dbCtype)
+            *dbCtype = NameStr(dbform->datctype);
     }

     systable_endscan(scan);
@@ -1416,3 +1496,45 @@
     else
         strcat(buf, "UNKNOWN");
 }
+
+#if defined(HAVE_LANGINFO_H) && defined(CODESET)
+
+static char *
+get_locale_encoding(const char *ctype)
+{
+    char       *save;
+    char       *sys;
+
+        save = setlocale(LC_CTYPE, NULL);
+        if (!save)
+                return NULL;
+        save = pstrdup(save);
+
+        setlocale(LC_CTYPE, ctype);
+        sys = nl_langinfo(CODESET);
+        sys = pstrdup(sys);
+
+        setlocale(LC_CTYPE, save);
+        pfree(save);
+
+        return sys;
+}
+
+static int
+check_locale_encoding(int encid, const char *ctype)
+{
+        char       *sys;
+
+        sys = get_locale_encoding(ctype);
+        if (encid == pg_char_to_encoding(sys))
+        {
+                pfree(sys);
+                return 0;
+        }
+
+        pfree(sys);
+        return -1;
+}
+
+#endif
+
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.522
diff -u -r2.522 gram.y
--- src/backend/parser/gram.y    21 Jan 2006 02:16:19 -0000    2.522
+++ src/backend/parser/gram.y    22 Jan 2006 16:41:09 -0000
@@ -372,7 +372,7 @@

     KEY

-    LANCOMPILER LANGUAGE LARGE_P  LAST_P LEADING LEAST LEFT LEVEL
+    LANCOMPILER LANGUAGE LARGE_P  LAST_P LCCOLLATE LCCTYPE LEADING LEAST LEFT LEVEL
     LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
     LOCK_P LOGIN_P

@@ -4635,6 +4635,22 @@
                 {
                     $$ = makeDefElem("encoding", NULL);
                 }
+            | LCCOLLATE opt_equal name
+                {
+                    $$ = makeDefElem("lccollate", (Node *)makeString($3));
+                }
+            | LCCOLLATE opt_equal DEFAULT
+                {
+                    $$ = makeDefElem("lccollate", NULL);
+                }
+            | LCCTYPE opt_equal name
+                {
+                    $$ = makeDefElem("lcctype", (Node *)makeString($3));
+                }
+            | LCCTYPE opt_equal DEFAULT
+                {
+                    $$ = makeDefElem("lcctype", NULL);
+                }
             | CONNECTION LIMIT opt_equal SignedIconst
                 {
                     $$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
@@ -8225,6 +8241,8 @@
             | LANGUAGE
             | LARGE_P
             | LAST_P
+            | LCCOLLATE
+            | LCCTYPE
             | LEVEL
             | LISTEN
             | LOAD
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.170
diff -u -r1.170 keywords.c
--- src/backend/parser/keywords.c    27 Dec 2005 04:00:07 -0000    1.170
+++ src/backend/parser/keywords.c    22 Jan 2006 16:41:09 -0000
@@ -193,6 +193,8 @@
     {"language", LANGUAGE},
     {"large", LARGE_P},
     {"last", LAST_P},
+    {"lccollate", LCCOLLATE},
+    {"lcctype", LCCTYPE},
     {"leading", LEADING},
     {"least", LEAST},
     {"left", LEFT},
Index: src/backend/utils/adt/pg_locale.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v
retrieving revision 1.34
diff -u -r1.34 pg_locale.c
--- src/backend/utils/adt/pg_locale.c    2 Jan 2006 20:25:45 -0000    1.34
+++ src/backend/utils/adt/pg_locale.c    22 Jan 2006 16:41:10 -0000
@@ -10,10 +10,8 @@
  */

 /*----------
- * Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
- * are fixed by initdb, stored in pg_control, and cannot be changed.
- * Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
- * etc. are always in the same fixed locale.
+ * Here is how the locale stuff is handled:
+ * LC_COLLATE and LC_CTYPE are defined by createdb and stored in pg_database.
  *
  * LC_MESSAGES is settable at run time and will take effect
  * immediately.
@@ -208,6 +206,17 @@
     return value;
 }

+const char *
+locale_collate_assign(const char *value, bool doit, GucSource source)
+{
+    return locale_xxx_assign(LC_COLLATE, value, doit, source);
+}
+
+const char *
+locale_ctype_assign(const char *value, bool doit, GucSource source)
+{
+    return locale_xxx_assign(LC_CTYPE, value, doit, source);
+}

 const char *
 locale_monetary_assign(const char *value, bool doit, GucSource source)
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.160
diff -u -r1.160 postinit.c
--- src/backend/utils/init/postinit.c    4 Jan 2006 21:06:32 -0000    1.160
+++ src/backend/utils/init/postinit.c    22 Jan 2006 16:41:10 -0000
@@ -138,6 +138,8 @@
     ScanKeyData key;
     HeapTuple    tup;
     Form_pg_database dbform;
+    char        *lc_ctype;
+    char        *lc_collate;

     /*
      * Because we grab RowShareLock here, we can be sure that dropdb() is not
@@ -225,6 +227,32 @@
     SetConfigOption("client_encoding", GetDatabaseEncodingName(),
                     PGC_BACKEND, PGC_S_DEFAULT);

+    /* Set up database locale */
+    lc_collate = NameStr(dbform->datcollate);
+    lc_ctype = NameStr(dbform->datctype);
+
+    if (setlocale(LC_COLLATE, lc_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().",
+                    lc_collate),
+            errhint("It looks like you need to recreate database or install locale support.")));
+    if (setlocale(LC_CTYPE, lc_ctype) == NULL)
+        ereport(FATAL,
+            (errmsg("database locale are incompatible with operating system"),
+            errdetail("The database was initialized with LC_CTYPE \"%s\","
+                    " which is not recognized by setlocale().",
+                    lc_ctype),
+            errhint("It looks like you need to recreate database or install locale support.")));
+
+    /* Record it as a GUC internal option, too */
+    SetConfigOption("lc_collate", lc_collate,
+                    PGC_INTERNAL, PGC_S_DATABASE);
+    SetConfigOption("lc_ctype", lc_ctype,
+                    PGC_INTERNAL, PGC_S_DATABASE);
+
+
     /*
      * Lastly, set up any database-specific configuration variables.
      */
Index: src/bin/initdb/initdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.106
diff -u -r1.106 initdb.c
--- src/bin/initdb/initdb.c    5 Jan 2006 10:07:46 -0000    1.106
+++ src/bin/initdb/initdb.c    22 Jan 2006 16:41:13 -0000
@@ -1377,6 +1377,10 @@

     bki_lines = replace_token(bki_lines, "ENCODING", encodingid);

+    bki_lines = replace_token(bki_lines, "LC_COLLATE", lc_collate);
+
+    bki_lines = replace_token(bki_lines, "LC_CTYPE", lc_ctype);
+
     /*
      * Pass correct LC_xxx environment to bootstrap.
      *
@@ -2617,7 +2621,7 @@
         printf(_("The database cluster will be initialized with locale %s.\n"), lc_ctype);
     else
     {
-        printf(_("The database cluster will be initialized with locales\n"
+        printf(_("The database template1 will be initialized with locales\n"
                  "  COLLATE:  %s\n"
                  "  CTYPE:    %s\n"
                  "  MESSAGES: %s\n"
Index: src/bin/pg_controldata/pg_controldata.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_controldata/pg_controldata.c,v
retrieving revision 1.27
diff -u -r1.27 pg_controldata.c
--- src/bin/pg_controldata/pg_controldata.c    15 Oct 2005 02:49:37 -0000    1.27
+++ src/bin/pg_controldata/pg_controldata.c    22 Jan 2006 16:41:13 -0000
@@ -177,9 +177,5 @@
     printf(_("Maximum columns in an index:          %u\n"), ControlFile.indexMaxKeys);
     printf(_("Date/time type storage:               %s\n"),
            (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
-    printf(_("Maximum length of locale name:        %u\n"), ControlFile.localeBuflen);
-    printf(_("LC_COLLATE:                           %s\n"), ControlFile.lc_collate);
-    printf(_("LC_CTYPE:                             %s\n"), ControlFile.lc_ctype);
-
     return 0;
 }
Index: src/bin/pg_resetxlog/pg_resetxlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v
retrieving revision 1.39
diff -u -r1.39 pg_resetxlog.c
--- src/bin/pg_resetxlog/pg_resetxlog.c    5 Jan 2006 03:01:37 -0000    1.39
+++ src/bin/pg_resetxlog/pg_resetxlog.c    22 Jan 2006 16:41:13 -0000
@@ -465,22 +465,6 @@
 #else
     ControlFile.enableIntTimes = FALSE;
 #endif
-    ControlFile.localeBuflen = LOCALE_NAME_BUFLEN;
-
-    localeptr = setlocale(LC_COLLATE, "");
-    if (!localeptr)
-    {
-        fprintf(stderr, _("%s: invalid LC_COLLATE setting\n"), progname);
-        exit(1);
-    }
-    StrNCpy(ControlFile.lc_collate, localeptr, LOCALE_NAME_BUFLEN);
-    localeptr = setlocale(LC_CTYPE, "");
-    if (!localeptr)
-    {
-        fprintf(stderr, _("%s: invalid LC_CTYPE setting\n"), progname);
-        exit(1);
-    }
-    StrNCpy(ControlFile.lc_ctype, localeptr, LOCALE_NAME_BUFLEN);

     /*
      * XXX eventually, should try to grovel through old XLOG to develop more
@@ -530,9 +514,6 @@
     printf(_("Maximum columns in an index:          %u\n"), ControlFile.indexMaxKeys);
     printf(_("Date/time type storage:               %s\n"),
            (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
-    printf(_("Maximum length of locale name:        %u\n"), ControlFile.localeBuflen);
-    printf(_("LC_COLLATE:                           %s\n"), ControlFile.lc_collate);
-    printf(_("LC_CTYPE:                             %s\n"), ControlFile.lc_ctype);
 }


Index: src/bin/psql/describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.130
diff -u -r1.130 describe.c
--- src/bin/psql/describe.c    22 Nov 2005 18:17:29 -0000    1.130
+++ src/bin/psql/describe.c    22 Jan 2006 16:41:15 -0000
@@ -360,6 +360,12 @@
     appendPQExpBuffer(&buf,
             ",\n       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
                       _("Encoding"));
+    appendPQExpBuffer(&buf,
+        ",\n       d.datcollate as \"%s\"",
+                     _("LC_COLLATE"));
+    appendPQExpBuffer(&buf,
+        ",\n       d.datctype as \"%s\"",
+                     _("LC_CTYPE"));
     if (verbose)
         appendPQExpBuffer(&buf,
                           ",\n       pg_catalog.obj_description(d.oid, 'pg_database') as \"%s\"",
Index: src/bin/scripts/createdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createdb.c,v
retrieving revision 1.15
diff -u -r1.15 createdb.c
--- src/bin/scripts/createdb.c    21 Jun 2005 04:02:33 -0000    1.15
+++ src/bin/scripts/createdb.c    22 Jan 2006 16:41:15 -0000
@@ -34,6 +34,8 @@
         {"tablespace", required_argument, NULL, 'D'},
         {"template", required_argument, NULL, 'T'},
         {"encoding", required_argument, NULL, 'E'},
+        {"lc-collate", required_argument, NULL, 1},
+        {"lc-ctype", required_argument, NULL, 2},
         {NULL, 0, NULL, 0}
     };

@@ -53,6 +55,8 @@
     char       *tablespace = NULL;
     char       *template = NULL;
     char       *encoding = NULL;
+    char       *lc_collate = NULL;
+    char       *lc_ctype = NULL;

     PQExpBufferData sql;

@@ -98,6 +102,12 @@
             case 'E':
                 encoding = optarg;
                 break;
+            case 1:
+                lc_collate = optarg;
+                break;
+            case 2:
+                lc_ctype = optarg;
+                break;
             default:
                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                 exit(1);
@@ -155,7 +165,12 @@
         appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
     if (template)
         appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
+    if (lc_collate)
+        appendPQExpBuffer(&sql, " LCCOLLATE %s", fmtId(lc_collate));
+    if (lc_ctype)
+        appendPQExpBuffer(&sql, " LCCTYPE %s", fmtId(lc_ctype));
     appendPQExpBuffer(&sql, ";\n");
+

     conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
                            host, port, username, password, progname);
@@ -219,19 +234,20 @@
     printf(_("Usage:\n"));
     printf(_("  %s [OPTION]... [DBNAME] [DESCRIPTION]\n"), progname);
     printf(_("\nOptions:\n"));
-    printf(_("  -D, --tablespace=TABLESPACE  default tablespace for the database\n"));
-    printf(_("  -E, --encoding=ENCODING      encoding for the database\n"));
-    printf(_("  -O, --owner=OWNER            database user to own the new database\n"));
-    printf(_("  -T, --template=TEMPLATE      template database to copy\n"));
-    printf(_("  -e, --echo                   show the commands being sent to the server\n"));
-    printf(_("  -q, --quiet                  don't write any messages\n"));
-    printf(_("  --help                       show this help, then exit\n"));
-    printf(_("  --version                    output version information, then exit\n"));
+    printf(_("  -D, --tablespace=TABLESPACE      default tablespace for the database\n"));
+    printf(_("  -E, --encoding=ENCODING          encoding for the database\n"));
+    printf(_("  --lc-collate, --lc-ctype=LOCALE    initialize database with given locale\n"));
+    printf(_("  -O, --owner=OWNER                database user to own the new database\n"));
+    printf(_("  -T, --template=TEMPLATE          template database to copy\n"));
+    printf(_("  -e, --echo                       show the commands being sent to the server\n"));
+    printf(_("  -q, --quiet                      don't write any messages\n"));
+    printf(_("  --help                           show this help, then exit\n"));
+    printf(_("  --version                        output version information, then exit\n"));
     printf(_("\nConnection options:\n"));
-    printf(_("  -h, --host=HOSTNAME          database server host or socket directory\n"));
-    printf(_("  -p, --port=PORT              database server port\n"));
-    printf(_("  -U, --username=USERNAME      user name to connect as\n"));
-    printf(_("  -W, --password               prompt for password\n"));
+    printf(_("  -h, --host=HOSTNAME              database server host or socket directory\n"));
+    printf(_("  -p, --port=PORT                  database server port\n"));
+    printf(_("  -U, --username=USERNAME          user name to connect as\n"));
+    printf(_("  -W, --password                   prompt for password\n"));
     printf(_("\nBy default, a database with the same name as the current user is created.\n"));
     printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
Index: src/include/catalog/pg_control.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_control.h,v
retrieving revision 1.26
diff -u -r1.26 pg_control.h
--- src/include/catalog/pg_control.h    22 Nov 2005 18:17:30 -0000    1.26
+++ src/include/catalog/pg_control.h    22 Jan 2006 16:41:15 -0000
@@ -137,11 +137,6 @@
     /* flag indicating internal format of timestamp, interval, time */
     uint32        enableIntTimes; /* int64 storage enabled? */

-    /* active locales */
-    uint32        localeBuflen;
-    char        lc_collate[LOCALE_NAME_BUFLEN];
-    char        lc_ctype[LOCALE_NAME_BUFLEN];
-
     /* CRC of all above ... MUST BE LAST! */
     pg_crc32    crc;
 } ControlFileData;
Index: src/include/catalog/pg_database.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_database.h,v
retrieving revision 1.38
diff -u -r1.38 pg_database.h
--- src/include/catalog/pg_database.h    15 Oct 2005 02:49:42 -0000    1.38
+++ src/include/catalog/pg_database.h    22 Jan 2006 16:41:16 -0000
@@ -38,6 +38,8 @@
     NameData    datname;        /* database name */
     Oid            datdba;            /* owner of database */
     int4        encoding;        /* character encoding */
+    NameData    datcollate;        /* locale LC_COLLATE */
+    NameData    datctype;        /* locale LC_CTYPE */
     bool        datistemplate;    /* allowed as CREATE DATABASE template? */
     bool        datallowconn;    /* new connections allowed? */
     int4        datconnlimit;    /* max connections allowed (-1=no limit) */
@@ -60,21 +62,23 @@
  *        compiler constants for pg_database
  * ----------------
  */
-#define Natts_pg_database                12
+#define Natts_pg_database                14
 #define Anum_pg_database_datname        1
 #define Anum_pg_database_datdba            2
 #define Anum_pg_database_encoding        3
-#define Anum_pg_database_datistemplate    4
-#define Anum_pg_database_datallowconn    5
-#define Anum_pg_database_datconnlimit    6
-#define Anum_pg_database_datlastsysoid    7
-#define Anum_pg_database_datvacuumxid    8
-#define Anum_pg_database_datfrozenxid    9
-#define Anum_pg_database_dattablespace    10
-#define Anum_pg_database_datconfig        11
-#define Anum_pg_database_datacl            12
+#define Anum_pg_database_datcollate    4
+#define Anum_pg_database_datctype    5
+#define Anum_pg_database_datistemplate    6
+#define Anum_pg_database_datallowconn    7
+#define Anum_pg_database_datconnlimit    8
+#define Anum_pg_database_datlastsysoid    9
+#define Anum_pg_database_datvacuumxid    10
+#define Anum_pg_database_datfrozenxid    11
+#define Anum_pg_database_dattablespace    12
+#define Anum_pg_database_datconfig        13
+#define Anum_pg_database_datacl            14

-DATA(insert OID = 1 (  template1 PGUID ENCODING t t -1 0 0 0 1663 _null_ _null_ ));
+DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_CTYPE" "LC_COLLATE" t t -1 0 0 0 1663 _null_ _null_ ));
 DESCR("Default template database");
 #define TemplateDbOid            1

Index: src/include/utils/pg_locale.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/pg_locale.h,v
retrieving revision 1.21
diff -u -r1.21 pg_locale.h
--- src/include/utils/pg_locale.h    28 Dec 2005 23:22:51 -0000    1.21
+++ src/include/utils/pg_locale.h    22 Jan 2006 16:41:16 -0000
@@ -22,6 +22,10 @@
 extern char *locale_numeric;
 extern char *locale_time;

+extern const char *locale_collate_assign(const char *value,
+                       bool doit, GucSource source);
+extern const char *locale_ctype_assign(const char *value,
+                       bool doit, GucSource source);
 extern const char *locale_messages_assign(const char *value,
                        bool doit, GucSource source);
 extern const char *locale_monetary_assign(const char *value,

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: Allow an alias for the target table in UPDATE/DELETE
Next
From: Tom Lane
Date:
Subject: Re: Allow an alias for the target table in UPDATE/DELETE