@@ -350,7 +350,9 @@ static void buildMatViewRefreshDependencies(Archive *fout);
350
350
static void getTableDataFKConstraints(void);
351
351
static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
352
352
TableInfo *tbinfo, int j,
353
- int i_notnull_name, int i_notnull_invalidoid,
353
+ int i_notnull_name,
354
+ int i_notnull_comment,
355
+ int i_notnull_invalidoid,
354
356
int i_notnull_noinherit,
355
357
int i_notnull_islocal,
356
358
PQExpBuffer *invalidnotnulloids);
@@ -9006,6 +9008,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9006
9008
int i_attalign;
9007
9009
int i_attislocal;
9008
9010
int i_notnull_name;
9011
+ int i_notnull_comment;
9009
9012
int i_notnull_noinherit;
9010
9013
int i_notnull_islocal;
9011
9014
int i_notnull_invalidoid;
@@ -9089,15 +9092,17 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9089
9092
9090
9093
/*
9091
9094
* Find out any NOT NULL markings for each column. In 18 and up we read
9092
- * pg_constraint to obtain the constraint name. notnull_noinherit is set
9095
+ * pg_constraint to obtain the constraint name, and for valid constraints
9096
+ * also pg_description to obtain its comment. notnull_noinherit is set
9093
9097
* according to the NO INHERIT property. For versions prior to 18, we
9094
9098
* store an empty string as the name when a constraint is marked as
9095
9099
* attnotnull (this cues dumpTableSchema to print the NOT NULL clause
9096
9100
* without a name); also, such cases are never NO INHERIT.
9097
9101
*
9098
9102
* For invalid constraints, we need to store their OIDs for processing
9099
9103
* elsewhere, so we bring the pg_constraint.oid value when the constraint
9100
- * is invalid, and NULL otherwise.
9104
+ * is invalid, and NULL otherwise. Their comments are handled not here
9105
+ * but by collectComments, because they're their own dumpable object.
9101
9106
*
9102
9107
* We track in notnull_islocal whether the constraint was defined directly
9103
9108
* in this table or via an ancestor, for binary upgrade. flagInhAttrs
@@ -9107,13 +9112,16 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9107
9112
if (fout->remoteVersion >= 180000)
9108
9113
appendPQExpBufferStr(q,
9109
9114
"co.conname AS notnull_name,\n"
9115
+ "CASE WHEN co.convalidated THEN pt.description"
9116
+ " ELSE NULL END AS notnull_comment,\n"
9110
9117
"CASE WHEN NOT co.convalidated THEN co.oid "
9111
9118
"ELSE NULL END AS notnull_invalidoid,\n"
9112
9119
"co.connoinherit AS notnull_noinherit,\n"
9113
9120
"co.conislocal AS notnull_islocal,\n");
9114
9121
else
9115
9122
appendPQExpBufferStr(q,
9116
9123
"CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
9124
+ "NULL AS notnull_comment,\n"
9117
9125
"NULL AS notnull_invalidoid,\n"
9118
9126
"false AS notnull_noinherit,\n"
9119
9127
"a.attislocal AS notnull_islocal,\n");
@@ -9157,15 +9165,16 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9157
9165
9158
9166
/*
9159
9167
* In versions 18 and up, we need pg_constraint for explicit NOT NULL
9160
- * entries. Also, we need to know if the NOT NULL for each column is
9161
- * backing a primary key.
9168
+ * entries and pg_description to get their comments.
9162
9169
*/
9163
9170
if (fout->remoteVersion >= 180000)
9164
9171
appendPQExpBufferStr(q,
9165
9172
" LEFT JOIN pg_catalog.pg_constraint co ON "
9166
9173
"(a.attrelid = co.conrelid\n"
9167
9174
" AND co.contype = 'n' AND "
9168
- "co.conkey = array[a.attnum])\n");
9175
+ "co.conkey = array[a.attnum])\n"
9176
+ " LEFT JOIN pg_catalog.pg_description pt ON "
9177
+ "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
9169
9178
9170
9179
appendPQExpBufferStr(q,
9171
9180
"WHERE a.attnum > 0::pg_catalog.int2\n"
@@ -9189,6 +9198,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9189
9198
i_attalign = PQfnumber(res, "attalign");
9190
9199
i_attislocal = PQfnumber(res, "attislocal");
9191
9200
i_notnull_name = PQfnumber(res, "notnull_name");
9201
+ i_notnull_comment = PQfnumber(res, "notnull_comment");
9192
9202
i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
9193
9203
i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
9194
9204
i_notnull_islocal = PQfnumber(res, "notnull_islocal");
@@ -9257,6 +9267,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9257
9267
tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
9258
9268
tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
9259
9269
tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
9270
+ tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
9260
9271
tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
9261
9272
tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
9262
9273
tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
@@ -9288,11 +9299,14 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9288
9299
determineNotNullFlags(fout, res, r,
9289
9300
tbinfo, j,
9290
9301
i_notnull_name,
9302
+ i_notnull_comment,
9291
9303
i_notnull_invalidoid,
9292
9304
i_notnull_noinherit,
9293
9305
i_notnull_islocal,
9294
9306
&invalidnotnulloids);
9295
9307
9308
+ tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
9309
+ NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
9296
9310
tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9297
9311
tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9298
9312
tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
@@ -9704,8 +9718,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
9704
9718
* 4) The column has a constraint with a known name; in that case
9705
9719
* notnull_constrs carries that name and dumpTableSchema will print
9706
9720
* "CONSTRAINT the_name NOT NULL". However, if the name is the default
9707
- * (table_column_not_null), there's no need to print that name in the dump,
9708
- * so notnull_constrs is set to the empty string and it behaves as case 2.
9721
+ * (table_column_not_null) and there's no comment on the constraint,
9722
+ * there's no need to print that name in the dump, so notnull_constrs
9723
+ * is set to the empty string and it behaves as case 2.
9709
9724
*
9710
9725
* In a child table that inherits from a parent already containing NOT NULL
9711
9726
* constraints and the columns in the child don't have their own NOT NULL
@@ -9732,6 +9747,7 @@ static void
9732
9747
determineNotNullFlags(Archive *fout, PGresult *res, int r,
9733
9748
TableInfo *tbinfo, int j,
9734
9749
int i_notnull_name,
9750
+ int i_notnull_comment,
9735
9751
int i_notnull_invalidoid,
9736
9752
int i_notnull_noinherit,
9737
9753
int i_notnull_islocal,
@@ -9805,11 +9821,13 @@ determineNotNullFlags(Archive *fout, PGresult *res, int r,
9805
9821
{
9806
9822
/*
9807
9823
* In binary upgrade of inheritance child tables, must have a
9808
- * constraint name that we can UPDATE later.
9824
+ * constraint name that we can UPDATE later; same if there's a
9825
+ * comment on the constraint.
9809
9826
*/
9810
- if (dopt->binary_upgrade &&
9811
- !tbinfo->ispartition &&
9812
- !tbinfo->notnull_islocal)
9827
+ if ((dopt->binary_upgrade &&
9828
+ !tbinfo->ispartition &&
9829
+ !tbinfo->notnull_islocal) ||
9830
+ !PQgetisnull(res, r, i_notnull_comment))
9813
9831
{
9814
9832
tbinfo->notnull_constrs[j] =
9815
9833
pstrdup(PQgetvalue(res, r, i_notnull_name));
@@ -17686,6 +17704,56 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
17686
17704
if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17687
17705
dumpTableSecLabel(fout, tbinfo, reltypename);
17688
17706
17707
+ /*
17708
+ * Dump comments for not-null constraints that aren't to be dumped
17709
+ * separately (those are processed by collectComments/dumpComment).
17710
+ */
17711
+ if (!fout->dopt->no_comments && dopt->dumpSchema &&
17712
+ fout->remoteVersion >= 180000)
17713
+ {
17714
+ PQExpBuffer comment = NULL;
17715
+ PQExpBuffer tag = NULL;
17716
+
17717
+ for (j = 0; j < tbinfo->numatts; j++)
17718
+ {
17719
+ if (tbinfo->notnull_constrs[j] != NULL &&
17720
+ tbinfo->notnull_comment[j] != NULL)
17721
+ {
17722
+ if (comment == NULL)
17723
+ {
17724
+ comment = createPQExpBuffer();
17725
+ tag = createPQExpBuffer();
17726
+ }
17727
+ else
17728
+ {
17729
+ resetPQExpBuffer(comment);
17730
+ resetPQExpBuffer(tag);
17731
+ }
17732
+
17733
+ appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
17734
+ fmtId(tbinfo->notnull_constrs[j]), qualrelname);
17735
+ appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
17736
+ appendPQExpBufferStr(comment, ";\n");
17737
+
17738
+ appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
17739
+ fmtId(tbinfo->notnull_constrs[j]), qrelname);
17740
+
17741
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
17742
+ ARCHIVE_OPTS(.tag = tag->data,
17743
+ .namespace = tbinfo->dobj.namespace->dobj.name,
17744
+ .owner = tbinfo->rolname,
17745
+ .description = "COMMENT",
17746
+ .section = SECTION_NONE,
17747
+ .createStmt = comment->data,
17748
+ .deps = &(tbinfo->dobj.dumpId),
17749
+ .nDeps = 1));
17750
+ }
17751
+ }
17752
+
17753
+ destroyPQExpBuffer(comment);
17754
+ destroyPQExpBuffer(tag);
17755
+ }
17756
+
17689
17757
/* Dump comments on inlined table constraints */
17690
17758
for (j = 0; j < tbinfo->ncheck; j++)
17691
17759
{
0 commit comments