Skip to content

Commit e65b550

Browse files
committed
Test IsInTransactionChain, not IsTransactionBlock, in vac_update_relstats.
As noted by Noah Misch, my initial cut at fixing bug #11638 didn't cover all cases where ANALYZE might be invoked in an unsafe context. We need to test the result of IsInTransactionChain not IsTransactionBlock; which is notationally a pain because IsInTransactionChain requires an isTopLevel flag, which would have to be passed down through several levels of callers. I chose to pass in_outer_xact (ie, the result of IsInTransactionChain) rather than isTopLevel per se, as that seemed marginally more apropos for the intermediate functions to know about.
1 parent 81f0a5e commit e65b550

File tree

4 files changed

+31
-20
lines changed

4 files changed

+31
-20
lines changed

src/backend/commands/analyze.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static BufferAccessStrategy vac_strategy;
8686

8787
static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
8888
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
89-
bool inh, int elevel);
89+
bool inh, bool in_outer_xact, int elevel);
9090
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
9191
int samplesize);
9292
static bool BlockSampler_HasMore(BlockSampler bs);
@@ -114,7 +114,8 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
114114
* analyze_rel() -- analyze one relation
115115
*/
116116
void
117-
analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
117+
analyze_rel(Oid relid, VacuumStmt *vacstmt,
118+
bool in_outer_xact, BufferAccessStrategy bstrategy)
118119
{
119120
Relation onerel;
120121
int elevel;
@@ -264,13 +265,15 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
264265
/*
265266
* Do the normal non-recursive ANALYZE.
266267
*/
267-
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, false, elevel);
268+
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
269+
false, in_outer_xact, elevel);
268270

269271
/*
270272
* If there are child tables, do recursive ANALYZE.
271273
*/
272274
if (onerel->rd_rel->relhassubclass)
273-
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, true, elevel);
275+
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
276+
true, in_outer_xact, elevel);
274277

275278
/*
276279
* Close source relation now, but keep lock so that no one deletes it
@@ -300,7 +303,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
300303
static void
301304
do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
302305
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
303-
bool inh, int elevel)
306+
bool inh, bool in_outer_xact, int elevel)
304307
{
305308
int attr_cnt,
306309
tcnt,
@@ -583,7 +586,8 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
583586
visibilitymap_count(onerel),
584587
hasindex,
585588
InvalidTransactionId,
586-
InvalidMultiXactId);
589+
InvalidMultiXactId,
590+
in_outer_xact);
587591

588592
/*
589593
* Same for indexes. Vacuum always scans all indexes, so if we're part of
@@ -604,7 +608,8 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
604608
0,
605609
false,
606610
InvalidTransactionId,
607-
InvalidMultiXactId);
611+
InvalidMultiXactId,
612+
in_outer_xact);
608613
}
609614
}
610615

src/backend/commands/vacuum.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
206206
*/
207207
if (use_own_xacts)
208208
{
209+
Assert(!in_outer_xact);
210+
209211
/* ActiveSnapshot is not set by autovacuum */
210212
if (ActiveSnapshotSet())
211213
PopActiveSnapshot();
@@ -251,7 +253,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
251253
PushActiveSnapshot(GetTransactionSnapshot());
252254
}
253255

254-
analyze_rel(relid, vacstmt, vac_strategy);
256+
analyze_rel(relid, vacstmt, in_outer_xact, vac_strategy);
255257

256258
if (use_own_xacts)
257259
{
@@ -665,13 +667,13 @@ vac_estimate_reltuples(Relation relation, bool is_analyze,
665667
* DDL flags such as relhasindex, by clearing them if no longer correct.
666668
* It's safe to do this in VACUUM, which can't run in parallel with
667669
* CREATE INDEX/RULE/TRIGGER and can't be part of a transaction block.
668-
* However, it's *not* safe to do it in an ANALYZE that's within a
669-
* transaction block, because for example the current transaction might
670+
* However, it's *not* safe to do it in an ANALYZE that's within an
671+
* outer transaction, because for example the current transaction might
670672
* have dropped the last index; then we'd think relhasindex should be
671673
* cleared, but if the transaction later rolls back this would be wrong.
672-
* So we refrain from updating the DDL flags if we're inside a
673-
* transaction block. This is OK since postponing the flag maintenance
674-
* is always allowable.
674+
* So we refrain from updating the DDL flags if we're inside an outer
675+
* transaction. This is OK since postponing the flag maintenance is
676+
* always allowable.
675677
*
676678
* This routine is shared by VACUUM and ANALYZE.
677679
*/
@@ -680,7 +682,8 @@ vac_update_relstats(Relation relation,
680682
BlockNumber num_pages, double num_tuples,
681683
BlockNumber num_all_visible_pages,
682684
bool hasindex, TransactionId frozenxid,
683-
MultiXactId minmulti)
685+
MultiXactId minmulti,
686+
bool in_outer_xact)
684687
{
685688
Oid relid = RelationGetRelid(relation);
686689
Relation rd;
@@ -716,9 +719,9 @@ vac_update_relstats(Relation relation,
716719
dirty = true;
717720
}
718721

719-
/* Apply DDL updates, but not inside a transaction block (see above) */
722+
/* Apply DDL updates, but not inside an outer transaction (see above) */
720723

721-
if (!IsTransactionBlock())
724+
if (!in_outer_xact)
722725
{
723726
/*
724727
* If we didn't find any indexes, reset relhasindex.

src/backend/commands/vacuumlazy.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
306306
new_rel_allvisible,
307307
vacrelstats->hasindex,
308308
new_frozen_xid,
309-
new_min_multi);
309+
new_min_multi,
310+
false);
310311

311312
/* report results to the stats collector, too */
312313
pgstat_report_vacuum(RelationGetRelid(onerel),
@@ -1370,7 +1371,8 @@ lazy_cleanup_index(Relation indrel,
13701371
0,
13711372
false,
13721373
InvalidTransactionId,
1373-
InvalidMultiXactId);
1374+
InvalidMultiXactId,
1375+
false);
13741376

13751377
ereport(elevel,
13761378
(errmsg("index \"%s\" now contains %.0f row versions in %u pages",

src/include/commands/vacuum.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ extern void vac_update_relstats(Relation relation,
156156
BlockNumber num_all_visible_pages,
157157
bool hasindex,
158158
TransactionId frozenxid,
159-
MultiXactId minmulti);
159+
MultiXactId minmulti,
160+
bool in_outer_xact);
160161
extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
161162
int multixact_freeze_min_age,
162163
int multixact_freeze_table_age,
@@ -175,7 +176,7 @@ extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
175176

176177
/* in commands/analyze.c */
177178
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
178-
BufferAccessStrategy bstrategy);
179+
bool in_outer_xact, BufferAccessStrategy bstrategy);
179180
extern bool std_typanalyze(VacAttrStats *stats);
180181
extern double anl_random_fract(void);
181182
extern double anl_init_selection_state(int n);

0 commit comments

Comments
 (0)