Avoid corrupting tables when ANALYZE inside a transaction is rolled back

Enterprise / PostgreSQL - Tom Lane [sss.pgh.pa.us] - 29 October 2014 17:12 UTC

VACUUM and ANALYZE update the target table's pg_class row in-place, that is nontransactionally. This is OK, more or less, for the statistical columns, which are mostly nontransactional anyhow. It's not so OK for the DDL hint flags (relhasindex etc), which might get changed in response to transactional changes that could still be rolled back. This isn't a problem for VACUUM, since it can't be run inside a transaction block nor in parallel with DDL on the table. However, we allow ANALYZE inside a transaction block, so if the transaction had earlier removed the last index, rule, or trigger from the table, and then we roll back the transaction after ANALYZE, the table would be left in a corrupted state with the hint flags not set though they should be.

To fix, suppress the hint-flag updates if we are InTransactionBlock(). This is safe enough because it's always OK to postpone hint maintenance some more; the worst-case consequence is a few extra searches of pg_index et al. There was discussion of instead using a transactional update, but that would change the behavior in ways that are not all desirable: in most scenarios we're better off keeping ANALYZE's statistical values even if the ANALYZE itself rolls back. In any case we probably don't want to change this behavior in back branches.

Per bug #11638 from Casey Shobe. This has been broken for a good long time, so back-patch to all supported branches.

Tom Lane and Michael Paquier, initial diagnosis by Andres Freund

e0722d9 Avoid corrupting tables when ANALYZE inside a transaction is rolled back.
src/backend/commands/vacuum.c | 91 +++++++++++++++++------------
src/test/regress/expected/alter_table.out | 17 ++++++
src/test/regress/sql/alter_table.sql | 10 ++++
3 files changed, 81 insertions(+), 37 deletions(-)

Upstream: git.postgresql.org


  • Share