]> granicus.if.org Git - postgresql/commitdiff
Give a better error for duplicate entries in VACUUM/ANALYZE column list.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Sep 2017 22:13:11 +0000 (18:13 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Sep 2017 22:13:11 +0000 (18:13 -0400)
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

src/backend/commands/analyze.c
src/test/regress/expected/vacuum.out
src/test/regress/sql/vacuum.sql

index c617abb223b07e2ee430e81861896213f6efdd36..c58f3096e6318dc92642a4fc7d6984b36203a953 100644 (file)
@@ -356,10 +356,14 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params,
        /*
         * Determine which columns to analyze
         *
-        * Note that system attributes are never analyzed.
+        * Note that system attributes are never analyzed, so we just reject them
+        * at the lookup stage.  We also reject duplicate column mentions.  (We
+        * could alternatively ignore duplicates, but analyzing a column twice
+        * won't work; we'd end up making a conflicting update in pg_statistic.)
         */
        if (va_cols != NIL)
        {
+               Bitmapset  *unique_cols = NULL;
                ListCell   *le;
 
                vacattrstats = (VacAttrStats **) palloc(list_length(va_cols) *
@@ -375,6 +379,13 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params,
                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
                                        errmsg("column \"%s\" of relation \"%s\" does not exist",
                                                   col, RelationGetRelationName(onerel))));
+                       if (bms_is_member(i, unique_cols))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_DUPLICATE_COLUMN),
+                                                errmsg("column \"%s\" of relation \"%s\" is specified twice",
+                                                               col, RelationGetRelationName(onerel))));
+                       unique_cols = bms_add_member(unique_cols, i);
+
                        vacattrstats[tcnt] = examine_attribute(onerel, i, NULL);
                        if (vacattrstats[tcnt] != NULL)
                                tcnt++;
index 9b604be4b62e1b472bdc60a31b5c3b19b67f227c..23a877e9ccae40de37e0a5209b7ad80f4daf9c50 100644 (file)
@@ -80,5 +80,10 @@ CONTEXT:  SQL function "do_analyze" statement 1
 SQL function "wrap_do_analyze" statement 1
 VACUUM FULL vactst;
 VACUUM (DISABLE_PAGE_SKIPPING) vaccluster;
+-- check behavior with duplicate column mentions
+VACUUM ANALYZE vaccluster(i,i);
+ERROR:  column "i" of relation "vaccluster" is specified twice
+ANALYZE vaccluster(i,i);
+ERROR:  column "i" of relation "vaccluster" is specified twice
 DROP TABLE vaccluster;
 DROP TABLE vactst;
index 7b819f654ddf51f0a53fb39de0726bc6bbc50d9f..0d35da99871fe255fbc4fc1399c99daa01ce472e 100644 (file)
@@ -62,5 +62,9 @@ VACUUM FULL vactst;
 
 VACUUM (DISABLE_PAGE_SKIPPING) vaccluster;
 
+-- check behavior with duplicate column mentions
+VACUUM ANALYZE vaccluster(i,i);
+ANALYZE vaccluster(i,i);
+
 DROP TABLE vaccluster;
 DROP TABLE vactst;