COLLATION <replaceable class="PARAMETER">object_name</replaceable> |
   COLUMN <replaceable class="PARAMETER">relation_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
   CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
+  CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON DOMAIN <replaceable class="PARAMETER">domain_name</replaceable> |
   CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
   DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
   DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><replaceable class="parameter">table_name</replaceable></term>
+    <term><replaceable class="parameter">domain_name</replaceable></term>
+    <listitem>
+     <para>
+      When creating a comment on a constraint on a table or a domain, these
+      parameteres specify the name of the table or domain on which the
+      constraint is defined.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
      <term><replaceable>source_type</replaceable></term>
      <listitem>
 COMMENT ON COLUMN my_table.my_column IS 'Employee ID number';
 COMMENT ON CONVERSION my_conv IS 'Conversion to UTF8';
 COMMENT ON CONSTRAINT bar_col_cons ON bar IS 'Constrains column col';
+COMMENT ON CONSTRAINT dom_col_constr ON DOMAIN dom IS 'Constrains col of domain';
 COMMENT ON DATABASE my_database IS 'Development Database';
 COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
 COMMENT ON EXTENSION hstore IS 'implements the hstore data type';
 
                break;
            case OBJECT_RULE:
            case OBJECT_TRIGGER:
-           case OBJECT_CONSTRAINT:
+           case OBJECT_TABCONSTRAINT:
            case OBJECT_POLICY:
                address = get_object_address_relobject(objtype, objname,
                                                       &relation, missing_ok);
                break;
+           case OBJECT_DOMCONSTRAINT:
+               {
+                   List           *domname;
+                   ObjectAddress   domaddr;
+                   char           *constrname;
+
+                   domname = list_truncate(list_copy(objname), list_length(objname) - 1);
+                   constrname = strVal(llast(objname));
+                   domaddr = get_object_address_type(OBJECT_DOMAIN, domname, missing_ok);
+
+                   address.classId = ConstraintRelationId;
+                   address.objectId = get_domain_constraint_oid(domaddr.objectId,
+                                                             constrname, missing_ok);
+                   address.objectSubId = 0;
+
+               }
+               break;
            case OBJECT_DATABASE:
            case OBJECT_EXTENSION:
            case OBJECT_TABLESPACE:
    const char *depname;
 
    /* Extract name of dependent object. */
-   depname = strVal(lfirst(list_tail(objname)));
+   depname = strVal(llast(objname));
 
    /* Separate relation name from dependent object name. */
    nnames = list_length(objname);
                    get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
                address.objectSubId = 0;
                break;
-           case OBJECT_CONSTRAINT:
+           case OBJECT_TABCONSTRAINT:
                address.classId = ConstraintRelationId;
                address.objectId = relation ?
                    get_relation_constraint_oid(reloid, depname, missing_ok) :
        case OBJECT_RULE:
        case OBJECT_TRIGGER:
        case OBJECT_POLICY:
-       case OBJECT_CONSTRAINT:
+       case OBJECT_TABCONSTRAINT:
            if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
                               RelationGetRelationName(relation));
        case OBJECT_TYPE:
        case OBJECT_DOMAIN:
        case OBJECT_ATTRIBUTE:
+       case OBJECT_DOMCONSTRAINT:
            if (!pg_type_ownercheck(address.objectId, roleid))
                aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
            break;
 
 {
    switch (stmt->renameType)
    {
-       case OBJECT_CONSTRAINT:
+       case OBJECT_TABCONSTRAINT:
+       case OBJECT_DOMCONSTRAINT:
            return RenameConstraint(stmt);
 
        case OBJECT_DATABASE:
 
        case OBJECT_ATTRIBUTE:
        case OBJECT_CAST:
        case OBJECT_COLUMN:
-       case OBJECT_CONSTRAINT:
        case OBJECT_COLLATION:
        case OBJECT_CONVERSION:
        case OBJECT_DOMAIN:
+       case OBJECT_DOMCONSTRAINT:
        case OBJECT_EXTENSION:
        case OBJECT_FDW:
        case OBJECT_FOREIGN_SERVER:
        case OBJECT_RULE:
        case OBJECT_SCHEMA:
        case OBJECT_SEQUENCE:
+       case OBJECT_TABCONSTRAINT:
        case OBJECT_TABLE:
        case OBJECT_TRIGGER:
        case OBJECT_TSCONFIGURATION:
 
    Oid         relid = InvalidOid;
    Oid         typid = InvalidOid;
 
-   if (stmt->relationType == OBJECT_DOMAIN)
+   if (stmt->renameType == OBJECT_DOMCONSTRAINT)
    {
        Relation    rel;
        HeapTuple   tup;
 
  *              CAST (<src type> AS <dst type>) |
  *              COLUMN <relname>.<colname> |
  *              CONSTRAINT <constraintname> ON <relname> |
+ *              CONSTRAINT <constraintname> ON DOMAIN <domainname> |
  *              FUNCTION <funcname> (arg1, arg2, ...) |
  *              LARGE OBJECT <oid> |
  *              OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
            | COMMENT ON CONSTRAINT name ON any_name IS comment_text
                {
                    CommentStmt *n = makeNode(CommentStmt);
-                   n->objtype = OBJECT_CONSTRAINT;
+                   n->objtype = OBJECT_TABCONSTRAINT;
                    n->objname = lappend($6, makeString($4));
                    n->objargs = NIL;
                    n->comment = $8;
                    $$ = (Node *) n;
                }
+           | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
+               {
+                   CommentStmt *n = makeNode(CommentStmt);
+                   n->objtype = OBJECT_DOMCONSTRAINT;
+                   n->objname = lappend($7, makeString($4));
+                   n->objargs = NIL;
+                   n->comment = $9;
+                   $$ = (Node *) n;
+               }
            | COMMENT ON POLICY name ON any_name IS comment_text
                {
                    CommentStmt *n = makeNode(CommentStmt);
            | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
                {
                    RenameStmt *n = makeNode(RenameStmt);
-                   n->renameType = OBJECT_CONSTRAINT;
-                   n->relationType = OBJECT_DOMAIN;
+                   n->renameType = OBJECT_DOMCONSTRAINT;
                    n->object = $3;
                    n->subname = $6;
                    n->newname = $8;
            | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
                {
                    RenameStmt *n = makeNode(RenameStmt);
-                   n->renameType = OBJECT_CONSTRAINT;
-                   n->relationType = OBJECT_TABLE;
+                   n->renameType = OBJECT_TABCONSTRAINT;
                    n->relation = $3;
                    n->subname = $6;
                    n->newname = $8;
 
            {
                CommentStmt *stmt = makeNode(CommentStmt);
 
-               stmt->objtype = OBJECT_CONSTRAINT;
+               stmt->objtype = OBJECT_TABCONSTRAINT;
                stmt->objname = list_make3(makeString(cxt->relation->schemaname),
                                           makeString(cxt->relation->relname),
                                           makeString(n->conname));
 
        case OBJECT_COLUMN:
            tag = "ALTER TABLE";
            break;
-       case OBJECT_CONSTRAINT:
-           tag = "ALTER TABLE";
-           break;
        case OBJECT_CONVERSION:
            tag = "ALTER CONVERSION";
            break;
            tag = "ALTER DATABASE";
            break;
        case OBJECT_DOMAIN:
+       case OBJECT_DOMCONSTRAINT:
            tag = "ALTER DOMAIN";
            break;
        case OBJECT_EXTENSION:
            tag = "ALTER SEQUENCE";
            break;
        case OBJECT_TABLE:
+       case OBJECT_TABCONSTRAINT:
            tag = "ALTER TABLE";
            break;
        case OBJECT_TABLESPACE:
 
            tyinfo->dobj.namespace->dobj.name,
            tyinfo->rolname, tyinfo->typacl);
 
+   /* Dump any per-constraint comments */
+   for (i = 0; i < tyinfo->nDomChecks; i++)
+   {
+       ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
+       PQExpBuffer labelq = createPQExpBuffer();
+
+       appendPQExpBuffer(labelq, "CONSTRAINT %s ",
+                         fmtId(domcheck->dobj.name));
+       appendPQExpBuffer(labelq, "ON DOMAIN %s",
+                         fmtId(qtypname));
+       dumpComment(fout, dopt, labelq->data,
+                   tyinfo->dobj.namespace->dobj.name,
+                   tyinfo->rolname,
+                   domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+       destroyPQExpBuffer(labelq);
+   }
+
    destroyPQExpBuffer(q);
    destroyPQExpBuffer(delq);
    destroyPQExpBuffer(labelq);
 
                      gettext_noop("Object"),
                      gettext_noop("Description"));
 
-   /* Constraint descriptions */
+   /* Table constraint descriptions */
    appendPQExpBuffer(&buf,
                      "  SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
                      "  n.nspname as nspname,\n"
                      "ON c.oid = pgc.conrelid\n"
                      "    LEFT JOIN pg_catalog.pg_namespace n "
                      "    ON n.oid = c.relnamespace\n",
-                     gettext_noop("constraint"));
+                     gettext_noop("table constraint"));
 
    if (!showSystem && !pattern)
        appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
                          false, "n.nspname", "pgc.conname", NULL,
                          "pg_catalog.pg_table_is_visible(c.oid)");
 
+   /* Domain constraint descriptions */
+   appendPQExpBuffer(&buf,
+                     "UNION ALL\n"
+                     "  SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
+                     "  n.nspname as nspname,\n"
+                     "  CAST(pgc.conname AS pg_catalog.text) as name,"
+                     "  CAST('%s' AS pg_catalog.text) as object\n"
+                     "  FROM pg_catalog.pg_constraint pgc\n"
+                     "    JOIN pg_catalog.pg_type t "
+                     "ON t.oid = pgc.contypid\n"
+                     "    LEFT JOIN pg_catalog.pg_namespace n "
+                     "    ON n.oid = t.typnamespace\n",
+                     gettext_noop("domain constraint"));
+
+   if (!showSystem && !pattern)
+       appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                            "      AND n.nspname <> 'information_schema'\n");
+
+   processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
+                         false, "n.nspname", "pgc.conname", NULL,
+                         "pg_catalog.pg_type_is_visible(t.oid)");
+
+
    /*
     * pg_opclass.opcmethod only available in 8.3+
     */
 
    OBJECT_ATTRIBUTE,           /* type's attribute, when distinct from column */
    OBJECT_CAST,
    OBJECT_COLUMN,
-   OBJECT_CONSTRAINT,
    OBJECT_COLLATION,
    OBJECT_CONVERSION,
    OBJECT_DATABASE,
    OBJECT_DOMAIN,
+   OBJECT_DOMCONSTRAINT,
    OBJECT_EVENT_TRIGGER,
    OBJECT_EXTENSION,
    OBJECT_FDW,
    OBJECT_RULE,
    OBJECT_SCHEMA,
    OBJECT_SEQUENCE,
+   OBJECT_TABCONSTRAINT,
    OBJECT_TABLE,
    OBJECT_TABLESPACE,
    OBJECT_TRIGGER,
 
 ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =);
 
 DROP TABLE deferred_excl;
+
+-- Comments
+CREATE TABLE constraint_comments_tbl (a int CONSTRAINT the_constraint CHECK (a > 0));
+CREATE DOMAIN constraint_comments_dom AS int CONSTRAINT the_constraint CHECK (value > 0);
+
+COMMENT ON CONSTRAINT the_constraint ON constraint_comments_tbl IS 'yes, the comment';
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN constraint_comments_dom IS 'yes, another comment';
+
+-- no such constraint
+COMMENT ON CONSTRAINT no_constraint ON constraint_comments_tbl IS 'yes, the comment';
+COMMENT ON CONSTRAINT no_constraint ON DOMAIN constraint_comments_dom IS 'yes, another comment';
+
+-- no such table/domain
+COMMENT ON CONSTRAINT the_constraint ON no_comments_tbl IS 'bad comment';
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN no_comments_dom IS 'another bad comment';
+
+COMMENT ON CONSTRAINT the_constraint ON constraint_comments_tbl IS NULL;
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN constraint_comments_dom IS NULL;
+
+DROP TABLE constraint_comments_tbl;
+DROP DOMAIN constraint_comments_dom;
 
 ERROR:  could not create exclusion constraint "deferred_excl_f1_excl"
 DETAIL:  Key (f1)=(3) conflicts with key (f1)=(3).
 DROP TABLE deferred_excl;
+-- Comments
+CREATE TABLE constraint_comments_tbl (a int CONSTRAINT the_constraint CHECK (a > 0));
+CREATE DOMAIN constraint_comments_dom AS int CONSTRAINT the_constraint CHECK (value > 0);
+COMMENT ON CONSTRAINT the_constraint ON constraint_comments_tbl IS 'yes, the comment';
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN constraint_comments_dom IS 'yes, another comment';
+-- no such constraint
+COMMENT ON CONSTRAINT no_constraint ON constraint_comments_tbl IS 'yes, the comment';
+ERROR:  constraint "no_constraint" for table "constraint_comments_tbl" does not exist
+COMMENT ON CONSTRAINT no_constraint ON DOMAIN constraint_comments_dom IS 'yes, another comment';
+ERROR:  constraint "no_constraint" for domain "constraint_comments_dom" does not exist
+-- no such table/domain
+COMMENT ON CONSTRAINT the_constraint ON no_comments_tbl IS 'bad comment';
+ERROR:  relation "no_comments_tbl" does not exist
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN no_comments_dom IS 'another bad comment';
+ERROR:  type "no_comments_dom" does not exist
+COMMENT ON CONSTRAINT the_constraint ON constraint_comments_tbl IS NULL;
+COMMENT ON CONSTRAINT the_constraint ON DOMAIN constraint_comments_dom IS NULL;
+DROP TABLE constraint_comments_tbl;
+DROP DOMAIN constraint_comments_dom;