Revert addition of third argument to format_type().
authorTom Lane <[email protected]>
Thu, 10 Mar 2011 22:30:18 +0000 (17:30 -0500)
committerTom Lane <[email protected]>
Thu, 10 Mar 2011 22:30:46 +0000 (17:30 -0500)
Including collation in the behavior of that function promotes a world view
we do not want.  Moreover, it was producing the wrong behavior for pg_dump
anyway: what we want is to dump a COLLATE clause on attributes whose
attcollation is different from the underlying type, and likewise for
domains, and the function cannot do that for us.  Doing it the hard way
in pg_dump is a bit more tedious but produces more correct output.

In passing, fix initdb so that the initial entry in pg_collation is
properly pinned.  It was droppable before :-(

doc/src/sgml/func.sgml
src/backend/catalog/system_views.sql
src/backend/utils/adt/format_type.c
src/bin/initdb/initdb.c
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h

index 5a021db33b747eaf2dd0c4faa159029acc7e46d1..4635cf2bb5e89e02d357450229e625b7a3fa33f3 100644 (file)
@@ -13269,7 +13269,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
 
      <tbody>
       <row>
-       <entry><literal><function>format_type(<parameter>type_oid</parameter> [, <parameter>typemod</> [, <parameter>collation_oid</> ]])</function></literal></entry>
+       <entry><literal><function>format_type(<parameter>type_oid</parameter>, <parameter>typemod</>)</function></literal></entry>
        <entry><type>text</type></entry>
        <entry>get SQL name of a data type</entry>
       </row>
@@ -13410,9 +13410,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
   <para>
    <function>format_type</function> returns the SQL name of a data type that
    is identified by its type OID and possibly a type modifier.  Pass NULL
-   for the type modifier or omit the argument if no specific modifier is known.
-   If a collation is given as third argument, a <literal>COLLATE</> clause
-   followed by a formatted collation name is appended.
+   for the type modifier if no specific modifier is known.
   </para>
 
   <para>
index 3f7d7d913aef1e40998b2de6711451b9a8161f8d..325d4523e6b7d6053fadd9ba0ec5a34363deed44 100644 (file)
@@ -693,10 +693,6 @@ COMMENT ON FUNCTION ts_debug(text) IS
 -- to get filled in.)
 --
 
-CREATE OR REPLACE FUNCTION
-  format_type(oid, int DEFAULT NULL, oid DEFAULT NULL)
-  RETURNS text STABLE LANGUAGE internal AS 'format_type';
-
 CREATE OR REPLACE FUNCTION
   pg_start_backup(label text, fast boolean DEFAULT false)
   RETURNS text STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup';
index f85e0bbd00ca7bd9c4992cfbc8379174e1939a75..b56bb74bdc6db437f8155ba10ca5e5360bb23ff4 100644 (file)
@@ -18,7 +18,6 @@
 #include <ctype.h>
 
 #include "catalog/namespace.h"
-#include "catalog/pg_collation.h"
 #include "catalog/pg_type.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -29,8 +28,7 @@
 #define MAX_INT32_LEN 11
 
 static char *format_type_internal(Oid type_oid, int32 typemod,
-                    bool typemod_given, bool allow_invalid,
-                                 Oid collation_oid);
+                    bool typemod_given, bool allow_invalid);
 static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
 static char *
 psnprintf(size_t len, const char *fmt,...)
@@ -69,7 +67,6 @@ format_type(PG_FUNCTION_ARGS)
 {
    Oid         type_oid;
    int32       typemod;
-   Oid         collation_oid;
    char       *result;
 
    /* Since this function is not strict, we must test for null args */
@@ -77,14 +74,13 @@ format_type(PG_FUNCTION_ARGS)
        PG_RETURN_NULL();
 
    type_oid = PG_GETARG_OID(0);
-   collation_oid = PG_ARGISNULL(2) ? InvalidOid : PG_GETARG_OID(2);
 
    if (PG_ARGISNULL(1))
-       result = format_type_internal(type_oid, -1, false, true, collation_oid);
+       result = format_type_internal(type_oid, -1, false, true);
    else
    {
        typemod = PG_GETARG_INT32(1);
-       result = format_type_internal(type_oid, typemod, true, true, collation_oid);
+       result = format_type_internal(type_oid, typemod, true, true);
    }
 
    PG_RETURN_TEXT_P(cstring_to_text(result));
@@ -99,7 +95,7 @@ format_type(PG_FUNCTION_ARGS)
 char *
 format_type_be(Oid type_oid)
 {
-   return format_type_internal(type_oid, -1, false, false, InvalidOid);
+   return format_type_internal(type_oid, -1, false, false);
 }
 
 /*
@@ -108,15 +104,14 @@ format_type_be(Oid type_oid)
 char *
 format_type_with_typemod(Oid type_oid, int32 typemod)
 {
-   return format_type_internal(type_oid, typemod, true, false, InvalidOid);
+   return format_type_internal(type_oid, typemod, true, false);
 }
 
 
 
 static char *
 format_type_internal(Oid type_oid, int32 typemod,
-                    bool typemod_given, bool allow_invalid,
-                    Oid collation_oid)
+                    bool typemod_given, bool allow_invalid)
 {
    bool        with_typemod = typemod_given && (typemod >= 0);
    HeapTuple   tuple;
@@ -322,12 +317,6 @@ format_type_internal(Oid type_oid, int32 typemod,
 
    ReleaseSysCache(tuple);
 
-   if (collation_oid && collation_oid != DEFAULT_COLLATION_OID)
-   {
-       char *collstr = generate_collation_name(collation_oid);
-       buf = psnprintf(strlen(buf) + 10 + strlen(collstr), "%s COLLATE %s", buf, collstr);
-   }
-
    return buf;
 }
 
@@ -431,7 +420,7 @@ oidvectortypes(PG_FUNCTION_ARGS)
    for (num = 0; num < numargs; num++)
    {
        char       *typename = format_type_internal(oidArray->values[num], -1,
-                                                   false, true, InvalidOid);
+                                                   false, true);
        size_t      slen = strlen(typename);
 
        if (left < (slen + 2))
index ce24d6101d13832e876e002b2d775e11fa94b60b..acd251415de54d08bcba68e16af72c6a4b00f427 100644 (file)
@@ -1388,6 +1388,8 @@ setup_depend(void)
        " FROM pg_ts_template;\n",
        "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
        " FROM pg_ts_config;\n",
+       "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+       " FROM pg_collation;\n",
        "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
        " FROM pg_authid;\n",
        NULL
index 12b22bc256c587266b7fb07b8fe1a483f99846d6..472760edf1b097a759827b5033d952fca8c9900e 100644 (file)
@@ -54,10 +54,12 @@ static int  numTables;
 static int numTypes;
 static int numFuncs;
 static int numOperators;
+static int numCollations;
 static DumpableObject **tblinfoindex;
 static DumpableObject **typinfoindex;
 static DumpableObject **funinfoindex;
 static DumpableObject **oprinfoindex;
+static DumpableObject **collinfoindex;
 
 
 static void flagInhTables(TableInfo *tbinfo, int numTables,
@@ -105,7 +107,6 @@ getSchemaData(int *numTablesPtr)
    int         numCasts;
    int         numOpclasses;
    int         numOpfamilies;
-   int         numCollations;
    int         numConversions;
    int         numTSParsers;
    int         numTSTemplates;
@@ -187,6 +188,7 @@ getSchemaData(int *numTablesPtr)
    if (g_verbose)
        write_msg(NULL, "reading user-defined collations\n");
    collinfo = getCollations(&numCollations);
+   collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
 
    if (g_verbose)
        write_msg(NULL, "reading user-defined conversions\n");
@@ -784,6 +786,17 @@ findOprByOid(Oid oid)
    return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
 }
 
+/*
+ * findCollationByOid
+ *   finds the entry (in collinfo) of the collation with the given oid
+ *   returns NULL if not found
+ */
+CollInfo *
+findCollationByOid(Oid oid)
+{
+   return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
+}
+
 
 /*
  * findParentsByOid
index dfbdcadd1453f72815f41c5e91a92ee3a2693afc..08845173311bf1ab460e49c69485d668a4eee9b2 100644 (file)
@@ -5502,6 +5502,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
    int         i_attalign;
    int         i_attislocal;
    int         i_attoptions;
+   int         i_attcollation;
    PGresult   *res;
    int         ntups;
    bool        hasdefaults;
@@ -5541,13 +5542,20 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
        if (g_fout->remoteVersion >= 90100)
        {
-           /* attcollation is new in 9.1 */
+           /*
+            * attcollation is new in 9.1.  Since we only want to dump
+            * COLLATE clauses for attributes whose collation is different
+            * from their type's default, we use a CASE here to suppress
+            * uninteresting attcollations cheaply.
+            */
            appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
                              "a.attstattarget, a.attstorage, t.typstorage, "
                              "a.attnotnull, a.atthasdef, a.attisdropped, "
                              "a.attlen, a.attalign, a.attislocal, "
-                 "pg_catalog.format_type(t.oid,a.atttypmod,a.attcollation) AS atttypname, "
-                          "array_to_string(attoptions, ', ') AS attoptions "
+                 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
+                         "array_to_string(a.attoptions, ', ') AS attoptions, "
+                             "CASE WHEN a.attcollation <> t.typcollation "
+                             "THEN a.attcollation ELSE 0 END AS attcollation "
             "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
                              "ON a.atttypid = t.oid "
                              "WHERE a.attrelid = '%u'::pg_catalog.oid "
@@ -5563,7 +5571,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                              "a.attnotnull, a.atthasdef, a.attisdropped, "
                              "a.attlen, a.attalign, a.attislocal, "
                  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                          "array_to_string(attoptions, ', ') AS attoptions "
+                         "array_to_string(a.attoptions, ', ') AS attoptions, "
+                             "0 AS attcollation "
             "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
                              "ON a.atttypid = t.oid "
                              "WHERE a.attrelid = '%u'::pg_catalog.oid "
@@ -5579,7 +5588,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                              "a.attnotnull, a.atthasdef, a.attisdropped, "
                              "a.attlen, a.attalign, a.attislocal, "
                  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                             "'' AS attoptions "
+                             "'' AS attoptions, 0 AS attcollation "
             "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
                              "ON a.atttypid = t.oid "
                              "WHERE a.attrelid = '%u'::pg_catalog.oid "
@@ -5600,7 +5609,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                              "false AS attisdropped, a.attlen, "
                              "a.attalign, false AS attislocal, "
                              "format_type(t.oid,a.atttypmod) AS atttypname, "
-                             "'' AS attoptions "
+                             "'' AS attoptions, 0 AS attcollation "
                              "FROM pg_attribute a LEFT JOIN pg_type t "
                              "ON a.atttypid = t.oid "
                              "WHERE a.attrelid = '%u'::oid "
@@ -5618,7 +5627,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                              "attlen, attalign, "
                              "false AS attislocal, "
                              "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
-                             "'' AS attoptions "
+                             "'' AS attoptions, 0 AS attcollation "
                              "FROM pg_attribute a "
                              "WHERE attrelid = '%u'::oid "
                              "AND attnum > 0::int2 "
@@ -5645,6 +5654,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
        i_attalign = PQfnumber(res, "attalign");
        i_attislocal = PQfnumber(res, "attislocal");
        i_attoptions = PQfnumber(res, "attoptions");
+       i_attcollation = PQfnumber(res, "attcollation");
 
        tbinfo->numatts = ntups;
        tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
@@ -5660,6 +5670,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
        tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
        tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
        tbinfo->attoptions = (char **) malloc(ntups * sizeof(char *));
+       tbinfo->attcollation = (Oid *) malloc(ntups * sizeof(Oid));
        tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
        tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
        tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
@@ -5685,6 +5696,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
            tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
            tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
            tbinfo->attoptions[j] = strdup(PQgetvalue(res, j, i_attoptions));
+           tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
            tbinfo->attrdefs[j] = NULL; /* fix below */
            if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
                hasdefaults = true;
@@ -7359,7 +7371,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
                          "typanalyze::pg_catalog.oid AS typanalyzeoid, "
                          "typcategory, typispreferred, "
                          "typdelim, typbyval, typalign, typstorage, "
-                         "(typcollation = (SELECT oid FROM pg_catalog.pg_collation WHERE collname = 'default')) AS typcollatable, "
+                         "(typcollation <> 0) AS typcollatable, "
                          "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
                          "FROM pg_catalog.pg_type "
                          "WHERE oid = '%u'::pg_catalog.oid",
@@ -7736,6 +7748,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
    char       *typnotnull;
    char       *typdefn;
    char       *typdefault;
+   Oid         typcollation;
    bool        typdefault_is_literal = false;
 
    /* Set proper schema search path so type references list correctly */
@@ -7745,11 +7758,14 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
    if (g_fout->remoteVersion >= 90100)
    {
        /* typcollation is new in 9.1 */
-       appendPQExpBuffer(query, "SELECT typnotnull, "
-                         "pg_catalog.format_type(typbasetype, typtypmod, typcollation) AS typdefn, "
-                         "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
-                         "typdefault "
+       appendPQExpBuffer(query, "SELECT t.typnotnull, "
+                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
+                         "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
+                         "t.typdefault, "
+                         "CASE WHEN t.typcollation <> u.typcollation "
+                         "THEN t.typcollation ELSE 0 END AS typcollation "
                          "FROM pg_catalog.pg_type t "
+                         "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
                          "WHERE t.oid = '%u'::pg_catalog.oid",
                          tyinfo->dobj.catId.oid);
    }
@@ -7759,7 +7775,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
        appendPQExpBuffer(query, "SELECT typnotnull, "
                          "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
                          "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
-                         "typdefault "
+                         "typdefault, 0 AS typcollation "
                          "FROM pg_catalog.pg_type "
                          "WHERE oid = '%u'::pg_catalog.oid",
                          tyinfo->dobj.catId.oid);
@@ -7790,6 +7806,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
    }
    else
        typdefault = NULL;
+   typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
 
    if (binary_upgrade)
        binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
@@ -7799,6 +7816,22 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
                      fmtId(tyinfo->dobj.name),
                      typdefn);
 
+   /* Print collation only if different from base type's collation */
+   if (OidIsValid(typcollation))
+   {
+       CollInfo *coll;
+
+       coll = findCollationByOid(typcollation);
+       if (coll)
+       {
+           /* always schema-qualify, don't try to be smart */
+           appendPQExpBuffer(q, " COLLATE %s.",
+                             fmtId(coll->dobj.namespace->dobj.name));
+           appendPQExpBuffer(q, "%s",
+                             fmtId(coll->dobj.name));
+       }
+   }
+
    if (typnotnull[0] == 't')
        appendPQExpBuffer(q, " NOT NULL");
 
@@ -11966,6 +11999,22 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                                   tbinfo->atttypmod[j]));
                }
 
+               /* Add collation if not default for the type */
+               if (OidIsValid(tbinfo->attcollation[j]))
+               {
+                   CollInfo *coll;
+
+                   coll = findCollationByOid(tbinfo->attcollation[j]);
+                   if (coll)
+                   {
+                       /* always schema-qualify, don't try to be smart */
+                       appendPQExpBuffer(q, " COLLATE %s.",
+                                         fmtId(coll->dobj.namespace->dobj.name));
+                       appendPQExpBuffer(q, "%s",
+                                         fmtId(coll->dobj.name));
+                   }
+               }
+
                if (has_default)
                    appendPQExpBuffer(q, " DEFAULT %s",
                                      tbinfo->attrdefs[j]->adef_expr);
index 94b7a6bf928a343d02478f48d09d754c9382db6f..113ecb184693fd941d9a663390ff6e17999ff6ff 100644 (file)
@@ -272,6 +272,7 @@ typedef struct _tableInfo
    char       *attalign;       /* attribute align, used by binary_upgrade */
    bool       *attislocal;     /* true if attr has local definition */
    char      **attoptions;     /* per-attribute options */
+   Oid        *attcollation;   /* per-attribute collation selection */
 
    /*
     * Note: we need to store per-attribute notnull, default, and constraint
@@ -510,6 +511,7 @@ extern TableInfo *findTableByOid(Oid oid);
 extern TypeInfo *findTypeByOid(Oid oid);
 extern FuncInfo *findFuncByOid(Oid oid);
 extern OprInfo *findOprByOid(Oid oid);
+extern CollInfo *findCollationByOid(Oid oid);
 
 extern void simple_oid_list_append(SimpleOidList *list, Oid val);
 extern void simple_string_list_append(SimpleStringList *list, const char *val);
index e21ee0a8354736ce2a07c91fc771aed343f11a13..22a0b89b44287d155de18bea4c76899b70f51a5c 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201103061
+#define CATALOG_VERSION_NO 201103101
 
 #endif
index 0533e5a6866dbf093bf2fe118bc024dfdc4f9b21..cff64ba6b0239ce2932fe375432018f05769829c 100644 (file)
@@ -1100,8 +1100,8 @@ DATA(insert OID = 1078 (  bpcharcmp          PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23
 DESCR("less-equal-greater");
 DATA(insert OID = 1080 (  hashbpchar      PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "1042" _null_ _null_ _null_ _null_   hashbpchar _null_ _null_ _null_ ));
 DESCR("hash");
-DATA(insert OID = 1081 (  format_type     PGNSP PGUID 12 1 0 0 f f f f f s 3 0 25 "26 23 26" _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ ));
-DESCR("format a type OID, atttypmod, and collation OID to canonical SQL");
+DATA(insert OID = 1081 (  format_type     PGNSP PGUID 12 1 0 0 f f f f f s 2 0 25 "26 23" _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ ));
+DESCR("format a type oid and atttypmod to canonical SQL");
 DATA(insert OID = 1084 (  date_in         PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1082 "2275" _null_ _null_ _null_ _null_ date_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 1085 (  date_out        PGNSP PGUID 12 1 0 0 f f f t f s 1 0 2275 "1082" _null_ _null_ _null_ _null_ date_out _null_ _null_ _null_ ));