Subject: COMMENTS are not being copied in CREATE TABLE LIKE

From: Jim Jones <[email-masked]>
Date: Thu, 12 Feb 2026 11:11:58 +0100

Hi,

While reviewing another patch[1] I saw that COMMENTS on tables are being
ignored in CREATE TABLE LIKE:

psql (18.1 (Debian 18.1-1.pgdg13+2))
Type "help" for help.

postgres=# \pset null '(null)'
Null display is "(null)".
postgres=# CREATE TABLE t1 (id int, name text);
COMMENT ON TABLE t1 IS 'table comment';
CREATE TABLE t2 (LIKE t1 INCLUDING ALL);
CREATE TABLE t3 (LIKE t1 INCLUDING COMMENTS);

SELECT
  obj_description('t1'::regclass, 'pg_class') AS t1_comment,
  obj_description('t2'::regclass, 'pg_class') AS t2_comment,
  obj_description('t3'::regclass, 'pg_class') AS t3_comment;
CREATE TABLE
COMMENT
CREATE TABLE
CREATE TABLE
  t1_comment   | t2_comment | t3_comment
---------------+------------+------------
 table comment | (null)     | (null)
(1 row)

v1 attached attempts to fix it by expanding expandTableLikeClause() to
retrieve and copy the table-level comment when the INCLUDING COMMENTS
[ALL] option is specified:

psql (19devel)
Type "help" for help.

postgres=# CREATE TABLE t1 (id int, name text);
COMMENT ON TABLE t1 IS 'table comment';
CREATE TABLE t2 (LIKE t1 INCLUDING ALL);
CREATE TABLE t3 (LIKE t1 INCLUDING COMMENTS);

SELECT
  obj_description('t1'::regclass, 'pg_class') AS t1_comment,
  obj_description('t2'::regclass, 'pg_class') AS t2_comment,
  obj_description('t3'::regclass, 'pg_class') AS t3_comment;
CREATE TABLE
COMMENT
CREATE TABLE
CREATE TABLE
  t1_comment   |  t2_comment   |  t3_comment
---------------+---------------+---------------
 table comment | table comment | table comment
(1 row)

Thoughts?

Best, Jim

1 -
https://www.postgresql.org/message-id/flat/DG7Y34A6VBEG.76L7K1OML5DI%40gmail.com

From 5afdb72e13092a94d01d40dcdc78a96c2632b423 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email-masked]>
Date: Thu, 12 Feb 2026 10:39:25 +0100
Subject: [PATCH v1] Fix missing table-level comment copying in CREATE TABLE
 LIKE

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.
---
 src/backend/parser/parse_utilcmd.c            | 36 +++++++++++++++----
 .../regress/expected/create_table_like.out    |  7 ++++
 src/test/regress/sql/create_table_like.sql    |  2 ++
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index b5f4c72459..bc6c9175a3 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1307,17 +1307,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 +1626,29 @@ 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 = 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));
+			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..765155912f 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,12 @@ 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)
+
 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..0390834186 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,7 @@ 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;
 
 CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL);
 \d+ ctlt_all
-- 
2.43.0

---

From: "Matheus Alcantara" <[email-masked]>
Date: Thu, 12 Feb 2026 11:36:26 -0300

Hi, thanks for checking this.

>   t1_comment   | t2_comment | t3_comment

The patch fix the issue and it seems correct to me.

This bug seems to also happen on 14.20:
postgres=# select version();
                                                           version
------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 14.20 (Homebrew) on aarch64-apple-darwin24.6.0, compiled by Apple clang version 17.0.0 (clang-1700.4.4.1), 64-bit
(1 row)

postgres=# CREATE TABLE t(a int, b text);
CREATE TABLE
postgres=# COMMENT ON TABLE t IS 'foo';
COMMENT
postgres=# CREATE TABLE t2(LIKE t INCLUDING ALL);
CREATE TABLE
postgres=# SELECT obj_description('t'::regclass, 'pg_class') as t_comment, obj_description('t2'::regclass, 'pg_class') AS t2_comment;
 t_comment | t2_comment
-----------+------------
 foo       |
(1 row)

So I think that we need to backport.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

---

From: Fujii Masao <[email-masked]>
Date: Fri, 13 Feb 2026 00:08:16 +0900

> postgres=# select version();

The documentation [1] states that INCLUDING COMMENTS copies comments for
the copied columns, constraints, and indexes. It does not mention copying
comments on the table itself. Therefore, not copying table comments with
INCLUDING COMMENTS does not appear to be a bug. That is, the proposed patch
seems more like an improvement than a bug fix.

Regards,

[1]
https://www.postgresql.org/docs/devel/sql-createtable.html#SQL-CREATETABLE-PARMS-LIKE-OPT-COMMENTS

-- 
Fujii Masao

---

From: Jim Jones <[email-masked]>
Date: Thu, 12 Feb 2026 16:33:59 +0100

>> The patch fix the issue and it seems correct to me.

Thanks for the review!

> seems more like an improvement than a bug fix.

Hmm, it seemed so obvious to me that I didn’t look more closely at the
documentation :) Although I struggle to see the rationale for not
copying a table’s comment in a CREATE TABLE LIKE ... INCLUDING COMMENTS
statement, I have to agree that the documentation is quite clear about
this limitation, and therefore it cannot really be considered a bug.
That said, it may well be worth considering for a future release.

What are your thoughts?

Thanks!

Best, Jim

---

From: Chao Li <[email-masked]>
Date: Fri, 13 Feb 2026 09:29:08 +0800

> On Feb 12, 2026, at 23:33, Jim Jones <[email-masked]> wrote:
> 
> 
> 

I feel the current behavior is proper. When you create a table using LIKE, you are cloning the structure, not the identity. Just as you have to pick a new name for the table, you should provide a new comment that fits its specific purpose. If a comment is needed, the COMMENT ON command is already the straightforward way to handle that.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

---

From: Fujii Masao <[email-masked]>
Date: Fri, 13 Feb 2026 13:13:25 +0900

> That said, it may well be worth considering for a future release.

At first, I felt it would be more intuitive to copy the table comment as well.
However, on second thought, since LIKE can reference multiple tables,
copying table-level properties such as comments may not be well-defined.

For example, if two source tables each have a table comment and both are
specified in LIKE, which comment should be applied to the new table?

Regards,

-- 
Fujii Masao

---

From: "David G. Johnston" <[email-masked]>
Date: Thu, 12 Feb 2026 21:22:38 -0700

> specified in LIKE, which comment should be applied to the new table?

Both, with a new line between them.

David J.

---

From: Tom Lane <[email-masked]>
Date: Thu, 12 Feb 2026 23:30:43 -0500

> I feel the current behavior is proper. When you create a table using
> LIKE, you are cloning the structure, not the identity.

Yeah, I was about to make a similar comment.  We do not for example
clone the ownership or permissions of the source table.  Maybe there
is an argument for cloning the table-level comment but it's by no
means open-and-shut.  So I think the current behavior is intentional
not an oversight.  Might be good to go find the thread in which the
INCLUDING COMMENTS functionality was developed and see if there was
discussion.

(Speaking of which, I'm feeling very dubious about the nearby
proposal to invent LIKE INCLUDING POLICIES.  It's hard to credit
that it makes sense to clone RLS policies while not cloning
table ownership and permissions.  But I suppose I should raise
that point in that thread.)

			regards, tom lane

---

From: Jim Jones <[email-masked]>
Date: Fri, 13 Feb 2026 10:19:59 +0100

Thanks everyone for the comments!

>> LIKE, you are cloning the structure, not the identity.

The concern regarding identity is certainly a valid one, but in this
case I do not see how it applies. Copying the comment would not, IMHO,
transfer the identity of the source table (in a semantic sense), but
would instead merely indicate its provenance.

> INCLUDING COMMENTS functionality was developed and see if there was

I did a bit of digging in the mailing list and found this old thread[1]
where INCLUDING COMMENTS was introduced. I couldn't see anything related
to table-level comments there. Perhaps it was discussed elsewhere?

> Both, with a new line between them.

I supposed we could, as David mentioned, simply concatenate them. How it
should be done can be discussed, but a \n (or two) would IMO work just fine.

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?

Best, Jim

1 -
https://www.postgresql.org/message-id/flat/20090907114058.C855.52131E4D%40oss.ntt.co.jp

From f49b512337b261c2824a4d495af68d39231c367e Mon Sep 17 00:00:00 2001
From: Jim Jones <[email-masked]>
Date: Fri, 13 Feb 2026 09:30:31 +0100
Subject: [PATCH v2] 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            | 15 +++--
 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, 115 insertions(+), 10 deletions(-)

diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 77c5a763d4..223f1eac5c 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -672,10 +672,17 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
         <term><literal>INCLUDING COMMENTS</literal></term>
         <listitem>
          <para>
-          Comments for the copied columns, constraints, and indexes will be
-          copied.  The default behavior is to exclude comments, resulting in
-          the copied columns and constraints in the new table having no
-          comments.
+          Comments for the table itself and for the copied columns,
+          constraints, and indexes will be copied.  The default behavior is to
+          exclude comments, resulting in the new table and its copied columns
+          and constraints having no comments.
+         </para>
+         <para>
+          If multiple <literal>LIKE</literal> clauses specify
+          <literal>INCLUDING COMMENTS</literal> and the source tables have
+          table-level comments, the 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 b5f4c72459..2c247312b9 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
 	}
 
 	/*
@@ -1625,6 +1627,51 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
 
+	/*
+	 * 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);
 
index d3c35c1484..e62ccd1ad5 100644
@@ -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;

---

From: Hüseyin Demir <[email-masked]>
Date: Sun, 22 Feb 2026 08:05:19 +0000

Hi Jim,

I have a couple of concerns about the patch and I wanted to highlight the following cases.

1. Table comments tend to describe the purpose or context of a specific table (e.g. "staging table for pipeline X"), unlike column or constraint comments which describe the schema structure. Copying them by default may be wrong more often than it's right, since the new table almost certainly serves a different purpose than the source.
2. This changes the behavior of INCLUDING ALL, which many users rely on without thinking too carefully about what it pulls in. Silently copying a source table's comment (which might say something like "template — do not use directly") into every derived table could cause confusion in practice.

Neither of these is necessarily a blocker, but I think they're worth discussing before we commit to this as the default behavior under INCLUDING COMMENTS.

Before reviewing the patch for code quality and repo standards, I think we need to decide whether this behavior change is the right approach at all. My preference would be to keep table comments managed separately, given the situations above.

---

From: Jim Jones <[email-masked]>
Date: Sun, 22 Feb 2026 13:34:35 +0100

Hi Hüseyin

> 1. Table comments tend to describe the purpose or context of a specific table (e.g. "staging table for pipeline X"), unlike column or constraint comments which describe the schema structure. Copyin…

Good point. Comments may well lose their semantic value when placed in a
different context, but I'm not sure how it differs from column comments.
A column comment can also refer to a context (original table) that is no
longer applicable after cloning, specially when the CREATE TABLE LIKE
includes multiple tables.

> 2. This changes the behavior of INCLUDING ALL, which many users rely on without thinking too carefully about what it pulls in. Silently copying a source table's comment (which might say something l…

It's also a valid concern - although I see it slightly differently. I we
take this line of reasoning too seriously, we might never be able to
expand CREATE TABLE LIKE, since the ALL keyword would be directly
affected (expanded) in the process. There are also other patches that
aim to expand CREATE TABLE LIKE, e.g. INCLUDING TRIGGERS[1]

> Before reviewing the patch for code quality and repo standards, I think we need to decide whether this behavior change is the right approach at all. My preference would be to keep table comments ma…

Are you suggesting we should simply keep ignoring the table comments? Or
should we manage them differently?

Thanks for the comments. Much appreciated!

Best, Jim

1 - https://commitfest.postgresql.org/patch/6087/

---

From: Hüseyin Demir <[email-masked]>
Date: Thu, 26 Feb 2026 08:46:14 +0100

Hi Jim,

> should we manage them differently?

Yes, because changing the behavior will lead to misinterpretations while
creating tables and tables derived from template ones will be presented
differently with respect to comments they have.

Such changes can cause unexpected different objects inside a database.
For example, any existing script using INCLUDING COMMENTS or INCLUDING ALL
will now copy the table comment where it didn't before.

If we need this behavioral change my idea is to introduce a new sub-option
or keep table comments excluded unless explicitly opted in. Because after
changing the current behavior there is no way to implement old behavior.

Regards.

Jim Jones <[email-masked]>, 22 Şub 2026 Paz, 13:34 tarihinde
şunu yazdı:

> > 1. Table comments tend to describe the purpose or context of a specific
> table (e.g. "staging table for pipeline X"), unlike column or constraint
> comments which describe the schema structure. Copying them by default may
> be wrong more often than it's right, since the new table almost certainly
> serves a different purpose than the source.
>
> > 2. This changes the behavior of INCLUDING ALL, which many users rely on
> without thinking too carefully about what it pulls in. Silently copying a
> source table's comment (which might say something like "template — do not
> use directly") into every derived table could cause confusion in practice.
>
>
> > Before reviewing the patch for code quality and repo standards, I think
> we need to decide whether this behavior change is the right approach at
> all. My preference would be to keep table comments managed separately,
> given the situations above.
>
>

---

From: Jim Jones <[email-masked]>
Date: Thu, 26 Feb 2026 11:07:34 +0100

> differently with respect to comments they have.

But isn't that the case to any feature that we add to CREATE TABLE LIKE?
For instance, if we add INCLUDING TRIGGERS, it will inevitably change
the behaviour of INCLUDING ALL.

> For example, any existing script using INCLUDING COMMENTS or INCLUDING
> ALL will now copy the table comment where it didn't before. 

That's true, the newly created table would then get a comment it didn't
have before. I just fail to see how this would create an unexpected
different object.

Of course, if this script relies on the table not having a comment to
work, it could case some problems.

> If we need this behavioral change my idea is to introduce a new sub-
> option or keep table comments excluded unless explicitly opted in.
> Because after changing the current behavior there is no way to implement
> old behavior. 

The user can always use EXCLUDING COMMENTS for that

CREATE TABLE t2 (
  LIKE t1
    INCLUDING ALL
    EXCLUDING COMMENTS
);

Thanks, Hüseyin!

Best, Jim

---

From: Jim Jones <[email-masked]>
Date: Thu, 26 Feb 2026 14:39:02 +0100

On 13/02/2026 10:19, Jim Jones wrote:
> ...

Rebase

Best, Jim

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

 doc/src/sgml/ref/create_table.sgml            | 17 ++++--
 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
 	}
 
 	/*
 
+	/*

---

From: Carlos Alves <[email-masked]>
Date: Tue, 24 Mar 2026 15:32:21 -0300

> Best, Jim

Hi Jim!

I ran some tests after applying your patch and initially didn't find any
problems. I tried to cover the main scenarios in a focused way, observing
the generated results.

Regarding the possibility of including comments in the table itself using
the LIKE clause, it seems sensible since other elements like columns,
indexes, and constraints have copied comments, as already discussed in the
thread.

Just one point I'd like to address is the documentation. Following the idea
of the other "includings" options wouldn't it be interesting to present a
more concise text? As a suggestion, it could be something like:

"Comments on columns, not null and check constraints, indexes, extended
statistics and the table itself from a source table will be copied. If the
command references multiple source tables with including clauses, any
existing table-level comments will be merged into a single entry, separated
by newlines in the order they were specified."

I've attached some preliminary tests I performed.

Thank you in advance for your attention.

---

From: Jim Jones <[email-masked]>
Date: Wed, 25 Mar 2026 10:21:56 +0100

Hi Carlos

On 24/03/2026 19:32, Carlos Alves wrote:
> Just one point I'd like to address is the documentation. Following the
> idea of the other "includings" options wouldn't it be interesting to
> present a more concise text? As a suggestion, it could be something like:
> 
> statistics and the table itself from a source table will be copied. If
> the command references multiple source tables with including clauses,
> any existing table-level comments will be merged into a single entry,
> separated by newlines in the order they were specified."

In the second paragraph of the INCLUDING COMMENTS docs I wrote:

<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>

Which pretty much states the same? Please let me know if I am missing
your point here.

> I've attached some preliminary tests I performed.

Thanks for the thorough tests. Much appreciated!

Best, Jim

---

From: Carlos Alves <[email-masked]>
Date: Wed, 25 Mar 2026 10:59:21 -0300

Hi Jim!

I saw the second paragraph that you wrote and the explanations are perfect!

My suggestion was instead of describing it in two paragraphs, try
describing the parameter in just one (and the text I sent was just a
suggestion).

But your document is perfect for me! It was just to simplify, as in the
description of the other parameters.

Sincerely, Carlos

---

From: Jim Jones <[email-masked]>
Date: Thu, 26 Mar 2026 19:12:04 +0100

Hi Carlos

On 26/03/2026 18:59, Carlos Alves wrote:
> No errors or failures were detected during the tests.
> 
> The only suggestion is to keep the parameter description a single paragraph, following the same style as the description of the other inclusion parameters. But the current description is coherent and okay.
> 
> After the tests, the patch is working as expected:
> - Table-level comments are copied when the `including comments` parameter is used.
> - When there is more than one source table, comments, if any, are kept in the order in which they appear in the command, separated by a new line.
> - The performance of command execution was not affected.
> 
> I think only the code review is missing, but I don't have much experience to perform this step.

Thanks for this thorough review. This helps a lot!
Let's see what the other reviewers have to say about the code and your
docs suggestion.

Best, Jim