renaming domain constraint

Started by Peter Eisentrautalmost 14 years ago4 messages
#1Peter Eisentraut
peter_e@gmx.net
1 attachment(s)

Here is a patch for being able to rename constraints of domains. It
goes on top of the previously committed patch for renaming table
constraints.

Attachments:

rename-domain-constraint.patchtext/x-patch; charset=UTF-8; name=rename-domain-constraint.patchDownload
diff --git a/doc/src/sgml/ref/alter_domain.sgml b/doc/src/sgml/ref/alter_domain.sgml
index 2511a12..c59975a 100644
--- a/doc/src/sgml/ref/alter_domain.sgml
+++ b/doc/src/sgml/ref/alter_domain.sgml
@@ -32,6 +32,8 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     DROP CONSTRAINT [ IF EXISTS ] <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
+     RENAME CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> TO <replaceable class="PARAMETER">new_constraint_name</replaceable>
+ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     VALIDATE CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
@@ -103,6 +105,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
    </varlistentry>
 
    <varlistentry>
+    <term>RENAME CONSTRAINT</term>
+    <listitem>
+     <para>
+      This form changes the name of a constraint on a domain.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term>VALIDATE CONSTRAINT</term>
     <listitem>
      <para>
@@ -182,7 +193,7 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
       <term><replaceable class="PARAMETER">constraint_name</replaceable></term>
       <listitem>
        <para>
-        Name of an existing constraint to drop.
+        Name of an existing constraint to drop or rename.
        </para>
       </listitem>
      </varlistentry>
@@ -226,6 +237,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
      </varlistentry>
 
      <varlistentry>
+      <term><replaceable class="PARAMETER">new_constraint_name</replaceable></term>
+      <listitem>
+       <para>
+        The new name for the constraint.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="PARAMETER">new_owner</replaceable></term>
       <listitem>
        <para>
@@ -289,6 +309,13 @@ ALTER DOMAIN zipcode DROP CONSTRAINT zipchk;
   </para>
 
   <para>
+   To rename a check constraint on a domain:
+<programlisting>
+ALTER DOMAIN zipcode RENAME CONSTRAINT zipchk TO zip_check;
+</programlisting>
+  </para>
+
+  <para>
    To move the domain into a different schema:
 <programlisting>
 ALTER DOMAIN zipcode SET SCHEMA customers;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index e6e0347..08de88b 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -753,7 +753,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
 				address.objectId =
-					get_constraint_oid(reloid, depname, missing_ok);
+					get_constraint_oid(reloid, InvalidOid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 342cf75..4377207 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -737,17 +737,20 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 
 /*
  * get_constraint_oid
- *		Find a constraint on the specified relation with the specified name.
+ *		Find a constraint on the specified relation or domain with the specified name.
  *		Returns constraint's OID.
  */
 Oid
-get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
+get_constraint_oid(Oid relid, Oid typid, const char *conname, bool missing_ok)
 {
 	Relation	pg_constraint;
 	HeapTuple	tuple;
 	SysScanDesc scan;
 	ScanKeyData skey[1];
 	Oid			conOid = InvalidOid;
+	Oid			indexId;
+
+	AssertArg(!relid || !typid);
 
 	/*
 	 * Fetch the constraint tuple from pg_constraint.  There may be more than
@@ -756,12 +759,24 @@ get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 	 */
 	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
 
-	ScanKeyInit(&skey[0],
-				Anum_pg_constraint_conrelid,
-				BTEqualStrategyNumber, F_OIDEQ,
-				ObjectIdGetDatum(relid));
+	if (relid)
+	{
+		ScanKeyInit(&skey[0],
+					Anum_pg_constraint_conrelid,
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(relid));
+		indexId = ConstraintRelidIndexId;
+	}
+	else
+	{
+		ScanKeyInit(&skey[0],
+					Anum_pg_constraint_contypid,
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(typid));
+		indexId = ConstraintTypidIndexId;
+	}
 
-	scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
+	scan = systable_beginscan(pg_constraint, indexId, true,
 							  SnapshotNow, 1, skey);
 
 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
@@ -771,10 +786,18 @@ get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 		if (strcmp(NameStr(con->conname), conname) == 0)
 		{
 			if (OidIsValid(conOid))
-				ereport(ERROR,
-						(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("table \"%s\" has multiple constraints named \"%s\"",
-						get_rel_name(relid), conname)));
+			{
+				if (relid)
+					ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_OBJECT),
+							 errmsg("table \"%s\" has multiple constraints named \"%s\"",
+									get_rel_name(relid), conname)));
+				else
+					ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_OBJECT),
+							 errmsg("domain \"%s\" has multiple constraints named \"%s\"",
+									format_type_be(typid), conname)));
+			}
 			conOid = HeapTupleGetOid(tuple);
 		}
 	}
@@ -783,10 +806,18 @@ get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 
 	/* If no such constraint exists, complain */
 	if (!OidIsValid(conOid) && !missing_ok)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("constraint \"%s\" for table \"%s\" does not exist",
-						conname, get_rel_name(relid))));
+	{
+		if (relid)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("constraint \"%s\" for table \"%s\" does not exist",
+							conname, get_rel_name(relid))));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("constraint \"%s\" for domain \"%s\" does not exist",
+							conname, format_type_be(typid))));
+	}
 
 	heap_close(pg_constraint, AccessShareLock);
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 9615380..a0a9270 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2333,22 +2333,32 @@ renameatt(RenameStmt *stmt)
  */
 static void
 rename_constraint_internal(Oid myrelid,
+						   Oid mytypid,
 						   const char *oldconname,
 						   const char *newconname,
 						   bool recurse,
 						   bool recursing,
 						   int expected_parents)
 {
-	Relation	targetrelation;
+	Relation	targetrelation = NULL;
 	Oid			constraintOid;
 	HeapTuple   tuple;
 	Form_pg_constraint con;
 
-	targetrelation = relation_open(myrelid, AccessExclusiveLock);
-	/* don't tell it whether we're recursing; we allow changing typed tables here */
-	renameatt_check(myrelid, RelationGetForm(targetrelation), false);
+	AssertArg(!myrelid || !mytypid);
+
+	if (mytypid)
+	{
+		constraintOid = get_constraint_oid(InvalidOid, mytypid, oldconname, false);
+	}
+	else
+	{
+		targetrelation = relation_open(myrelid, AccessExclusiveLock);
+		/* don't tell it whether we're recursing; we allow changing typed tables here */
+		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
 
-	constraintOid = get_constraint_oid(myrelid, oldconname, false);
+		constraintOid = get_constraint_oid(myrelid, InvalidOid, oldconname, false);
+	}
 
 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
 	if (!HeapTupleIsValid(tuple))
@@ -2356,7 +2366,7 @@ rename_constraint_internal(Oid myrelid,
 			 constraintOid);
 	con = (Form_pg_constraint) GETSTRUCT(tuple);
 
-	if (con->contype == CONSTRAINT_CHECK && !con->conisonly)
+	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->conisonly)
 	{
 		if (recurse)
 		{
@@ -2376,7 +2386,7 @@ rename_constraint_internal(Oid myrelid,
 				if (childrelid == myrelid)
 					continue;
 
-				rename_constraint_internal(childrelid, oldconname, newconname, false, true, numparents);
+				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
 			}
 		}
 		else
@@ -2407,24 +2417,43 @@ rename_constraint_internal(Oid myrelid,
 
 	ReleaseSysCache(tuple);
 
-	relation_close(targetrelation, NoLock);		/* close rel but keep lock */
+	if (targetrelation)
+		relation_close(targetrelation, NoLock);		/* close rel but keep lock */
 }
 
 void
 RenameConstraint(RenameStmt *stmt)
 {
-	Oid			relid;
+	Oid			relid = InvalidOid;
+	Oid			typid = InvalidOid;
 
-	/* lock level taken here should match rename_constraint_internal */
-	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
-									 false, false,
-									 RangeVarCallbackForRenameAttribute,
-									 NULL);
+	if (stmt->relationType == OBJECT_DOMAIN)
+	{
+		Relation	rel;
+		HeapTuple	tup;
+
+		typid = typenameTypeId(NULL,  makeTypeNameFromNameList(stmt->object));
+		rel = heap_open(TypeRelationId, RowExclusiveLock);
+		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+		if (!HeapTupleIsValid(tup))
+			elog(ERROR, "cache lookup failed for type %u", typid);
+		checkDomainOwner(tup);
+		ReleaseSysCache(tup);
+		heap_close(rel, NoLock);
+	}
+	else
+	{
+		/* lock level taken here should match rename_constraint_internal */
+		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
+										 false, false,
+										 RangeVarCallbackForRenameAttribute,
+										 NULL);
+	}
 
-	rename_constraint_internal(relid,
+	rename_constraint_internal(relid, typid,
 							   stmt->subname,
 							   stmt->newname,
-							   interpretInhOption(stmt->relation->inhOpt),		/* recursive? */
+							   stmt->relation ? interpretInhOption(stmt->relation->inhOpt) : false,		/* recursive? */
 							   false,	/* recursing? */
 							   0		/* expected inhcount */);
 }
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 37fe5e8..701a986 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -98,7 +98,6 @@ static Oid	findRangeCanonicalFunction(List *procname, Oid typeOid);
 static Oid	findRangeSubtypeDiffFunction(List *procname, Oid subtype);
 static void validateDomainConstraint(Oid domainoid, char *ccbin);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
-static void checkDomainOwner(HeapTuple tup);
 static void checkEnumOwner(HeapTuple tup);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
 					Oid baseTypeOid,
@@ -2794,7 +2793,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
  * Check that the type is actually a domain and that the current user
  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
  */
-static void
+void
 checkDomainOwner(HeapTuple tup)
 {
 	Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index feb28a4..bdfed84 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6534,6 +6534,16 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_CONSTRAINT;
+					n->relationType = OBJECT_DOMAIN;
+					n->object = $3;
+					n->subname = $6;
+					n->newname = $8;
+					$$ = (Node *)n;
+				}
 			| ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 43f5634..f4370ee 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -802,7 +802,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 
 			/* Copy comment on constraint */
 			if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
-				(comment = GetComment(get_constraint_oid(RelationGetRelid(relation),
+				(comment = GetComment(get_constraint_oid(RelationGetRelid(relation), InvalidOid,
 														 n->conname, false),
 									  ConstraintRelationId,
 									  0)) != NULL)
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 77015ae..19281e5 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -244,7 +244,7 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
 
 extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 						  Oid newNspId, bool isType);
-extern Oid	get_constraint_oid(Oid relid, const char *conname, bool missing_ok);
+extern Oid	get_constraint_oid(Oid relid, Oid typid, const char *conname, bool missing_ok);
 
 extern bool check_functional_grouping(Oid relid,
 						  Index varno, Index varlevelsup,
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index 0c7e10d..bb4a7c3 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -14,6 +14,7 @@
 #ifndef TYPECMDS_H
 #define TYPECMDS_H
 
+#include "access/htup.h"
 #include "nodes/parsenodes.h"
 
 
@@ -35,6 +36,8 @@ extern void AlterDomainValidateConstraint(List *names, char *constrName);
 extern void AlterDomainDropConstraint(List *names, const char *constrName,
 									  DropBehavior behavior, bool missing_ok);
 
+extern void checkDomainOwner(HeapTuple tup);
+
 extern List *GetDomainConstraints(Oid typeOid);
 
 extern void RenameType(RenameStmt *stmt);
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index e713b97..03204ff 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -659,3 +659,10 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+--
+-- Renaming domain constraints
+--
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index ad049b7..5af36af 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -496,3 +496,13 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+
+
+--
+-- Renaming domain constraints
+--
+
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;
#2Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#1)
Re: renaming domain constraint

On Fri, Mar 16, 2012 at 1:34 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

Here is a patch for being able to rename constraints of domains.  It
goes on top of the previously committed patch for renaming table
constraints.

I don't like the way you've modified get_constraint_oid(), which is
currently parallel to many other get_whatever_oid() functions and with
this patch, would no longer be. There seems to be little point in
shoehorning the new functionality into the existing function anyway,
considering that you've conditionalized basically every piece of logic
in the function. I think you should just invent a completely separate
function and be done with it.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#3Alvaro Herrera
alvherre@commandprompt.com
In reply to: Robert Haas (#2)
Re: renaming domain constraint

Excerpts from Robert Haas's message of mié mar 21 11:43:17 -0300 2012:

On Fri, Mar 16, 2012 at 1:34 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

Here is a patch for being able to rename constraints of domains.  It
goes on top of the previously committed patch for renaming table
constraints.

I don't like the way you've modified get_constraint_oid(), which is
currently parallel to many other get_whatever_oid() functions and with
this patch, would no longer be. There seems to be little point in
shoehorning the new functionality into the existing function anyway,
considering that you've conditionalized basically every piece of logic
in the function. I think you should just invent a completely separate
function and be done with it.

get_relation_constraint_oid() plus get_domain_constraint_oid()?

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#4Peter Eisentraut
peter_e@gmx.net
In reply to: Alvaro Herrera (#3)
1 attachment(s)
Re: renaming domain constraint

On ons, 2012-03-21 at 11:57 -0300, Alvaro Herrera wrote:

Excerpts from Robert Haas's message of mié mar 21 11:43:17 -0300 2012:

On Fri, Mar 16, 2012 at 1:34 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

Here is a patch for being able to rename constraints of domains. It
goes on top of the previously committed patch for renaming table
constraints.

I don't like the way you've modified get_constraint_oid(), which is
currently parallel to many other get_whatever_oid() functions and with
this patch, would no longer be. There seems to be little point in
shoehorning the new functionality into the existing function anyway,
considering that you've conditionalized basically every piece of logic
in the function. I think you should just invent a completely separate
function and be done with it.

get_relation_constraint_oid() plus get_domain_constraint_oid()?

Makes sense. Updated patch attached.

Attachments:

rename-domain-constraint-v2.patchtext/x-patch; charset=UTF-8; name=rename-domain-constraint-v2.patchDownload
diff --git a/doc/src/sgml/ref/alter_domain.sgml b/doc/src/sgml/ref/alter_domain.sgml
index 2511a12..c59975a 100644
--- a/doc/src/sgml/ref/alter_domain.sgml
+++ b/doc/src/sgml/ref/alter_domain.sgml
@@ -32,6 +32,8 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     DROP CONSTRAINT [ IF EXISTS ] <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
+     RENAME CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> TO <replaceable class="PARAMETER">new_constraint_name</replaceable>
+ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     VALIDATE CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
@@ -103,6 +105,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
    </varlistentry>
 
    <varlistentry>
+    <term>RENAME CONSTRAINT</term>
+    <listitem>
+     <para>
+      This form changes the name of a constraint on a domain.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term>VALIDATE CONSTRAINT</term>
     <listitem>
      <para>
@@ -182,7 +193,7 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
       <term><replaceable class="PARAMETER">constraint_name</replaceable></term>
       <listitem>
        <para>
-        Name of an existing constraint to drop.
+        Name of an existing constraint to drop or rename.
        </para>
       </listitem>
      </varlistentry>
@@ -226,6 +237,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
      </varlistentry>
 
      <varlistentry>
+      <term><replaceable class="PARAMETER">new_constraint_name</replaceable></term>
+      <listitem>
+       <para>
+        The new name for the constraint.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="PARAMETER">new_owner</replaceable></term>
       <listitem>
        <para>
@@ -289,6 +309,13 @@ ALTER DOMAIN zipcode DROP CONSTRAINT zipchk;
   </para>
 
   <para>
+   To rename a check constraint on a domain:
+<programlisting>
+ALTER DOMAIN zipcode RENAME CONSTRAINT zipchk TO zip_check;
+</programlisting>
+  </para>
+
+  <para>
    To move the domain into a different schema:
 <programlisting>
 ALTER DOMAIN zipcode SET SCHEMA customers;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index e6e0347..250069f 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -753,7 +753,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
 				address.objectId =
-					get_constraint_oid(reloid, depname, missing_ok);
+					get_relation_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 342cf75..bf174b6 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -736,12 +736,12 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 }
 
 /*
- * get_constraint_oid
+ * get_relation_constraint_oid
  *		Find a constraint on the specified relation with the specified name.
  *		Returns constraint's OID.
  */
 Oid
-get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
+get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 {
 	Relation	pg_constraint;
 	HeapTuple	tuple;
@@ -794,6 +794,64 @@ get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 }
 
 /*
+ * get_domain_constraint_oid
+ *		Find a constraint on the specified domain with the specified name.
+ *		Returns constraint's OID.
+ */
+Oid
+get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
+{
+	Relation	pg_constraint;
+	HeapTuple	tuple;
+	SysScanDesc scan;
+	ScanKeyData skey[1];
+	Oid			conOid = InvalidOid;
+
+	/*
+	 * Fetch the constraint tuple from pg_constraint.  There may be more than
+	 * one match, because constraints are not required to have unique names;
+	 * if so, error out.
+	 */
+	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
+
+	ScanKeyInit(&skey[0],
+				Anum_pg_constraint_contypid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(typid));
+
+	scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
+							  SnapshotNow, 1, skey);
+
+	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+	{
+		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
+
+		if (strcmp(NameStr(con->conname), conname) == 0)
+		{
+			if (OidIsValid(conOid))
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("domain \"%s\" has multiple constraints named \"%s\"",
+						format_type_be(typid), conname)));
+			conOid = HeapTupleGetOid(tuple);
+		}
+	}
+
+	systable_endscan(scan);
+
+	/* If no such constraint exists, complain */
+	if (!OidIsValid(conOid) && !missing_ok)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("constraint \"%s\" for domain \"%s\" does not exist",
+						conname, format_type_be(typid))));
+
+	heap_close(pg_constraint, AccessShareLock);
+
+	return conOid;
+}
+
+/*
  * Determine whether a relation can be proven functionally dependent on
  * a set of grouping columns.  If so, return TRUE and add the pg_constraint
  * OIDs of the constraints needed for the proof to the *constraintDeps list.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 9615380..9853686 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2333,22 +2333,32 @@ renameatt(RenameStmt *stmt)
  */
 static void
 rename_constraint_internal(Oid myrelid,
+						   Oid mytypid,
 						   const char *oldconname,
 						   const char *newconname,
 						   bool recurse,
 						   bool recursing,
 						   int expected_parents)
 {
-	Relation	targetrelation;
+	Relation	targetrelation = NULL;
 	Oid			constraintOid;
 	HeapTuple   tuple;
 	Form_pg_constraint con;
 
-	targetrelation = relation_open(myrelid, AccessExclusiveLock);
-	/* don't tell it whether we're recursing; we allow changing typed tables here */
-	renameatt_check(myrelid, RelationGetForm(targetrelation), false);
+	AssertArg(!myrelid || !mytypid);
+
+	if (mytypid)
+	{
+		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
+	}
+	else
+	{
+		targetrelation = relation_open(myrelid, AccessExclusiveLock);
+		/* don't tell it whether we're recursing; we allow changing typed tables here */
+		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
 
-	constraintOid = get_constraint_oid(myrelid, oldconname, false);
+		constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
+	}
 
 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
 	if (!HeapTupleIsValid(tuple))
@@ -2356,7 +2366,7 @@ rename_constraint_internal(Oid myrelid,
 			 constraintOid);
 	con = (Form_pg_constraint) GETSTRUCT(tuple);
 
-	if (con->contype == CONSTRAINT_CHECK && !con->conisonly)
+	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->conisonly)
 	{
 		if (recurse)
 		{
@@ -2376,7 +2386,7 @@ rename_constraint_internal(Oid myrelid,
 				if (childrelid == myrelid)
 					continue;
 
-				rename_constraint_internal(childrelid, oldconname, newconname, false, true, numparents);
+				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
 			}
 		}
 		else
@@ -2407,24 +2417,43 @@ rename_constraint_internal(Oid myrelid,
 
 	ReleaseSysCache(tuple);
 
-	relation_close(targetrelation, NoLock);		/* close rel but keep lock */
+	if (targetrelation)
+		relation_close(targetrelation, NoLock);		/* close rel but keep lock */
 }
 
 void
 RenameConstraint(RenameStmt *stmt)
 {
-	Oid			relid;
+	Oid			relid = InvalidOid;
+	Oid			typid = InvalidOid;
 
-	/* lock level taken here should match rename_constraint_internal */
-	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
-									 false, false,
-									 RangeVarCallbackForRenameAttribute,
-									 NULL);
+	if (stmt->relationType == OBJECT_DOMAIN)
+	{
+		Relation	rel;
+		HeapTuple	tup;
+
+		typid = typenameTypeId(NULL,  makeTypeNameFromNameList(stmt->object));
+		rel = heap_open(TypeRelationId, RowExclusiveLock);
+		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+		if (!HeapTupleIsValid(tup))
+			elog(ERROR, "cache lookup failed for type %u", typid);
+		checkDomainOwner(tup);
+		ReleaseSysCache(tup);
+		heap_close(rel, NoLock);
+	}
+	else
+	{
+		/* lock level taken here should match rename_constraint_internal */
+		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
+										 false, false,
+										 RangeVarCallbackForRenameAttribute,
+										 NULL);
+	}
 
-	rename_constraint_internal(relid,
+	rename_constraint_internal(relid, typid,
 							   stmt->subname,
 							   stmt->newname,
-							   interpretInhOption(stmt->relation->inhOpt),		/* recursive? */
+							   stmt->relation ? interpretInhOption(stmt->relation->inhOpt) : false,		/* recursive? */
 							   false,	/* recursing? */
 							   0		/* expected inhcount */);
 }
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 37fe5e8..701a986 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -98,7 +98,6 @@ static Oid	findRangeCanonicalFunction(List *procname, Oid typeOid);
 static Oid	findRangeSubtypeDiffFunction(List *procname, Oid subtype);
 static void validateDomainConstraint(Oid domainoid, char *ccbin);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
-static void checkDomainOwner(HeapTuple tup);
 static void checkEnumOwner(HeapTuple tup);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
 					Oid baseTypeOid,
@@ -2794,7 +2793,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
  * Check that the type is actually a domain and that the current user
  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
  */
-static void
+void
 checkDomainOwner(HeapTuple tup)
 {
 	Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3827e2e..f2151ef 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6529,6 +6529,16 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_CONSTRAINT;
+					n->relationType = OBJECT_DOMAIN;
+					n->object = $3;
+					n->subname = $6;
+					n->newname = $8;
+					$$ = (Node *)n;
+				}
 			| ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 43f5634..7c315f6 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -802,7 +802,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 
 			/* Copy comment on constraint */
 			if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
-				(comment = GetComment(get_constraint_oid(RelationGetRelid(relation),
+				(comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
 														 n->conname, false),
 									  ConstraintRelationId,
 									  0)) != NULL)
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 77015ae..22d6595 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -244,7 +244,8 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
 
 extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 						  Oid newNspId, bool isType);
-extern Oid	get_constraint_oid(Oid relid, const char *conname, bool missing_ok);
+extern Oid	get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
+extern Oid	get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
 
 extern bool check_functional_grouping(Oid relid,
 						  Index varno, Index varlevelsup,
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index 0c7e10d..bb4a7c3 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -14,6 +14,7 @@
 #ifndef TYPECMDS_H
 #define TYPECMDS_H
 
+#include "access/htup.h"
 #include "nodes/parsenodes.h"
 
 
@@ -35,6 +36,8 @@ extern void AlterDomainValidateConstraint(List *names, char *constrName);
 extern void AlterDomainDropConstraint(List *names, const char *constrName,
 									  DropBehavior behavior, bool missing_ok);
 
+extern void checkDomainOwner(HeapTuple tup);
+
 extern List *GetDomainConstraints(Oid typeOid);
 
 extern void RenameType(RenameStmt *stmt);
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index e713b97..03204ff 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -659,3 +659,10 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+--
+-- Renaming domain constraints
+--
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index ad049b7..5af36af 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -496,3 +496,13 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+
+
+--
+-- Renaming domain constraints
+--
+
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;