diff options
| author | Peter Eisentraut | 2011-02-12 13:54:13 +0000 |
|---|---|---|
| committer | Peter Eisentraut | 2011-02-12 13:55:18 +0000 |
| commit | b313bca0afce3ab9dab0a77c64c0982835854b9a (patch) | |
| tree | 862203ffd9adbc62684bec05fa32b2de4713e6b9 /src/backend/commands | |
| parent | d31e2a495b6f2127afc31b4da2e5f4e89aa2cdfe (diff) | |
DDL support for collations
- collowner field
- CREATE COLLATION
- ALTER COLLATION
- DROP COLLATION
- COMMENT ON COLLATION
- integration with extensions
- pg_dump support for the above
- dependency management
- psql tab completion
- psql \dO command
Diffstat (limited to 'src/backend/commands')
| -rw-r--r-- | src/backend/commands/Makefile | 2 | ||||
| -rw-r--r-- | src/backend/commands/alter.c | 17 | ||||
| -rw-r--r-- | src/backend/commands/collationcmds.c | 401 | ||||
| -rw-r--r-- | src/backend/commands/comment.c | 5 | ||||
| -rw-r--r-- | src/backend/commands/dbcommands.c | 116 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 26 | ||||
| -rw-r--r-- | src/backend/commands/typecmds.c | 1 |
7 files changed, 504 insertions, 64 deletions
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 0aadbc56adb..81fd6581f32 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -13,7 +13,7 @@ top_builddir = ../../.. include $(top_builddir)/src/Makefile.global OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ - constraint.o conversioncmds.o copy.o \ + collationcmds.o constraint.o conversioncmds.o copy.o \ dbcommands.o define.o discard.o explain.o extension.o \ foreigncmds.o functioncmds.o \ indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \ diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 2c9340accf1..99fdd7dba30 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -20,6 +20,7 @@ #include "catalog/pg_largeobject.h" #include "catalog/pg_namespace.h" #include "commands/alter.h" +#include "commands/collationcmds.h" #include "commands/conversioncmds.h" #include "commands/dbcommands.h" #include "commands/defrem.h" @@ -53,6 +54,10 @@ ExecRenameStmt(RenameStmt *stmt) RenameAggregate(stmt->object, stmt->objarg, stmt->newname); break; + case OBJECT_COLLATION: + RenameCollation(stmt->object, stmt->newname); + break; + case OBJECT_CONVERSION: RenameConversion(stmt->object, stmt->newname); break; @@ -185,6 +190,10 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt) stmt->newschema); break; + case OBJECT_COLLATION: + AlterCollationNamespace(stmt->object, stmt->newschema); + break; + case OBJECT_CONVERSION: AlterConversionNamespace(stmt->object, stmt->newschema); break; @@ -302,6 +311,10 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid) oldNspOid = AlterTypeNamespace_oid(objid, nspOid); break; + case OCLASS_COLLATION: + oldNspOid = AlterCollationNamespace_oid(objid, nspOid); + break; + case OCLASS_CONVERSION: oldNspOid = AlterConversionNamespace_oid(objid, nspOid); break; @@ -478,6 +491,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) AlterAggregateOwner(stmt->object, stmt->objarg, newowner); break; + case OBJECT_COLLATION: + AlterCollationOwner(stmt->object, newowner); + break; + case OBJECT_CONVERSION: AlterConversionOwner(stmt->object, newowner); break; diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c new file mode 100644 index 00000000000..6db72d919cc --- /dev/null +++ b/src/backend/commands/collationcmds.c @@ -0,0 +1,401 @@ +/*------------------------------------------------------------------------- + * + * collationcmds.c + * collation creation command support code + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/commands/collationcmds.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_collation_fn.h" +#include "commands/alter.h" +#include "commands/collationcmds.h" +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "parser/parse_type.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + +static void AlterCollationOwner_internal(Relation rel, Oid collationOid, + Oid newOwnerId); + +/* + * CREATE COLLATION + */ +void +DefineCollation(List *names, List *parameters) +{ + char *collName; + Oid collNamespace; + AclResult aclresult; + ListCell *pl; + DefElem *fromEl = NULL; + DefElem *localeEl = NULL; + DefElem *lccollateEl = NULL; + DefElem *lcctypeEl = NULL; + char *collcollate = NULL; + char *collctype = NULL; + + collNamespace = QualifiedNameGetCreationNamespace(names, &collName); + + aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(collNamespace)); + + foreach(pl, parameters) + { + DefElem *defel = (DefElem *) lfirst(pl); + DefElem **defelp; + + if (pg_strcasecmp(defel->defname, "from") == 0) + defelp = &fromEl; + else if (pg_strcasecmp(defel->defname, "locale") == 0) + defelp = &localeEl; + else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) + defelp = &lccollateEl; + else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) + defelp = &lcctypeEl; + else + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("collation attribute \"%s\" not recognized", + defel->defname))); + break; + } + + *defelp = defel; + } + + if ((localeEl && (lccollateEl || lcctypeEl)) + || (fromEl && list_length(parameters) != 1)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + if (fromEl) + { + Oid collid; + HeapTuple tp; + + collid = LookupCollation(NULL, defGetQualifiedName(fromEl), -1); + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for collation %u", collid); + + collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate)); + collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype)); + + ReleaseSysCache(tp); + } + + if (localeEl) + { + collcollate = defGetString(localeEl); + collctype = defGetString(localeEl); + } + + if (lccollateEl) + collcollate = defGetString(lccollateEl); + + if (lcctypeEl) + collctype = defGetString(lcctypeEl); + + if (!collcollate) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("parameter \"lc_collate\" parameter must be specified"))); + + if (!collctype) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("parameter \"lc_ctype\" must be specified"))); + + check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype); + + CollationCreate(collName, + collNamespace, + GetUserId(), + GetDatabaseEncoding(), + collcollate, + collctype); +} + +/* + * DROP COLLATION + */ +void +DropCollationsCommand(DropStmt *drop) +{ + ObjectAddresses *objects; + ListCell *cell; + + /* + * First we identify all the collations, then we delete them in a single + * performMultipleDeletions() call. This is to avoid unwanted DROP + * RESTRICT errors if one of the collations depends on another. (Not that + * that is very likely, but we may as well do this consistently.) + */ + objects = new_object_addresses(); + + foreach(cell, drop->objects) + { + List *name = (List *) lfirst(cell); + Oid collationOid; + HeapTuple tuple; + Form_pg_collation coll; + ObjectAddress object; + + collationOid = get_collation_oid(name, drop->missing_ok); + + if (!OidIsValid(collationOid)) + { + ereport(NOTICE, + (errmsg("collation \"%s\" does not exist, skipping", + NameListToString(name)))); + continue; + } + + tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for collation %u", + collationOid); + coll = (Form_pg_collation) GETSTRUCT(tuple); + + /* Permission check: must own collation or its namespace */ + if (!pg_collation_ownercheck(collationOid, GetUserId()) && + !pg_namespace_ownercheck(coll->collnamespace, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, + NameStr(coll->collname)); + + object.classId = CollationRelationId; + object.objectId = collationOid; + object.objectSubId = 0; + + add_exact_object_address(&object, objects); + + ReleaseSysCache(tuple); + } + + performMultipleDeletions(objects, drop->behavior); + + free_object_addresses(objects); +} + +/* + * Rename collation + */ +void +RenameCollation(List *name, const char *newname) +{ + Oid collationOid; + Oid namespaceOid; + HeapTuple tup; + Relation rel; + AclResult aclresult; + + rel = heap_open(CollationRelationId, RowExclusiveLock); + + collationOid = get_collation_oid(name, false); + + tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collationOid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for collation %u", collationOid); + + namespaceOid = ((Form_pg_collation) GETSTRUCT(tup))->collnamespace; + + /* make sure the new name doesn't exist */ + if (SearchSysCacheExists3(COLLNAMEENCNSP, + CStringGetDatum(newname), + Int32GetDatum(GetDatabaseEncoding()), + ObjectIdGetDatum(namespaceOid))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("collation \"%s\" for current database encoding \"%s\" already exists in schema \"%s\"", + newname, + GetDatabaseEncodingName(), + get_namespace_name(namespaceOid)))); + + /* must be owner */ + if (!pg_collation_ownercheck(collationOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, + NameListToString(name)); + + /* must have CREATE privilege on namespace */ + aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + + /* rename */ + namestrcpy(&(((Form_pg_collation) GETSTRUCT(tup))->collname), newname); + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + heap_close(rel, NoLock); + heap_freetuple(tup); +} + +/* + * Change collation owner, by name + */ +void +AlterCollationOwner(List *name, Oid newOwnerId) +{ + Oid collationOid; + Relation rel; + + rel = heap_open(CollationRelationId, RowExclusiveLock); + + collationOid = get_collation_oid(name, false); + + AlterCollationOwner_internal(rel, collationOid, newOwnerId); + + heap_close(rel, NoLock); +} + +/* + * Change collation owner, by oid + */ +void +AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId) +{ + Relation rel; + + rel = heap_open(CollationRelationId, RowExclusiveLock); + + AlterCollationOwner_internal(rel, collationOid, newOwnerId); + + heap_close(rel, NoLock); +} + +/* + * AlterCollationOwner_internal + * + * Internal routine for changing the owner. rel must be pg_collation, already + * open and suitably locked; it will not be closed. + */ +static void +AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid newOwnerId) +{ + Form_pg_collation collForm; + HeapTuple tup; + + Assert(RelationGetRelid(rel) == CollationRelationId); + + tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collationOid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for collation %u", collationOid); + + collForm = (Form_pg_collation) GETSTRUCT(tup); + + /* + * If the new owner is the same as the existing owner, consider the + * command to have succeeded. This is for dump restoration purposes. + */ + if (collForm->collowner != newOwnerId) + { + AclResult aclresult; + + /* Superusers can always do it */ + if (!superuser()) + { + /* Otherwise, must be owner of the existing object */ + if (!pg_collation_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, + NameStr(collForm->collname)); + + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(), newOwnerId); + + /* New owner must have CREATE privilege on namespace */ + aclresult = pg_namespace_aclcheck(collForm->collnamespace, + newOwnerId, + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(collForm->collnamespace)); + } + + /* + * Modify the owner --- okay to scribble on tup because it's a copy + */ + collForm->collowner = newOwnerId; + + simple_heap_update(rel, &tup->t_self, tup); + + CatalogUpdateIndexes(rel, tup); + + /* Update owner dependency reference */ + changeDependencyOnOwner(CollationRelationId, collationOid, + newOwnerId); + } + + heap_freetuple(tup); +} + +/* + * Execute ALTER COLLATION SET SCHEMA + */ +void +AlterCollationNamespace(List *name, const char *newschema) +{ + Oid collOid, nspOid; + Relation rel; + + rel = heap_open(CollationRelationId, RowExclusiveLock); + + collOid = get_collation_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, COLLOID, -1, + collOid, nspOid, + Anum_pg_collation_collname, + Anum_pg_collation_collnamespace, + Anum_pg_collation_collowner, + ACL_KIND_COLLATION); + + heap_close(rel, NoLock); +} + +/* + * Change collation schema, by oid + */ +Oid +AlterCollationNamespace_oid(Oid collOid, Oid newNspOid) +{ + Oid oldNspOid; + Relation rel; + + rel = heap_open(CollationRelationId, RowExclusiveLock); + + oldNspOid = AlterObjectNamespace(rel, COLLOID, -1, + collOid, newNspOid, + Anum_pg_collation_collname, + Anum_pg_collation_collnamespace, + Anum_pg_collation_collowner, + ACL_KIND_COLLATION); + + heap_close(rel, RowExclusiveLock); + + return oldNspOid; +} diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index faef256b1d8..a0a561c144d 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -133,6 +133,11 @@ CommentObject(CommentStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, strVal(linitial(stmt->objname))); break; + case OBJECT_COLLATION: + if (!pg_collation_ownercheck(address.objectId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, + NameListToString(stmt->objname)); + break; case OBJECT_CONVERSION: if (!pg_conversion_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index c7e0c6a8778..87d9e545b4f 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -129,8 +129,6 @@ createdb(const CreatedbStmt *stmt) char *dbctype = NULL; int encoding = -1; int dbconnlimit = -1; - int ctype_encoding; - int collate_encoding; int notherbackends; int npreparedxacts; createdb_failure_params fparms; @@ -334,60 +332,7 @@ createdb(const CreatedbStmt *stmt) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("invalid locale name %s", dbctype))); - /* - * Check whether chosen encoding matches chosen locale settings. This - * restriction is necessary because libc's locale-specific code usually - * fails when presented with data in an encoding it's not expecting. We - * allow mismatch in four cases: - * - * 1. locale encoding = SQL_ASCII, which means that the locale is C/POSIX - * which works with any encoding. - * - * 2. locale encoding = -1, which means that we couldn't determine the - * locale's encoding and have to trust the user to get it right. - * - * 3. selected encoding is UTF8 and platform is win32. This is because - * UTF8 is a pseudo codepage that is supported in all locales since it's - * converted to UTF16 before being used. - * - * 4. selected encoding is SQL_ASCII, but only if you're a superuser. This - * is risky but we have historically allowed it --- notably, the - * regression tests require it. - * - * Note: if you change this policy, fix initdb to match. - */ - ctype_encoding = pg_get_encoding_from_locale(dbctype, true); - collate_encoding = pg_get_encoding_from_locale(dbcollate, true); - - if (!(ctype_encoding == encoding || - ctype_encoding == PG_SQL_ASCII || - ctype_encoding == -1 || -#ifdef WIN32 - encoding == PG_UTF8 || -#endif - (encoding == PG_SQL_ASCII && superuser()))) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("encoding %s does not match locale %s", - pg_encoding_to_char(encoding), - dbctype), - errdetail("The chosen LC_CTYPE setting requires encoding %s.", - pg_encoding_to_char(ctype_encoding)))); - - if (!(collate_encoding == encoding || - collate_encoding == PG_SQL_ASCII || - collate_encoding == -1 || -#ifdef WIN32 - encoding == PG_UTF8 || -#endif - (encoding == PG_SQL_ASCII && superuser()))) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("encoding %s does not match locale %s", - pg_encoding_to_char(encoding), - dbcollate), - errdetail("The chosen LC_COLLATE setting requires encoding %s.", - pg_encoding_to_char(collate_encoding)))); + check_encoding_locale_matches(encoding, dbcollate, dbctype); /* * Check that the new encoding and locale settings match the source @@ -710,6 +655,65 @@ createdb(const CreatedbStmt *stmt) PointerGetDatum(&fparms)); } +/* + * Check whether chosen encoding matches chosen locale settings. This + * restriction is necessary because libc's locale-specific code usually + * fails when presented with data in an encoding it's not expecting. We + * allow mismatch in four cases: + * + * 1. locale encoding = SQL_ASCII, which means that the locale is C/POSIX + * which works with any encoding. + * + * 2. locale encoding = -1, which means that we couldn't determine the + * locale's encoding and have to trust the user to get it right. + * + * 3. selected encoding is UTF8 and platform is win32. This is because + * UTF8 is a pseudo codepage that is supported in all locales since it's + * converted to UTF16 before being used. + * + * 4. selected encoding is SQL_ASCII, but only if you're a superuser. This + * is risky but we have historically allowed it --- notably, the + * regression tests require it. + * + * Note: if you change this policy, fix initdb to match. + */ +void +check_encoding_locale_matches(int encoding, const char *collate, const char *ctype) +{ + int ctype_encoding = pg_get_encoding_from_locale(ctype, true); + int collate_encoding = pg_get_encoding_from_locale(collate, true); + + if (!(ctype_encoding == encoding || + ctype_encoding == PG_SQL_ASCII || + ctype_encoding == -1 || +#ifdef WIN32 + encoding == PG_UTF8 || +#endif + (encoding == PG_SQL_ASCII && superuser()))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("encoding %s does not match locale %s", + pg_encoding_to_char(encoding), + ctype), + errdetail("The chosen LC_CTYPE setting requires encoding %s.", + pg_encoding_to_char(ctype_encoding)))); + + if (!(collate_encoding == encoding || + collate_encoding == PG_SQL_ASCII || + collate_encoding == -1 || +#ifdef WIN32 + encoding == PG_UTF8 || +#endif + (encoding == PG_SQL_ASCII && superuser()))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("encoding %s does not match locale %s", + pg_encoding_to_char(encoding), + collate), + errdetail("The chosen LC_COLLATE setting requires encoding %s.", + pg_encoding_to_char(collate_encoding)))); +} + /* Error cleanup callback for createdb */ static void createdb_failure_callback(int code, Datum arg) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1db42d044ac..324d9ff9ea1 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -27,6 +27,7 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/objectaccess.h" +#include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_depend.h" #include "catalog/pg_foreign_table.h" @@ -293,7 +294,7 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu AlterTableCmd *cmd, LOCKMODE lockmode); static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool isOid, LOCKMODE lockmode); -static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid); +static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid); static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode); static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode); @@ -4369,14 +4370,14 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, /* * Add needed dependency entries for the new column. */ - add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid); + add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid, attribute.attcollation); } /* * Install a column's dependency on its datatype. */ static void -add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid) +add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid) { ObjectAddress myself, referenced; @@ -4388,6 +4389,14 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid) referenced.objectId = typid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + if (collid) + { + referenced.classId = CollationRelationId; + referenced.objectId = collid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } } /* @@ -6877,6 +6886,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, case OCLASS_PROC: case OCLASS_TYPE: case OCLASS_CAST: + case OCLASS_COLLATION: case OCLASS_CONVERSION: case OCLASS_LANGUAGE: case OCLASS_LARGEOBJECT: @@ -6918,7 +6928,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, /* * Now scan for dependencies of this column on other things. The only * thing we should find is the dependency on the column datatype, which we - * want to remove. + * want to remove, and possibly an associated collation. */ ScanKeyInit(&key[0], Anum_pg_depend_classid, @@ -6943,8 +6953,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, if (foundDep->deptype != DEPENDENCY_NORMAL) elog(ERROR, "found unexpected dependency type '%c'", foundDep->deptype); - if (foundDep->refclassid != TypeRelationId || - foundDep->refobjid != attTup->atttypid) + if (!(foundDep->refclassid == TypeRelationId && + foundDep->refobjid == attTup->atttypid) && + !(foundDep->refclassid == CollationRelationId && + foundDep->refobjid == attTup->attcollation)) elog(ERROR, "found unexpected dependency for column"); simple_heap_delete(depRel, &depTup->t_self); @@ -6977,7 +6989,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, heap_close(attrelation, RowExclusiveLock); /* Install dependency on new datatype */ - add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype); + add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype, targetcollid); /* * Drop any pg_statistic entry for the column, since it's now wrong type diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index f9da7816b25..be1f1d791fd 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1736,6 +1736,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) InvalidOid, false, /* a domain isn't an implicit array */ typTup->typbasetype, + typTup->typcollation, defaultExpr, true); /* Rebuild is true */ |
