public inbox for [email protected]  
help / color / mirror / Atom feed
From: Julien Tachoires <[email protected]>
To: [email protected]
Subject: Bug in CREATE TABLE .. LIKE .. INCLUDING STATISTICS?
Date: Wed, 15 Apr 2026 12:57:18 +0200
Message-ID: <[email protected]> (raw)

Hi,

One of our customer is experiencing an issue when executing CREATE TABLE
.. LIKE .. INCLUDING ALL; on 14, the following kind of error happens:
ERROR: cache lookup failed for attribute X of relation ZZZZZZ

It seems to come from generateClonedExtStatsStmt(): get_attname()
appears to be called with an attribute number (attnum) that does not
exist.

Please find attached 2 patches for the master branch, the first one adds
a test that triggers the problem, the 2nd one is an attempt to fix it.

Best regards,

-- 
Julien Tachoires


Attachments:

  [text/x-diff] v1-0001-Add-test-for-CTL-.-INCLUDING-STATS.patch (3.4K, 2-v1-0001-Add-test-for-CTL-.-INCLUDING-STATS.patch)
  download | inline diff:
From ff199dee22838be31a1428cec7f983f3f8e16ff6 Mon Sep 17 00:00:00 2001
From: Julien Tachoires <[email protected]>
Date: Wed, 15 Apr 2026 12:35:32 +0200
Subject: [PATCH 1/2] Add test for CTL ... INCLUDING STATS

With the help of this new test we ensure that a table created using
CREATE TABLE ... LIKE ... INCLUDING STATS; will get the statistics
object of the parent properly cloned.
---
 .../regress/expected/create_table_like.out    | 25 +++++++++++++++++++
 src/test/regress/sql/create_table_like.sql    | 21 ++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index 5720d160f05..e6637ee8344 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -698,6 +698,31 @@ SELECT attname, attcompression FROM pg_attribute
  e       | 
 (5 rows)
 
+-- Test CREATE TABLE  ... LIKE ... INCLUDING STATISTICS
+-- When the parent table definitions changed before creating statistics
+CREATE TABLE parent_like_stats (a int, b int, c int);
+ALTER TABLE parent_like_stats DROP COLUMN b;
+CREATE STATISTICS s_parent ON a, c FROM parent_like_stats;
+CREATE TABLE child_like_stats (LIKE parent_like_stats INCLUDING STATISTICS);
+-- Verify what columns the cloned statistics cover: both columns must be 'a'
+-- and 'c'
+SELECT
+  stxname,
+  array_agg(a.attname ORDER BY u.ord) AS stats_columns
+FROM pg_statistic_ext s
+CROSS JOIN LATERAL
+  unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord)
+JOIN pg_attribute a
+  ON a.attrelid = s.stxrelid AND a.attnum = u.attnum
+WHERE s.stxrelid = 'child_like_stats'::regclass
+GROUP BY stxname;
+          stxname          | stats_columns 
+---------------------------+---------------
+ child_like_stats_a_c_stat | {a,c}
+(1 row)
+
+DROP TABLE parent_like_stats CASCADE;
+DROP TABLE child_like_stats;
 DROP TABLE ctl_table;
 DROP FOREIGN TABLE ctl_foreign_table1;
 DROP FOREIGN TABLE ctl_foreign_table2;
diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql
index 93389b57dbf..63fdaab0d2e 100644
--- a/src/test/regress/sql/create_table_like.sql
+++ b/src/test/regress/sql/create_table_like.sql
@@ -276,6 +276,27 @@ CREATE FOREIGN TABLE ctl_foreign_table2(LIKE ctl_table INCLUDING ALL) SERVER ctl
 SELECT attname, attcompression FROM pg_attribute
   WHERE attrelid = 'ctl_foreign_table2'::regclass and attnum > 0 ORDER BY attnum;
 
+-- Test CREATE TABLE  ... LIKE ... INCLUDING STATISTICS
+-- When the parent table definitions changed before creating statistics
+CREATE TABLE parent_like_stats (a int, b int, c int);
+ALTER TABLE parent_like_stats DROP COLUMN b;
+CREATE STATISTICS s_parent ON a, c FROM parent_like_stats;
+CREATE TABLE child_like_stats (LIKE parent_like_stats INCLUDING STATISTICS);
+-- Verify what columns the cloned statistics cover: both columns must be 'a'
+-- and 'c'
+SELECT
+  stxname,
+  array_agg(a.attname ORDER BY u.ord) AS stats_columns
+FROM pg_statistic_ext s
+CROSS JOIN LATERAL
+  unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord)
+JOIN pg_attribute a
+  ON a.attrelid = s.stxrelid AND a.attnum = u.attnum
+WHERE s.stxrelid = 'child_like_stats'::regclass
+GROUP BY stxname;
+DROP TABLE parent_like_stats CASCADE;
+DROP TABLE child_like_stats;
+
 DROP TABLE ctl_table;
 DROP FOREIGN TABLE ctl_foreign_table1;
 DROP FOREIGN TABLE ctl_foreign_table2;
-- 
2.51.2



  [text/x-diff] v1-0002-Fix-attnum-remapping-in-generateClonedExtStatsStmt.patch (1.5K, 3-v1-0002-Fix-attnum-remapping-in-generateClonedExtStatsStmt.patch)
  download | inline diff:
From be743cccfae542dec9ee07918b88be61073ab6ec Mon Sep 17 00:00:00 2001
From: Julien Tachoires <[email protected]>
Date: Wed, 15 Apr 2026 12:46:46 +0200
Subject: [PATCH 2/2] Fix attnum remapping in generateClonedExtStatsStmt()

When cloning extended statistics via CREATE TABLE ... LIKE ... INCLUDING
STATISTICS, stxkeys holds attribute numbers from the source (parent) table,
but get_attname() was being called with the child relation's OID.  If the
parent has dropped columns, the child's attribute numbers are renumbered
sequentially and no longer match, so the lookup either returns the wrong
column name or errors out when the attnum does not exist in the child.

Fix it by remapping the parent attnum through attmap before the lookup,
consistent with how expression statistics are already handled a few lines
below.
---
 src/backend/parser/parse_utilcmd.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 37071502a9f..131f33962b5 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2100,7 +2100,8 @@ generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
 		StatsElem  *selem = makeNode(StatsElem);
 		AttrNumber	attnum = statsrec->stxkeys.values[i];
 
-		selem->name = get_attname(heapRelid, attnum, false);
+		selem->name =
+			get_attname(heapRelid, attmap->attnums[attnum - 1], false);
 		selem->expr = NULL;
 
 		def_names = lappend(def_names, selem);
-- 
2.51.2



reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected]
  Subject: Re: Bug in CREATE TABLE .. LIKE .. INCLUDING STATISTICS?
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox