From 6ce0366be2a3f92a46202acaba40be3aa72fa073 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 10 Aug 2019 11:30:11 -0400 Subject: [PATCH] Fix "ANALYZE t, t" inside a transaction block. This failed with either "tuple already updated by self" or "duplicate key value violates unique constraint", depending on whether the table had previously been analyzed or not. The reason is that ANALYZE tried to insert or update the same pg_statistic rows twice, and there was no CommandCounterIncrement between. So add one. The same case works fine outside a transaction block, because then there's a whole transaction boundary between, as a consequence of the way VACUUM works. This issue has been latent all along, but the problem was unreachable before commit 11d8d72c2 added the ability to specify multiple tables in ANALYZE. We could, perhaps, alternatively fix it by adding code to de-duplicate the list of VacuumRelations --- but that would add a lot of overhead to work around dumb commands, so it's not attractive. Per bug #15946 from Yaroslav Schekin. Back-patch to v11. (Note: in v11 I also back-patched the test added by commit 23224563d; otherwise the problem doesn't manifest in the test I added, because "vactst" is empty when the tests for multiple ANALYZE targets are reached. That seems like not a very good thing anyway, so I did this rather than rethinking the choice of test case.) Discussion: https://postgr.es/m/15946-5c7570a2884a26cf@postgresql.org --- src/backend/commands/vacuum.c | 9 +++++++++ src/test/regress/expected/vacuum.out | 4 ++++ src/test/regress/sql/vacuum.sql | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index e7b379dfda..ef275c0812 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -418,6 +418,15 @@ vacuum(List *relations, VacuumParams *params, PopActiveSnapshot(); CommitTransactionCommand(); } + else + { + /* + * If we're not using separate xacts, better separate the + * ANALYZE actions with CCIs. This avoids trouble if user + * says "ANALYZE t, t". + */ + CommandCounterIncrement(); + } } } } diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out index 02c53e3058..aff0b10a93 100644 --- a/src/test/regress/expected/vacuum.out +++ b/src/test/regress/expected/vacuum.out @@ -180,6 +180,10 @@ ANALYZE vactst, does_not_exist, vacparted; ERROR: relation "does_not_exist" does not exist ANALYZE vactst (i), vacparted (does_not_exist); ERROR: column "does_not_exist" of relation "vacparted" does not exist +ANALYZE vactst, vactst; +BEGIN; -- ANALYZE behaves differently inside a transaction block +ANALYZE vactst, vactst; +COMMIT; -- parenthesized syntax for ANALYZE ANALYZE (VERBOSE) does_not_exist; ERROR: relation "does_not_exist" does not exist diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql index 6ffb495546..f0fee3af2b 100644 --- a/src/test/regress/sql/vacuum.sql +++ b/src/test/regress/sql/vacuum.sql @@ -147,6 +147,10 @@ ANALYZE vactst, vacparted; ANALYZE vacparted (b), vactst; ANALYZE vactst, does_not_exist, vacparted; ANALYZE vactst (i), vacparted (does_not_exist); +ANALYZE vactst, vactst; +BEGIN; -- ANALYZE behaves differently inside a transaction block +ANALYZE vactst, vactst; +COMMIT; -- parenthesized syntax for ANALYZE ANALYZE (VERBOSE) does_not_exist;