diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index 36a7312056..62e1968c08 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -28,6 +28,7 @@ COMMENT ON
COLLATION object_name |
COLUMN relation_name.column_name |
CONSTRAINT constraint_name ON table_name |
+ CONSTRAINT constraint_name ON DOMAIN domain_name |
CONVERSION object_name |
DATABASE object_name |
DOMAIN object_name |
@@ -126,6 +127,18 @@ COMMENT ON
+
+ table_name
+ domain_name
+
+
+ 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.
+
+
+
+
source_type
@@ -266,6 +279,7 @@ COMMENT ON COLLATION "fr_CA" IS 'Canadian French';
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';
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index e261307e9d..297deb5f3f 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -530,11 +530,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
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:
@@ -934,7 +951,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
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);
@@ -990,7 +1007,7 @@ get_object_address_relobject(ObjectType objtype, List *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) :
@@ -1178,7 +1195,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
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));
@@ -1191,6 +1208,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
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;
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9bafef7..e7f4ef3e8e 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -305,7 +305,8 @@ ExecRenameStmt(RenameStmt *stmt)
{
switch (stmt->renameType)
{
- case OBJECT_CONSTRAINT:
+ case OBJECT_TABCONSTRAINT:
+ case OBJECT_DOMCONSTRAINT:
return RenameConstraint(stmt);
case OBJECT_DATABASE:
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 8b88ecb359..6bdb774987 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1053,10 +1053,10 @@ EventTriggerSupportsObjectType(ObjectType obtype)
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:
@@ -1073,6 +1073,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
case OBJECT_RULE:
case OBJECT_SCHEMA:
case OBJECT_SEQUENCE:
+ case OBJECT_TABCONSTRAINT:
case OBJECT_TABLE:
case OBJECT_TRIGGER:
case OBJECT_TSCONFIGURATION:
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 81c5ab27c9..3c0cdea265 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2457,7 +2457,7 @@ RenameConstraint(RenameStmt *stmt)
Oid relid = InvalidOid;
Oid typid = InvalidOid;
- if (stmt->relationType == OBJECT_DOMAIN)
+ if (stmt->renameType == OBJECT_DOMCONSTRAINT)
{
Relation rel;
HeapTuple tup;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1f4fe9d494..6431601c66 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5572,6 +5572,7 @@ opt_restart_seqs:
* CAST ( AS ) |
* COLUMN . |
* CONSTRAINT ON |
+ * CONSTRAINT ON DOMAIN |
* FUNCTION (arg1, arg2, ...) |
* LARGE OBJECT |
* OPERATOR (leftoperand_typ, rightoperand_typ) |
@@ -5623,12 +5624,21 @@ CommentStmt:
| 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);
@@ -7355,8 +7365,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| 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;
@@ -7624,8 +7633,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| 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;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index b9fbb5b6ef..a85327df2c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -896,7 +896,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
{
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));
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index aa8fe880d7..71580e8ec5 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1589,9 +1589,6 @@ AlterObjectTypeCommandTag(ObjectType objtype)
case OBJECT_COLUMN:
tag = "ALTER TABLE";
break;
- case OBJECT_CONSTRAINT:
- tag = "ALTER TABLE";
- break;
case OBJECT_CONVERSION:
tag = "ALTER CONVERSION";
break;
@@ -1599,6 +1596,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
tag = "ALTER DATABASE";
break;
case OBJECT_DOMAIN:
+ case OBJECT_DOMCONSTRAINT:
tag = "ALTER DOMAIN";
break;
case OBJECT_EXTENSION:
@@ -1650,6 +1648,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
tag = "ALTER SEQUENCE";
break;
case OBJECT_TABLE:
+ case OBJECT_TABCONSTRAINT:
tag = "ALTER TABLE";
break;
case OBJECT_TABLESPACE:
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4175ddc823..6658fda83e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -9261,6 +9261,23 @@ dumpDomain(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
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);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 5a9ceca0df..f2d33258d7 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -952,7 +952,7 @@ objectDescription(const char *pattern, bool showSystem)
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"
@@ -963,7 +963,7 @@ objectDescription(const char *pattern, bool showSystem)
"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"
@@ -973,6 +973,29 @@ objectDescription(const char *pattern, bool showSystem)
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+
*/
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 458eeb0b9e..64508f0338 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1208,11 +1208,11 @@ typedef enum ObjectType
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,
@@ -1231,6 +1231,7 @@ typedef enum ObjectType
OBJECT_RULE,
OBJECT_SCHEMA,
OBJECT_SEQUENCE,
+ OBJECT_TABCONSTRAINT,
OBJECT_TABLE,
OBJECT_TABLESPACE,
OBJECT_TRIGGER,
diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source
index 16d38f6d1e..8ec00543fb 100644
--- a/src/test/regress/input/constraints.source
+++ b/src/test/regress/input/constraints.source
@@ -478,3 +478,24 @@ UPDATE deferred_excl SET f1 = 3;
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;
diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source
index 2ffd263dd3..0d32a9eab6 100644
--- a/src/test/regress/output/constraints.source
+++ b/src/test/regress/output/constraints.source
@@ -645,3 +645,22 @@ ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =);
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;