On 13/02/2026 10:19, Jim Jones wrote:
> ...
> Example:
> 
> CREATE TABLE t1 (a int);
> COMMENT ON TABLE t1 IS 'comment from table 1';
> CREATE TABLE t2 (b int);
> COMMENT ON TABLE t2 IS 'comment from table 2';
> CREATE TABLE t3 (c int);
> COMMENT ON TABLE t3 IS 'comment from table 3';
> 
> CREATE TABLE tm (
>     LIKE t1 INCLUDING COMMENTS,
>     LIKE t3 INCLUDING COMMENTS,
>     LIKE t2 INCLUDING COMMENTS
> );
> 
> SELECT obj_description('tm'::regclass, 'pg_class') AS table_comment;
>     table_comment
> ----------------------
>  comment from table 1+
>  comment from table 3+
>  comment from table 2
> (1 row)
> 
> 
> Any thoughts on that?

Rebase

Best, Jim
From d61ded2485c69293b21c9b2372363e82b7adbe88 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Thu, 26 Feb 2026 14:11:43 +0100
Subject: [PATCH v3] Add table comments in CREATE TABLE LIKE INCLUDING COMMENTS

When using CREATE TABLE ... LIKE ... INCLUDING COMMENTS (or INCLUDING
ALL), table-level comments were not being copied to the new table, even
though column comments, constraint comments, index comments, and
statistics comments were properly copied. This patch extends the
feature to also copy the table's own comment to the target table.

When multiple LIKE clauses specify INCLUDING COMMENTS and the source
tables have table-level comments, the comments are now concatenated in
the target table, separated by newlines, in the order that the LIKE
clauses appear. This allows users to preserve comment information from
all source tables when creating tables that combine properties from
multiple sources.
---
 doc/src/sgml/ref/create_table.sgml            | 17 ++++--
 src/backend/parser/parse_utilcmd.c            | 59 +++++++++++++++++--
 .../regress/expected/create_table_like.out    | 30 ++++++++++
 src/test/regress/sql/create_table_like.sql    | 21 +++++++
 4 files changed, 116 insertions(+), 11 deletions(-)

diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 982532fe72..483a1b4736 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -672,11 +672,18 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
         <term><literal>INCLUDING COMMENTS</literal></term>
         <listitem>
          <para>
-          Comments for the copied columns, check constraints,
-          not-null constraints, indexes, and extended statistics will be
-          copied.  The default behavior is to exclude comments, resulting in
-          the corresponding objects in the new table having no
-          comments.
+          Comments on the copied columns, check constraints,
+          not-null constraints, indexes, extended statistics, and on the
+          table itself will be copied.  The default behavior is to exclude
+          comments, resulting in the corresponding objects in the new table
+          having no comments.
+         </para>
+         <para>
+          If multiple <literal>LIKE</literal> clauses specify
+          <literal>INCLUDING COMMENTS</literal> and the source tables have
+          table-level comments, these comments will be concatenated in the new
+          table, separated by newlines, in the order that the
+          <literal>LIKE</literal> clauses appear.
          </para>
         </listitem>
        </varlistentry>
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index cc244c49e9..6c21dd093f 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -43,6 +43,7 @@
 #include "commands/comment.h"
 #include "commands/defrem.h"
 #include "commands/sequence.h"
+#include "lib/stringinfo.h"
 #include "commands/tablecmds.h"
 #include "commands/tablespace.h"
 #include "miscadmin.h"
@@ -1307,17 +1308,18 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 	}
 
 	/*
-	 * We cannot yet deal with defaults, CHECK constraints, indexes, or
-	 * statistics, since we don't yet know what column numbers the copied
-	 * columns will have in the finished table.  If any of those options are
-	 * specified, add the LIKE clause to cxt->likeclauses so that
-	 * expandTableLikeClause will be called after we do know that.
+	 * We cannot yet deal with defaults, CHECK constraints, indexes,
+	 * statistics, or table comments, since we don't yet know what column
+	 * numbers the copied columns will have in the finished table.  If any of
+	 * those options are specified, add the LIKE clause to cxt->likeclauses
+	 * so that expandTableLikeClause will be called after we do know that.
 	 *
 	 * In order for this to work, we remember the relation OID so that
 	 * expandTableLikeClause is certain to open the same table.
 	 */
 	if (table_like_clause->options &
-		(CREATE_TABLE_LIKE_DEFAULTS |
+		(CREATE_TABLE_LIKE_COMMENTS |
+		 CREATE_TABLE_LIKE_DEFAULTS |
 		 CREATE_TABLE_LIKE_GENERATED |
 		 CREATE_TABLE_LIKE_CONSTRAINTS |
 		 CREATE_TABLE_LIKE_INDEXES |
@@ -1625,6 +1627,51 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
 		list_free(parent_extstats);
 	}
 
+	/*
+	 * Copy comment on the relation itself, if requested.
+	 */
+	if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
+	{
+		comment = GetComment(RelationGetRelid(relation), RelationRelationId, 0);
+
+		if (comment != NULL)
+		{
+			CommentStmt *stmt;
+			char *existing_comment;
+
+			/*
+			 * Check if the target table already has a comment from a previous
+			 * LIKE clause.  If so, append this comment to it with a newline
+			 * separator.
+			 */
+			existing_comment = GetComment(RelationGetRelid(childrel), RelationRelationId, 0);
+
+			stmt = makeNode(CommentStmt);
+			stmt->objtype = OBJECT_TABLE;
+			if (heapRel->schemaname)
+				stmt->object = (Node *)list_make2(makeString(heapRel->schemaname),
+												  makeString(heapRel->relname));
+			else
+				stmt->object = (Node *)list_make1(makeString(heapRel->relname));
+
+			/* Combine comments if there was a previous one */
+			if (existing_comment != NULL)
+			{
+				StringInfoData buf;
+
+				initStringInfo(&buf);
+				appendStringInfoString(&buf, existing_comment);
+				appendStringInfoChar(&buf, '\n');
+				appendStringInfoString(&buf, comment);
+				stmt->comment = buf.data;
+			}
+			else
+				stmt->comment = comment;
+
+			result = lappend(result, stmt);
+		}
+	}
+
 	/* Done with child rel */
 	table_close(childrel, NoLock);
 
diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index d3c35c1484..e62ccd1ad5 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -341,6 +341,7 @@ 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;
 CREATE INDEX ctlt3_fnidx ON ctlt3 ((a || c));
+COMMENT ON TABLE ctlt3 IS 'ctlt3 table comment';
 COMMENT ON COLUMN ctlt3.a IS 'A3';
 COMMENT ON COLUMN ctlt3.c IS 'C';
 COMMENT ON CONSTRAINT ctlt3_a_check ON ctlt3 IS 't3_a_check';
@@ -449,6 +450,35 @@ SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_con
  t3_a_check
 (1 row)
 
+SELECT obj_description('ctlt13_like'::regclass, 'pg_class') AS table_comment;
+    table_comment    
+---------------------
+ ctlt3 table comment
+(1 row)
+
+-- Test multiple LIKE clauses with table comments
+CREATE TABLE ctlt_comment1 (a int);
+COMMENT ON TABLE ctlt_comment1 IS 'table 1 comment';
+CREATE TABLE ctlt_comment2 (b int);
+COMMENT ON TABLE ctlt_comment2 IS 'table 2 comment';
+CREATE TABLE ctlt_comment3 (c int);
+COMMENT ON TABLE ctlt_comment3 IS 'table 3 comment';
+-- Multiple LIKE clauses should concatenate table comments
+CREATE TABLE ctlt_multi_comments (
+    LIKE ctlt_comment1 INCLUDING COMMENTS,
+    LIKE ctlt_comment3 INCLUDING COMMENTS,
+    LIKE ctlt_comment2 INCLUDING COMMENTS
+);
+-- The order of comments should be the same as the order of LIKE clauses
+SELECT obj_description('ctlt_multi_comments'::regclass, 'pg_class') AS table_comment;
+  table_comment  
+-----------------
+ table 1 comment+
+ table 3 comment+
+ table 2 comment
+(1 row)
+
+DROP TABLE ctlt_comment1, ctlt_comment2, ctlt_comment3, ctlt_multi_comments;
 CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL);
 \d+ ctlt_all
                                 Table "public.ctlt_all"
diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql
index 93389b57db..903c51d062 100644
--- a/src/test/regress/sql/create_table_like.sql
+++ b/src/test/regress/sql/create_table_like.sql
@@ -153,6 +153,7 @@ 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;
 CREATE INDEX ctlt3_fnidx ON ctlt3 ((a || c));
+COMMENT ON TABLE ctlt3 IS 'ctlt3 table comment';
 COMMENT ON COLUMN ctlt3.a IS 'A3';
 COMMENT ON COLUMN ctlt3.c IS 'C';
 COMMENT ON CONSTRAINT ctlt3_a_check ON ctlt3 IS 't3_a_check';
@@ -173,6 +174,26 @@ CREATE TABLE ctlt13_inh () INHERITS (ctlt1, ctlt3);
 CREATE TABLE ctlt13_like (LIKE ctlt3 INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (ctlt1);
 \d+ ctlt13_like
 SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt13_like'::regclass;
+SELECT obj_description('ctlt13_like'::regclass, 'pg_class') AS table_comment;
+
+-- Test multiple LIKE clauses with table comments
+CREATE TABLE ctlt_comment1 (a int);
+COMMENT ON TABLE ctlt_comment1 IS 'table 1 comment';
+CREATE TABLE ctlt_comment2 (b int);
+COMMENT ON TABLE ctlt_comment2 IS 'table 2 comment';
+CREATE TABLE ctlt_comment3 (c int);
+COMMENT ON TABLE ctlt_comment3 IS 'table 3 comment';
+
+
+-- Multiple LIKE clauses should concatenate table comments
+CREATE TABLE ctlt_multi_comments (
+    LIKE ctlt_comment1 INCLUDING COMMENTS,
+    LIKE ctlt_comment3 INCLUDING COMMENTS,
+    LIKE ctlt_comment2 INCLUDING COMMENTS
+);
+-- The order of comments should be the same as the order of LIKE clauses
+SELECT obj_description('ctlt_multi_comments'::regclass, 'pg_class') AS table_comment;
+DROP TABLE ctlt_comment1, ctlt_comment2, ctlt_comment3, ctlt_multi_comments;
 
 CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL);
 \d+ ctlt_all
-- 
2.43.0

Reply via email to