Make CREATE TABLE LIKE copy comments on NOT NULL constraints when requested.
authorFujii Masao <fujii@postgresql.org>
Thu, 26 Jun 2025 11:25:34 +0000 (20:25 +0900)
committerFujii Masao <fujii@postgresql.org>
Thu, 26 Jun 2025 11:25:34 +0000 (20:25 +0900)
Commit 14e87ffa5c5 introduced support for adding comments to NOT NULL
constraints. However, CREATE TABLE LIKE INCLUDING COMMENTS did not copy
these comments to the new table. This was an oversight in that commit.

This commit corrects the behavior by ensuring CREATE TABLE LIKE to also copy
the comments on NOT NULL constraints when INCLUDING COMMENTS is specified.

Author: Jian He <jian.universality@gmail.com>
Co-authored-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/127debef-e558-4784-9e24-0d5eaf91e2d1@oss.nttdata.com

src/backend/parser/parse_utilcmd.c
src/test/regress/expected/create_table_like.out
src/test/regress/sql/create_table_like.sql

index 62015431fdf1ae7a342360a2a9450886d0d2770a..afcf54169c3b3f1ace029cc436642efe04ab5a11 100644 (file)
@@ -1279,6 +1279,28 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
        lst = RelationGetNotNullConstraints(RelationGetRelid(relation), false,
                                            true);
        cxt->nnconstraints = list_concat(cxt->nnconstraints, lst);
+
+       /* Copy comments on not-null constraints */
+       if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
+       {
+           foreach_node(Constraint, nnconstr, lst)
+           {
+               if ((comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
+                                                                     nnconstr->conname, false),
+                                         ConstraintRelationId,
+                                         0)) != NULL)
+               {
+                   CommentStmt *stmt = makeNode(CommentStmt);
+
+                   stmt->objtype = OBJECT_TABCONSTRAINT;
+                   stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
+                                                      makeString(cxt->relation->relname),
+                                                      makeString(nnconstr->conname));
+                   stmt->comment = comment;
+                   cxt->alist = lappend(cxt->alist, stmt);
+               }
+           }
+       }
    }
 
    /*
index bf34289e9842bd2119995e32c576faa4e9ddaaad..29a779c2e9072ac89ceb09c92386ba3771f8ac24 100644 (file)
@@ -332,9 +332,10 @@ COMMENT ON CONSTRAINT ctlt1_a_check ON ctlt1 IS 't1_a_check';
 COMMENT ON INDEX ctlt1_pkey IS 'index pkey';
 COMMENT ON INDEX ctlt1_b_key IS 'index b_key';
 ALTER TABLE ctlt1 ALTER COLUMN a SET STORAGE MAIN;
-CREATE TABLE ctlt2 (c text);
+CREATE TABLE ctlt2 (c text NOT NULL);
 ALTER TABLE ctlt2 ALTER COLUMN c SET STORAGE EXTERNAL;
 COMMENT ON COLUMN ctlt2.c IS 'C';
+COMMENT ON CONSTRAINT ctlt2_c_not_null ON ctlt2 IS 't2_c_not_null';
 CREATE TABLE ctlt3 (a text CHECK (length(a) < 5), c text CHECK (length(c) < 7));
 ALTER TABLE ctlt3 ALTER COLUMN c SET STORAGE EXTERNAL;
 ALTER TABLE ctlt3 ALTER COLUMN a SET STORAGE MAIN;
@@ -351,9 +352,10 @@ CREATE TABLE ctlt12_storage (LIKE ctlt1 INCLUDING STORAGE, LIKE ctlt2 INCLUDING
 --------+------+-----------+----------+---------+----------+--------------+-------------
  a      | text |           | not null |         | main     |              | 
  b      | text |           |          |         | extended |              | 
- c      | text |           |          |         | external |              | 
+ c      | text |           | not null |         | external |              | 
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
+    "ctlt2_c_not_null" NOT NULL "c"
 
 CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDING COMMENTS);
 \d+ ctlt12_comments
@@ -362,9 +364,16 @@ CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDIN
 --------+------+-----------+----------+---------+----------+--------------+-------------
  a      | text |           | not null |         | extended |              | A
  b      | text |           |          |         | extended |              | B
- c      | text |           |          |         | extended |              | C
+ c      | text |           | not null |         | extended |              | C
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
+    "ctlt2_c_not_null" NOT NULL "c"
+
+SELECT conname, description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt12_comments'::regclass;
+     conname      |  description  
+------------------+---------------
+ ctlt2_c_not_null | t2_c_not_null
+(1 row)
 
 CREATE TABLE ctlt1_inh (LIKE ctlt1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (ctlt1);
 NOTICE:  merging column "a" with inherited definition
@@ -529,7 +538,9 @@ NOTICE:  drop cascades to table inhe
 -- LIKE must respect NO INHERIT property of constraints
 CREATE TABLE noinh_con_copy (a int CHECK (a > 0) NO INHERIT, b int not null,
    c int not null no inherit);
-CREATE TABLE noinh_con_copy1 (LIKE noinh_con_copy INCLUDING CONSTRAINTS);
+COMMENT ON CONSTRAINT noinh_con_copy_b_not_null ON noinh_con_copy IS 'not null b';
+COMMENT ON CONSTRAINT noinh_con_copy_c_not_null ON noinh_con_copy IS 'not null c no inherit';
+CREATE TABLE noinh_con_copy1 (LIKE noinh_con_copy INCLUDING CONSTRAINTS INCLUDING COMMENTS);
 \d+ noinh_con_copy1
                               Table "public.noinh_con_copy1"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -543,6 +554,17 @@ Not-null constraints:
     "noinh_con_copy_b_not_null" NOT NULL "b"
     "noinh_con_copy_c_not_null" NOT NULL "c" NO INHERIT
 
+SELECT conname, description
+FROM  pg_description, pg_constraint c
+WHERE classoid = 'pg_constraint'::regclass
+AND   objoid = c.oid AND c.conrelid = 'noinh_con_copy1'::regclass
+ORDER BY conname COLLATE "C";
+          conname          |      description      
+---------------------------+-----------------------
+ noinh_con_copy_b_not_null | not null b
+ noinh_con_copy_c_not_null | not null c no inherit
+(2 rows)
+
 -- fail, as partitioned tables don't allow NO INHERIT constraints
 CREATE TABLE noinh_con_copy1_parted (LIKE noinh_con_copy INCLUDING ALL)
   PARTITION BY LIST (a);
index 6e21722aaeb95b21491af93e064753127dd98b46..bf8702116a74b4f5f6ee52f73cd6f5af2eac850e 100644 (file)
@@ -143,9 +143,10 @@ COMMENT ON INDEX ctlt1_pkey IS 'index pkey';
 COMMENT ON INDEX ctlt1_b_key IS 'index b_key';
 ALTER TABLE ctlt1 ALTER COLUMN a SET STORAGE MAIN;
 
-CREATE TABLE ctlt2 (c text);
+CREATE TABLE ctlt2 (c text NOT NULL);
 ALTER TABLE ctlt2 ALTER COLUMN c SET STORAGE EXTERNAL;
 COMMENT ON COLUMN ctlt2.c IS 'C';
+COMMENT ON CONSTRAINT ctlt2_c_not_null ON ctlt2 IS 't2_c_not_null';
 
 CREATE TABLE ctlt3 (a text CHECK (length(a) < 5), c text CHECK (length(c) < 7));
 ALTER TABLE ctlt3 ALTER COLUMN c SET STORAGE EXTERNAL;
@@ -162,6 +163,7 @@ CREATE TABLE ctlt12_storage (LIKE ctlt1 INCLUDING STORAGE, LIKE ctlt2 INCLUDING
 \d+ ctlt12_storage
 CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDING COMMENTS);
 \d+ ctlt12_comments
+SELECT conname, description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt12_comments'::regclass;
 CREATE TABLE ctlt1_inh (LIKE ctlt1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (ctlt1);
 \d+ ctlt1_inh
 SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt1_inh'::regclass;
@@ -197,9 +199,19 @@ DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_in
 -- LIKE must respect NO INHERIT property of constraints
 CREATE TABLE noinh_con_copy (a int CHECK (a > 0) NO INHERIT, b int not null,
    c int not null no inherit);
-CREATE TABLE noinh_con_copy1 (LIKE noinh_con_copy INCLUDING CONSTRAINTS);
+
+COMMENT ON CONSTRAINT noinh_con_copy_b_not_null ON noinh_con_copy IS 'not null b';
+COMMENT ON CONSTRAINT noinh_con_copy_c_not_null ON noinh_con_copy IS 'not null c no inherit';
+
+CREATE TABLE noinh_con_copy1 (LIKE noinh_con_copy INCLUDING CONSTRAINTS INCLUDING COMMENTS);
 \d+ noinh_con_copy1
 
+SELECT conname, description
+FROM  pg_description, pg_constraint c
+WHERE classoid = 'pg_constraint'::regclass
+AND   objoid = c.oid AND c.conrelid = 'noinh_con_copy1'::regclass
+ORDER BY conname COLLATE "C";
+
 -- fail, as partitioned tables don't allow NO INHERIT constraints
 CREATE TABLE noinh_con_copy1_parted (LIKE noinh_con_copy INCLUDING ALL)
   PARTITION BY LIST (a);