]> granicus.if.org Git - postgresql/commitdiff
Fix "ANALYZE t, t" inside a transaction block.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 Aug 2019 15:30:11 +0000 (11:30 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 Aug 2019 15:30:11 +0000 (11:30 -0400)
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
src/test/regress/expected/vacuum.out
src/test/regress/sql/vacuum.sql

index 046bb04732109aaa3e410b729df85597de599330..7d6c50b49d9301bbacdbfd280d5633a23cc91c93 100644 (file)
@@ -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();
+                               }
                        }
                }
        }
index 02c53e30589e5b5a3a449e2219d0b66472c44d22..aff0b10a93900deedafaa91a1f25acd61fd0f19f 100644 (file)
@@ -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
index 6ffb495546838dee5fde9e3502d7b7c40b1990cb..f0fee3af2bff13f5229379d9fc15c044adcd2303 100644 (file)
@@ -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;