static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
                     char *cmd, List **wqueue, LOCKMODE lockmode,
                     bool rewrite);
+static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
+                        Oid objid, Relation rel, char *conname);
 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
 static void TryReuseForeignKey(Oid oldId, Constraint *con);
 static void change_owner_fix_column_acls(Oid relationOid,
                ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
                                    false, true, lockmode);
            break;
+       case AT_ReAddComment:   /* Re-add existing comment */
+           address = CommentObject((CommentStmt *) cmd->def);
+           break;
        case AT_AddIndexConstraint:     /* ADD CONSTRAINT USING INDEX */
            address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
                                               lockmode);
 
            if (!rewrite)
                TryReuseIndex(oldId, stmt);
+           /* keep the index's comment */
+           stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
 
            newcmd = makeNode(AlterTableCmd);
            newcmd->subtype = AT_ReAddIndex;
 
                if (cmd->subtype == AT_AddIndex)
                {
+                   IndexStmt  *indstmt;
+                   Oid         indoid;
+
                    Assert(IsA(cmd->def, IndexStmt));
 
+                   indstmt = (IndexStmt *) cmd->def;
+                   indoid = get_constraint_index(oldId);
+
                    if (!rewrite)
-                       TryReuseIndex(get_constraint_index(oldId),
-                                     (IndexStmt *) cmd->def);
+                       TryReuseIndex(indoid, indstmt);
+                   /* keep any comment on the index */
+                   indstmt->idxcomment = GetComment(indoid,
+                                                    RelationRelationId, 0);
 
                    cmd->subtype = AT_ReAddIndex;
                    tab->subcmds[AT_PASS_OLD_INDEX] =
                        lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
+
+                   /* recreate any comment on the constraint */
+                   RebuildConstraintComment(tab,
+                                            AT_PASS_OLD_INDEX,
+                                            oldId,
+                                            rel, indstmt->idxname);
                }
                else if (cmd->subtype == AT_AddConstraint)
                {
                    cmd->subtype = AT_ReAddConstraint;
                    tab->subcmds[AT_PASS_OLD_CONSTR] =
                        lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
+
+                   /* recreate any comment on the constraint */
+                   RebuildConstraintComment(tab,
+                                            AT_PASS_OLD_CONSTR,
+                                            oldId,
+                                            rel, con->conname);
                }
                else
                    elog(ERROR, "unexpected statement type: %d",
    relation_close(rel, NoLock);
 }
 
+/*
+ * Subroutine for ATPostAlterTypeParse() to recreate a comment entry for
+ * a constraint that is being re-added.
+ */
+static void
+RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
+                        Relation rel, char *conname)
+{
+   CommentStmt *cmd;
+   char       *comment_str;
+   AlterTableCmd *newcmd;
+
+   /* Look for comment for object wanted, and leave if none */
+   comment_str = GetComment(objid, ConstraintRelationId, 0);
+   if (comment_str == NULL)
+       return;
+
+   /* Build node CommentStmt */
+   cmd = makeNode(CommentStmt);
+   cmd->objtype = OBJECT_TABCONSTRAINT;
+   cmd->objname = list_make3(
+                  makeString(get_namespace_name(RelationGetNamespace(rel))),
+                             makeString(RelationGetRelationName(rel)),
+                             makeString(conname));
+   cmd->objargs = NIL;
+   cmd->comment = comment_str;
+
+   /* Append it to list of commands */
+   newcmd = makeNode(AlterTableCmd);
+   newcmd->subtype = AT_ReAddComment;
+   newcmd->def = (Node *) cmd;
+   tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
+}
+
 /*
  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
  * for the real analysis, then mutates the IndexStmt based on that verdict.
 
    AT_AddConstraint,           /* add constraint */
    AT_AddConstraintRecurse,    /* internal to commands/tablecmds.c */
    AT_ReAddConstraint,         /* internal to commands/tablecmds.c */
+   AT_ReAddComment,            /* internal to commands/tablecmds.c */
    AT_AlterConstraint,         /* alter constraint */
    AT_ValidateConstraint,      /* validate constraint */
    AT_ValidateConstraintRecurse,       /* internal to commands/tablecmds.c */
 
 
 DROP TABLE alter2.tt8;
 DROP SCHEMA alter2;
+-- Check that comments on constraints and indexes are not lost at ALTER TABLE.
+CREATE TABLE comment_test (
+  id int,
+  positive_col int CHECK (positive_col > 0),
+  indexed_col int,
+  CONSTRAINT comment_test_pk PRIMARY KEY (id));
+CREATE INDEX comment_test_index ON comment_test(indexed_col);
+COMMENT ON COLUMN comment_test.id IS 'Column ''id'' on comment_test';
+COMMENT ON INDEX comment_test_index IS 'Simple index on comment_test';
+COMMENT ON CONSTRAINT comment_test_positive_col_check ON comment_test IS 'CHECK constraint on comment_test.positive_col';
+COMMENT ON CONSTRAINT comment_test_pk ON comment_test IS 'PRIMARY KEY constraint of comment_test';
+COMMENT ON INDEX comment_test_pk IS 'Index backing the PRIMARY KEY of comment_test';
+SELECT col_description('comment_test'::regclass, 1) as comment;
+           comment           
+-----------------------------
+ Column 'id' on comment_test
+(1 row)
+
+SELECT indexrelid::regclass as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass;
+       index        |                    comment                    
+--------------------+-----------------------------------------------
+ comment_test_index | Simple index on comment_test
+ comment_test_pk    | Index backing the PRIMARY KEY of comment_test
+(2 rows)
+
+SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass;
+           constraint            |                    comment                    
+---------------------------------+-----------------------------------------------
+ comment_test_pk                 | PRIMARY KEY constraint of comment_test
+ comment_test_positive_col_check | CHECK constraint on comment_test.positive_col
+(2 rows)
+
+-- Change the datatype of all the columns. ALTER TABLE is optimized to not
+-- rebuild an index if the new data type is binary compatible with the old
+-- one. Check do a dummy ALTER TABLE that doesn't change the datatype
+-- first, to test that no-op codepath, and another one that does.
+ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE text;
+ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE text;
+ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE bigint;
+-- Check that the comments are intact.
+SELECT col_description('comment_test'::regclass, 1) as comment;
+           comment           
+-----------------------------
+ Column 'id' on comment_test
+(1 row)
+
+SELECT indexrelid::regclass as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass;
+       index        |                    comment                    
+--------------------+-----------------------------------------------
+ comment_test_pk    | Index backing the PRIMARY KEY of comment_test
+ comment_test_index | Simple index on comment_test
+(2 rows)
+
+SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass;
+           constraint            |                    comment                    
+---------------------------------+-----------------------------------------------
+ comment_test_positive_col_check | CHECK constraint on comment_test.positive_col
+ comment_test_pk                 | PRIMARY KEY constraint of comment_test
+(2 rows)
+
 -- Check that we map relation oids to filenodes and back correctly.  Only
 -- display bad mappings so the test output doesn't change all the time.  A
 -- filenode function call can return NULL for a relation dropped concurrently
 
 DROP TABLE alter2.tt8;
 DROP SCHEMA alter2;
 
+
+-- Check that comments on constraints and indexes are not lost at ALTER TABLE.
+CREATE TABLE comment_test (
+  id int,
+  positive_col int CHECK (positive_col > 0),
+  indexed_col int,
+  CONSTRAINT comment_test_pk PRIMARY KEY (id));
+CREATE INDEX comment_test_index ON comment_test(indexed_col);
+
+COMMENT ON COLUMN comment_test.id IS 'Column ''id'' on comment_test';
+COMMENT ON INDEX comment_test_index IS 'Simple index on comment_test';
+COMMENT ON CONSTRAINT comment_test_positive_col_check ON comment_test IS 'CHECK constraint on comment_test.positive_col';
+COMMENT ON CONSTRAINT comment_test_pk ON comment_test IS 'PRIMARY KEY constraint of comment_test';
+COMMENT ON INDEX comment_test_pk IS 'Index backing the PRIMARY KEY of comment_test';
+
+SELECT col_description('comment_test'::regclass, 1) as comment;
+SELECT indexrelid::regclass as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass;
+SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass;
+
+-- Change the datatype of all the columns. ALTER TABLE is optimized to not
+-- rebuild an index if the new data type is binary compatible with the old
+-- one. Check do a dummy ALTER TABLE that doesn't change the datatype
+-- first, to test that no-op codepath, and another one that does.
+ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE text;
+ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE text;
+ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE int;
+ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE bigint;
+
+-- Check that the comments are intact.
+SELECT col_description('comment_test'::regclass, 1) as comment;
+SELECT indexrelid::regclass as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass;
+SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass;
+
+
 -- Check that we map relation oids to filenodes and back correctly.  Only
 -- display bad mappings so the test output doesn't change all the time.  A
 -- filenode function call can return NULL for a relation dropped concurrently