| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | 303677365(at)qq(dot)com |
| Subject: | BUG #19833: ALTER TABLE that rebuilds an extended statistics object silently drops its SET STATISTICS target (st |
| Date: | 2026-11-05 09:37:25 |
| Message-ID: | 19833-37de35b8f159e62a@postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
The following bug has been logged on the website:
Bug reference: 19833
Logged by: chunling qin
Email address: 303677365(at)qq(dot)com
PostgreSQL version: 18.6
Operating system: Linux x86_64 (official Docker image postgres:lates
Description:
**Description:**
`ALTER TABLE ... ALTER COLUMN TYPE` (and `ALTER COLUMN ... SET EXPRESSION`)
drops and rebuilds extended statistics objects that reference the column.
The rebuild preserves the definition (columns/expressions/kinds), the owner,
and the comment — but silently resets `stxstattarget` (the value set by
`ALTER STATISTICS ... SET STATISTICS N`) to NULL. The next ANALYZE then uses
the default target instead of the user's requested one, degrading the
statistics detail and planner estimates.
Since `pg_dump` dumps `ALTER STATISTICS ... SET STATISTICS N` as a persisted
property, dropping it on an unrelated ALTER TABLE is an inconsistency, and
the owner/comment preservation shows the rebuild path is *meant* to carry
user-visible properties across.
**Reproduction (self-contained SQL, works on the official image):**
```sql
CREATE TABLE st2 (c int, d int);
INSERT INTO st2 SELECT g, g FROM generate_series(1, 1000) g;
CREATE STATISTICS st2_s ON c, (c + 1) FROM st2;
ALTER STATISTICS st2_s SET STATISTICS 250;
ANALYZE st2;
SELECT s.stxstattarget AS target FROM pg_statistic_ext s WHERE s.stxname =
'st2_s';
-- 250
ALTER TABLE st2 ALTER COLUMN c TYPE bigint; -- rebuilds the statistics
object
SELECT s.oid, s.stxstattarget AS target,
obj_description(s.oid, 'pg_statistic_ext') AS comment
FROM pg_statistic_ext s WHERE s.stxname = 'st2_s';
-- new oid, target = NULL, comment = 'keep me' (comment and definition
survive)
-- Control: altering an UNREFERENCED column does not rebuild, target
survives:
ALTER STATISTICS st2_s SET STATISTICS 333;
ALTER TABLE st2 ALTER COLUMN d TYPE bigint;
SELECT s.stxstattarget FROM pg_statistic_ext s WHERE s.stxname = 'st2_s';
-- 333
-- Second trigger: virtual generated column SET EXPRESSION also rebuilds and
drops the target
CREATE TABLE st3 (a int, g int GENERATED ALWAYS AS (a * 2) VIRTUAL);
CREATE STATISTICS st3_s ON g, (a + g) FROM st3;
ALTER STATISTICS st3_s SET STATISTICS 400;
ALTER TABLE st3 ALTER COLUMN g SET EXPRESSION AS (a * 3);
SELECT s.stxstattarget FROM pg_statistic_ext s WHERE s.stxname = 'st3_s';
-- NULL (was 400)
```
**Root cause:** the statistics-object rebuild path in
`src/backend/commands/tablecmds.c` (`RememberStatisticsForRebuilding` and
friends) restores owner and comment but not `stxstattarget`.
**Expected behavior:** the rebuild should preserve `stxstattarget`, the same
way it preserves the owner and the comment.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | PG Bug reporting form | 2026-11-05 09:39:38 | BUG #19834: eager aggregation still evaluates volatile join clauses when the volatile function is inside a SubPl |
| Previous Message | PG Bug reporting form | 2026-11-05 09:32:54 | BUG #19832: convert() between BIG5 and EUC_TW returns different characters than PostgreSQL's own UTF-8 mappings |