diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index b4a597bb83..a0ef3ff140 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3368,6 +3368,7 @@ _copyTableLikeClause(const TableLikeClause *from) COPY_NODE_FIELD(relation); COPY_SCALAR_FIELD(options); + COPY_SCALAR_FIELD(relationOid); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 4f2ebe5118..88e17a3a60 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1252,6 +1252,7 @@ _equalTableLikeClause(const TableLikeClause *a, const TableLikeClause *b) { COMPARE_NODE_FIELD(relation); COMPARE_SCALAR_FIELD(options); + COMPARE_SCALAR_FIELD(relationOid); return true; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index fc75384c07..4a0e461d36 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2746,6 +2746,7 @@ _outTableLikeClause(StringInfo str, const TableLikeClause *node) WRITE_NODE_FIELD(relation); WRITE_UINT_FIELD(options); + WRITE_OID_FIELD(relationOid); } static void diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 32797728d2..9de9dbd8a8 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -3595,6 +3595,7 @@ TableLikeClause: TableLikeClause *n = makeNode(TableLikeClause); n->relation = $2; n->options = $3; + n->relationOid = InvalidOid; $$ = (Node *)n; } ; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index d3ef6f4ab5..577fe1e752 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1091,14 +1091,18 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla * 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. + * called after we do know that. Also, 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_GENERATED | CREATE_TABLE_LIKE_CONSTRAINTS | CREATE_TABLE_LIKE_INDEXES)) + { + table_like_clause->relationOid = RelationGetRelid(relation); cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause); + } /* * We may copy extended statistics if requested, since the representation @@ -1171,9 +1175,13 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause) * Open the relation referenced by the LIKE clause. We should still have * the table lock obtained by transformTableLikeClause (and this'll throw * an assertion failure if not). Hence, no need to recheck privileges - * etc. + * etc. We must open the rel by OID not name, to be sure we get the same + * table. */ - relation = relation_openrv(table_like_clause->relation, NoLock); + if (!OidIsValid(table_like_clause->relationOid)) + elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause"); + + relation = relation_open(table_like_clause->relationOid, NoLock); tupleDesc = RelationGetDescr(relation); constr = tupleDesc->constr; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 439dfea29a..96ad25208c 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -671,6 +671,7 @@ typedef struct TableLikeClause NodeTag type; RangeVar *relation; bits32 options; /* OR of TableLikeOption flags */ + Oid relationOid; /* If table has been looked up, its OID */ } TableLikeClause; typedef enum TableLikeOption diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 59acaf394d..2877436cb4 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -455,6 +455,27 @@ Statistics objects: "public"."pg_attrdef_a_b_stat" (ndistinct, dependencies, mcv) ON a, b FROM public.pg_attrdef DROP TABLE public.pg_attrdef; +-- Check that LIKE isn't confused when new table masks the old, either +BEGIN; +CREATE SCHEMA ctl_schema; +SET LOCAL search_path = ctl_schema, public; +CREATE TABLE ctlt1 (LIKE ctlt1 INCLUDING ALL); +\d+ ctlt1 + Table "ctl_schema.ctlt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | A + b | text | | | | extended | | B +Indexes: + "ctlt1_pkey" PRIMARY KEY, btree (a) + "ctlt1_b_idx" btree (b) + "ctlt1_expr_idx" btree ((a || b)) +Check constraints: + "ctlt1_a_check" CHECK (length(a) > 2) +Statistics objects: + "ctl_schema"."ctlt1_a_b_stat" (ndistinct, dependencies, mcv) ON a, b FROM ctlt1 + +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 /* LIKE with other relation kinds */ diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 00dff231e3..20374c8c66 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -173,6 +173,14 @@ CREATE TABLE pg_attrdef (LIKE ctlt1 INCLUDING ALL); \d+ public.pg_attrdef DROP TABLE public.pg_attrdef; +-- Check that LIKE isn't confused when new table masks the old, either +BEGIN; +CREATE SCHEMA ctl_schema; +SET LOCAL search_path = ctl_schema, public; +CREATE TABLE ctlt1 (LIKE ctlt1 INCLUDING ALL); +\d+ ctlt1 +ROLLBACK; + DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE;