OSDN Git Service

Revert addition of third argument to format_type().
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Mar 2011 22:30:18 +0000 (17:30 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
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 5a021db..4635cf2 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 3f7d7d9..325d452 100644 (file)
@@ -694,9 +694,5 @@ COMMENT ON FUNCTION ts_debug(text) IS
 --
 
 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 f85e0bb..b56bb74 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 ce24d61..acd2514 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 12b22bc..472760e 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 dfbdcad..0884517 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 94b7a6b..113ecb1 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 e21ee0a..22a0b89 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201103061
+#define CATALOG_VERSION_NO     201103101
 
 #endif
index 0533e5a..cff64ba 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_ ));