Skip to content

Commit e56facd

Browse files
committed
Give a better error for duplicate entries in VACUUM/ANALYZE column list.
Previously, the code didn't think about this case and would just try to analyze such a column twice. That would fail at the point of inserting the second version of the pg_statistic row, with obscure error messsages like "duplicate key value violates unique constraint" or "tuple already updated by self", depending on context and PG version. We could allow the case by ignoring duplicate column specifications, but it seems better to reject it explicitly. The bogus error messages seem like arguably a bug, so back-patch to all supported versions. Nathan Bossart, per a report from Michael Paquier, and whacked around a bit by me. Discussion: https://postgr.es/m/E061A8E3-5E3D-494D-94F0-E8A9B312BBFC@amazon.com
1 parent 4cd6cd2 commit e56facd

File tree

3 files changed

+21
-1
lines changed

3 files changed

+21
-1
lines changed

src/backend/commands/analyze.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,14 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
367367
/*
368368
* Determine which columns to analyze
369369
*
370-
* Note that system attributes are never analyzed.
370+
* Note that system attributes are never analyzed, so we just reject them
371+
* at the lookup stage. We also reject duplicate column mentions. (We
372+
* could alternatively ignore duplicates, but analyzing a column twice
373+
* won't work; we'd end up making a conflicting update in pg_statistic.)
371374
*/
372375
if (vacstmt->va_cols != NIL)
373376
{
377+
Bitmapset *unique_cols = NULL;
374378
ListCell *le;
375379

376380
vacattrstats = (VacAttrStats **) palloc(list_length(vacstmt->va_cols) *
@@ -386,6 +390,13 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
386390
(errcode(ERRCODE_UNDEFINED_COLUMN),
387391
errmsg("column \"%s\" of relation \"%s\" does not exist",
388392
col, RelationGetRelationName(onerel))));
393+
if (bms_is_member(i, unique_cols))
394+
ereport(ERROR,
395+
(errcode(ERRCODE_DUPLICATE_COLUMN),
396+
errmsg("column \"%s\" of relation \"%s\" is specified twice",
397+
col, RelationGetRelationName(onerel))));
398+
unique_cols = bms_add_member(unique_cols, i);
399+
389400
vacattrstats[tcnt] = examine_attribute(onerel, i, NULL);
390401
if (vacattrstats[tcnt] != NULL)
391402
tcnt++;

src/test/regress/expected/vacuum.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,10 @@ ERROR: ANALYZE cannot be executed from VACUUM or ANALYZE
8080
CONTEXT: SQL function "do_analyze" statement 1
8181
SQL function "wrap_do_analyze" statement 1
8282
VACUUM FULL vactst;
83+
-- check behavior with duplicate column mentions
84+
VACUUM ANALYZE vaccluster(i,i);
85+
ERROR: column "i" of relation "vaccluster" is specified twice
86+
ANALYZE vaccluster(i,i);
87+
ERROR: column "i" of relation "vaccluster" is specified twice
8388
DROP TABLE vaccluster;
8489
DROP TABLE vactst;

src/test/regress/sql/vacuum.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,9 @@ VACUUM FULL pg_database;
6060
VACUUM FULL vaccluster;
6161
VACUUM FULL vactst;
6262

63+
-- check behavior with duplicate column mentions
64+
VACUUM ANALYZE vaccluster(i,i);
65+
ANALYZE vaccluster(i,i);
66+
6367
DROP TABLE vaccluster;
6468
DROP TABLE vactst;

0 commit comments

Comments
 (0)