diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 5a021db33b7..4635cf2bb5e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13269,7 +13269,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
- format_type(type_oid [, typemod> [, collation_oid> ]])
+ format_type(type_oid, typemod>)
text
get SQL name of a data type
@@ -13410,9 +13410,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
format_type 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 COLLATE> clause
- followed by a formatted collation name is appended.
+ for the type modifier if no specific modifier is known.
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 3f7d7d913ae..325d4523e6b 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -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';
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index f85e0bbd00c..b56bb74bdc6 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -18,7 +18,6 @@
#include
#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))
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ce24d6101d1..acd251415de 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -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
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 12b22bc256c..472760edf1b 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -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
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index dfbdcadd145..08845173311 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -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);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 94b7a6bf928..113ecb18469 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -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);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e21ee0a8354..22a0b89b442 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201103061
+#define CATALOG_VERSION_NO 201103101
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0533e5a6866..cff64ba6b02 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -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_ ));