Skip to content

Commit 38cb868

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 40058fb commit 38cb868

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
@@ -85,7 +85,7 @@ static BufferAccessStrategy vac_strategy;
8585

8686
static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
8787
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
88-
bool inh, int elevel);
88+
bool inh, bool in_outer_xact, int elevel);
8989
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
9090
int samplesize);
9191
static bool BlockSampler_HasMore(BlockSampler bs);
@@ -113,7 +113,8 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
113113
* analyze_rel() -- analyze one relation
114114
*/
115115
void
116-
analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
116+
analyze_rel(Oid relid, VacuumStmt *vacstmt,
117+
bool in_outer_xact, BufferAccessStrategy bstrategy)
117118
{
118119
Relation onerel;
119120
int elevel;
@@ -262,13 +263,15 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
262263
/*
263264
* Do the normal non-recursive ANALYZE.
264265
*/
265-
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, false, elevel);
266+
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
267+
false, in_outer_xact, elevel);
266268

267269
/*
268270
* If there are child tables, do recursive ANALYZE.
269271
*/
270272
if (onerel->rd_rel->relhassubclass)
271-
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, true, elevel);
273+
do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
274+
true, in_outer_xact, elevel);
272275

273276
/*
274277
* Close source relation now, but keep lock so that no one deletes it
@@ -298,7 +301,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
298301
static void
299302
do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
300303
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
301-
bool inh, int elevel)
304+
bool inh, bool in_outer_xact, int elevel)
302305
{
303306
int attr_cnt,
304307
tcnt,
@@ -580,7 +583,8 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
580583
totalrows,
581584
visibilitymap_count(onerel),
582585
hasindex,
583-
InvalidTransactionId);
586+
InvalidTransactionId,
587+
in_outer_xact);
584588

585589
/*
586590
* Same for indexes. Vacuum always scans all indexes, so if we're part of
@@ -600,7 +604,8 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
600604
totalindexrows,
601605
0,
602606
false,
603-
InvalidTransactionId);
607+
InvalidTransactionId,
608+
in_outer_xact);
604609
}
605610
}
606611

src/backend/commands/vacuum.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
199199
*/
200200
if (use_own_xacts)
201201
{
202+
Assert(!in_outer_xact);
203+
202204
/* ActiveSnapshot is not set by autovacuum */
203205
if (ActiveSnapshotSet())
204206
PopActiveSnapshot();
@@ -244,7 +246,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
244246
PushActiveSnapshot(GetTransactionSnapshot());
245247
}
246248

247-
analyze_rel(relid, vacstmt, vac_strategy);
249+
analyze_rel(relid, vacstmt, in_outer_xact, vac_strategy);
248250

249251
if (use_own_xacts)
250252
{
@@ -567,21 +569,22 @@ vac_estimate_reltuples(Relation relation, bool is_analyze,
567569
* DDL flags such as relhasindex, by clearing them if no longer correct.
568570
* It's safe to do this in VACUUM, which can't run in parallel with
569571
* CREATE INDEX/RULE/TRIGGER and can't be part of a transaction block.
570-
* However, it's *not* safe to do it in an ANALYZE that's within a
571-
* transaction block, because for example the current transaction might
572+
* However, it's *not* safe to do it in an ANALYZE that's within an
573+
* outer transaction, because for example the current transaction might
572574
* have dropped the last index; then we'd think relhasindex should be
573575
* cleared, but if the transaction later rolls back this would be wrong.
574-
* So we refrain from updating the DDL flags if we're inside a
575-
* transaction block. This is OK since postponing the flag maintenance
576-
* is always allowable.
576+
* So we refrain from updating the DDL flags if we're inside an outer
577+
* transaction. This is OK since postponing the flag maintenance is
578+
* always allowable.
577579
*
578580
* This routine is shared by VACUUM and ANALYZE.
579581
*/
580582
void
581583
vac_update_relstats(Relation relation,
582584
BlockNumber num_pages, double num_tuples,
583585
BlockNumber num_all_visible_pages,
584-
bool hasindex, TransactionId frozenxid)
586+
bool hasindex, TransactionId frozenxid,
587+
bool in_outer_xact)
585588
{
586589
Oid relid = RelationGetRelid(relation);
587590
Relation rd;
@@ -617,9 +620,9 @@ vac_update_relstats(Relation relation,
617620
dirty = true;
618621
}
619622

620-
/* Apply DDL updates, but not inside a transaction block (see above) */
623+
/* Apply DDL updates, but not inside an outer transaction (see above) */
621624

622-
if (!IsTransactionBlock())
625+
if (!in_outer_xact)
623626
{
624627
/*
625628
* 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
@@ -284,7 +284,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
284284
new_rel_tuples,
285285
new_rel_allvisible,
286286
vacrelstats->hasindex,
287-
new_frozen_xid);
287+
new_frozen_xid,
288+
false);
288289

289290
/* report results to the stats collector, too */
290291
pgstat_report_vacuum(RelationGetRelid(onerel),
@@ -1283,7 +1284,8 @@ lazy_cleanup_index(Relation indrel,
12831284
stats->num_index_tuples,
12841285
0,
12851286
false,
1286-
InvalidTransactionId);
1287+
InvalidTransactionId,
1288+
false);
12871289

12881290
ereport(elevel,
12891291
(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
@@ -153,7 +153,8 @@ extern void vac_update_relstats(Relation relation,
153153
double num_tuples,
154154
BlockNumber num_all_visible_pages,
155155
bool hasindex,
156-
TransactionId frozenxid);
156+
TransactionId frozenxid,
157+
bool in_outer_xact);
157158
extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
158159
bool sharedRel,
159160
TransactionId *oldestXmin,
@@ -168,7 +169,7 @@ extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
168169

169170
/* in commands/analyze.c */
170171
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
171-
BufferAccessStrategy bstrategy);
172+
bool in_outer_xact, BufferAccessStrategy bstrategy);
172173
extern bool std_typanalyze(VacAttrStats *stats);
173174
extern double anl_random_fract(void);
174175
extern double anl_init_selection_state(int n);

0 commit comments

Comments
 (0)