Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wD17k-002WTe-1Y for pgsql-bugs@arkaria.postgresql.org; Wed, 15 Apr 2026 14:21:49 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wD17e-00HLNO-31 for pgsql-bugs@arkaria.postgresql.org; Wed, 15 Apr 2026 14:21:43 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wD12y-00GWET-2q for pgsql-bugs@lists.postgresql.org; Wed, 15 Apr 2026 14:16:53 +0000 Received: from relay5-d.mail.gandi.net ([2001:4b98:dc4:8::225]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wCxvx-00000001CNc-3VE4 for pgsql-bugs@lists.postgresql.org; Wed, 15 Apr 2026 10:57:28 +0000 Received: by mail.gandi.net (Postfix) with ESMTPSA id 4DCBC3EBFD for ; Wed, 15 Apr 2026 10:57:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tachoires.me; s=gm1; t=1776250639; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=XJn1i2ZrF3j5/bhkbV+wyJruQVZMC21VRbgzFpMPTHU=; b=FtHbIQEqia7ujsk/lKEdy4M5LHB8w3QWHNb1EjS5ud9Nqb26ZOE632SlXUytl+8SP6jcvk VnafNJqY3v2VF8XbCZ8eMSJTwtEAxpxhjLkdicLkGuIPNOKnBpha5IGeOhe9eYDVnvU9Xi EjMLvnPmnbjQm1z2ZEjTWy2RTEnrLSWbb+JNR5nkxEyB7Vehc0Qiqx2L+SPP/9JG9zQ4QJ 6w4B/TZd5XM2MnTHowiFceosnzB7zbDBBziFqlvKHdI+Ws4384lZYWQbpESW48y0HF+nY9 13dhSkl9E+VANxmjGVWhIfioDJH/BZmXJJ1+2A9teeNj9g7QqAzrP2HpbcI4/g== Date: Wed, 15 Apr 2026 12:57:18 +0200 From: Julien Tachoires To: pgsql-bugs@lists.postgresql.org Subject: Bug in CREATE TABLE .. LIKE .. INCLUDING STATISTICS? Message-ID: <20260415105718.tomuncfbmlt67oel@poseidon.home.virt> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="ly2yk5uozlo3oxwh" Content-Disposition: inline X-GND-Sasl: julien@tachoires.me X-GND-State: clean X-GND-Score: 0 X-GND-Cause: dmFkZTGmd7zxUEXvGim9YX1Ut/qprQKNwVr4LVrilvWZQi7pXCM1fhsO094JcDCQW52bzYzFChswwaZVNOiRBA5hcTm2QWpbtQCeA9TnpCMwCeSPdd9LP6/EVctNeBFwDYq6Fo7IDM8pedFszg+2rhOK0cqLbdw2TL/jAszo42kegBzW0iypAIP/T9jZd4kQEfyRfhCZJZcUGcczxB7X9hfvf1PezX/T5j4gyYJ5Dr0HfhIkMEjyf1spJUw/kO9RBjsD3ritMg3DcfQPX8YIrEYwShDEeKSn0UspsaVgBf0owTr0z6L5TH7AleqOEWMcnkm4RkEOosjxDFZ2FdyLI6jb/1VJSy+Q+aFw7gspDl7xAFdEecppU3gJRWzMbSNX7uUjV15WM/hKfhcr7AewaHzi9x+auaJcXXXoyB4ls+8VJKpgydoMy/20veLFB+0x0sGOem6ev1T+z2gmuWqfF1cA6++dVibjZGDgSnjTU4grXfs4qw1XHL81FdmexXwATVODT3/A8Y/bTuIjWL6QzvUFvi22nVDqsHxqn006RqyshbP0JaQgpwTyhgCMclplOYaxUII4KvDsKLOvyxgVAdATH8f7jTFk170VGPV1RWgkNaUrTJnTRcBdvplkBH1Ni0U+3TRSzRoPAhQqB+hrgUrfR3OcPuj8sTHZwIbf5WIJbAVl+w List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --ly2yk5uozlo3oxwh Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 --ly2yk5uozlo3oxwh Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v1-0001-Add-test-for-CTL-.-INCLUDING-STATS.patch" From ff199dee22838be31a1428cec7f983f3f8e16ff6 Mon Sep 17 00:00:00 2001 From: Julien Tachoires 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 --ly2yk5uozlo3oxwh Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v1-0002-Fix-attnum-remapping-in-generateClonedExtStatsStmt.patch" From be743cccfae542dec9ee07918b88be61073ab6ec Mon Sep 17 00:00:00 2001 From: Julien Tachoires 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 --ly2yk5uozlo3oxwh--