#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"
#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,...)
{
Oid type_oid;
int32 typemod;
- Oid collation_oid;
char *result;
/* Since this function is not strict, we must test for null 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));
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);
}
/*
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;
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;
}
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))
int i_attalign;
int i_attislocal;
int i_attoptions;
+ int i_attcollation;
PGresult *res;
int ntups;
bool hasdefaults;
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 "
"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 "
"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 "
"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 "
"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 "
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 *));
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));
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;
"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",
char *typnotnull;
char *typdefn;
char *typdefault;
+ Oid typcollation;
bool typdefault_is_literal = false;
/* Set proper schema search path so type references list correctly */
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);
}
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);
}
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);
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");
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);