From 38ee6063302aa178117243ffbaaa3a9342402e15 Mon Sep 17 00:00:00 2001
From: Jim Jones <jim.jones@uni-muenster.de>
Date: Thu, 29 Oct 2026 20:11:28 +0100
Subject: [PATCH v2] Fix copied comments landing on wrong table in CREATE TEMP
 TABLE LIKE

transformCreateStmt() schema-qualifies the target name so that the
commands generated after the table is created cannot find a different
table of the same name earlier in search_path.  Temp tables were
exempted, on the theory that the RangeVar's relpersistence is enough.
But the CommentStmts generated by LIKE ... INCLUDING COMMENTS identify
the table by a name list, which loses relpersistence.  So with pg_temp
listed explicitly after another schema containing a table of the same
name, the copied column and constraint comments were applied to that
other table, or the command failed if it had no matching constraint.

Fix by qualifying temp table names too, using the actual temp schema
name.

Author: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Reviewed-by: Koshi Shibagaki <shibagaki.koshi@fujitsu.com>
Reviewed-by: Salma El-Sayed <salmasayed182003@gmail.com>
---
 src/backend/parser/parse_utilcmd.c            | 10 ++++---
 .../regress/expected/create_table_like.out    | 29 +++++++++++++++++++
 src/test/regress/sql/create_table_like.sql    | 18 ++++++++++++
 3 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 583346bf531..846be02f194 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -222,11 +222,13 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	 * If the target relation name isn't schema-qualified, make it so.  This
 	 * prevents some corner cases in which added-on rewritten commands might
 	 * think they should apply to other relations that have the same name and
-	 * are earlier in the search path.  But a local temp table is effectively
-	 * specified to be in pg_temp, so no need for anything extra in that case.
+	 * are earlier in the search path.  This applies to temp tables too: the
+	 * RangeVar's relpersistence suffices for commands that look the table up
+	 * via the RangeVar itself, but not for those that identify it by a name
+	 * list, such as the COMMENT commands generated for LIKE ... INCLUDING
+	 * COMMENTS.
 	 */
-	if (stmt->relation->schemaname == NULL
-		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
+	if (stmt->relation->schemaname == NULL)
 		stmt->relation->schemaname = get_namespace_name(namespaceid);
 
 	/* Set up CreateStmtContext */
diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index 0deba8b6ac4..c2f1e0f7bda 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -544,6 +544,35 @@ Statistics objects:
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
 
+ROLLBACK;
+-- Check that copied comments go to a new temp table, not to a same-named
+-- permanent table that precedes pg_temp in the search path
+BEGIN;
+SET LOCAL search_path = public, pg_temp;
+CREATE TABLE ctlt_src (a int NOT NULL CONSTRAINT ctlt_src_a_check CHECK (a > 0));
+COMMENT ON COLUMN ctlt_src.a IS 'src column';
+COMMENT ON CONSTRAINT ctlt_src_a_not_null ON ctlt_src IS 'src not-null';
+COMMENT ON CONSTRAINT ctlt_src_a_check ON ctlt_src IS 'src check';
+CREATE TABLE ctlt_temp (a int);
+COMMENT ON COLUMN ctlt_temp.a IS 'unrelated column';
+CREATE TEMP TABLE ctlt_temp (LIKE ctlt_src INCLUDING COMMENTS INCLUDING CONSTRAINTS);
+SELECT relpersistence, col_description(oid, 1) AS column_comment
+FROM pg_class WHERE relname = 'ctlt_temp' ORDER BY 1;
+ relpersistence |  column_comment  
+----------------+------------------
+ p              | unrelated column
+ t              | src column
+(2 rows)
+
+SELECT c.relpersistence, con.conname, obj_description(con.oid, 'pg_constraint')
+FROM pg_constraint con JOIN pg_class c ON c.oid = con.conrelid
+WHERE c.relname = 'ctlt_temp' ORDER BY 1, 2;
+ relpersistence |       conname       | obj_description 
+----------------+---------------------+-----------------
+ t              | ctlt_src_a_check    | src check
+ t              | ctlt_src_a_not_null | src not-null
+(2 rows)
+
 ROLLBACK;
 DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE;
 NOTICE:  drop cascades to table inhe
diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql
index 5dd81f4eaf9..e975349297c 100644
--- a/src/test/regress/sql/create_table_like.sql
+++ b/src/test/regress/sql/create_table_like.sql
@@ -195,6 +195,24 @@ CREATE TABLE ctlt1 (LIKE ctlt1 INCLUDING ALL);
 \d+ ctlt1
 ROLLBACK;
 
+-- Check that copied comments go to a new temp table, not to a same-named
+-- permanent table that precedes pg_temp in the search path
+BEGIN;
+SET LOCAL search_path = public, pg_temp;
+CREATE TABLE ctlt_src (a int NOT NULL CONSTRAINT ctlt_src_a_check CHECK (a > 0));
+COMMENT ON COLUMN ctlt_src.a IS 'src column';
+COMMENT ON CONSTRAINT ctlt_src_a_not_null ON ctlt_src IS 'src not-null';
+COMMENT ON CONSTRAINT ctlt_src_a_check ON ctlt_src IS 'src check';
+CREATE TABLE ctlt_temp (a int);
+COMMENT ON COLUMN ctlt_temp.a IS 'unrelated column';
+CREATE TEMP TABLE ctlt_temp (LIKE ctlt_src INCLUDING COMMENTS INCLUDING CONSTRAINTS);
+SELECT relpersistence, col_description(oid, 1) AS column_comment
+FROM pg_class WHERE relname = 'ctlt_temp' ORDER BY 1;
+SELECT c.relpersistence, con.conname, obj_description(con.oid, 'pg_constraint')
+FROM pg_constraint con JOIN pg_class c ON c.oid = con.conrelid
+WHERE c.relname = 'ctlt_temp' ORDER BY 1, 2;
+ROLLBACK;
+
 DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE;
 
 -- LIKE must respect NO INHERIT property of constraints
-- 
2.56.0

