Skip to content

Commit 73f950f

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 9d06da5 commit 73f950f

File tree

4 files changed

+36
-20
lines changed

4 files changed

+36
-20
lines changed

src/backend/commands/analyze.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ static MemoryContext anl_context = NULL;
8282
static BufferAccessStrategy vac_strategy;
8383

8484

85-
static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh);
85+
static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
86+
bool inh, bool in_outer_xact);
8687
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
8788
int samplesize);
8889
static bool BlockSampler_HasMore(BlockSampler bs);
@@ -114,7 +115,8 @@ static bool std_typanalyze(VacAttrStats *stats);
114115
* analyze_rel() -- analyze one relation
115116
*/
116117
void
117-
analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
118+
analyze_rel(Oid relid, VacuumStmt *vacstmt,
119+
bool in_outer_xact, BufferAccessStrategy bstrategy)
118120
{
119121
Relation onerel;
120122

@@ -214,13 +216,13 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
214216
/*
215217
* Do the normal non-recursive ANALYZE.
216218
*/
217-
do_analyze_rel(onerel, vacstmt, false);
219+
do_analyze_rel(onerel, vacstmt, false, in_outer_xact);
218220

219221
/*
220222
* If there are child tables, do recursive ANALYZE.
221223
*/
222224
if (onerel->rd_rel->relhassubclass)
223-
do_analyze_rel(onerel, vacstmt, true);
225+
do_analyze_rel(onerel, vacstmt, true, in_outer_xact);
224226

225227
/*
226228
* Close source relation now, but keep lock so that no one deletes it
@@ -243,7 +245,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
243245
* do_analyze_rel() -- analyze one relation, recursively or not
244246
*/
245247
static void
246-
do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh)
248+
do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
249+
bool inh, bool in_outer_xact)
247250
{
248251
int attr_cnt,
249252
tcnt,
@@ -520,7 +523,10 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh)
520523
if (!inh)
521524
vac_update_relstats(onerel,
522525
RelationGetNumberOfBlocks(onerel),
523-
totalrows, hasindex, InvalidTransactionId);
526+
totalrows,
527+
hasindex,
528+
InvalidTransactionId,
529+
in_outer_xact);
524530

525531
/*
526532
* Same for indexes. Vacuum always scans all indexes, so if we're part of
@@ -537,7 +543,10 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh)
537543
totalindexrows = ceil(thisdata->tupleFract * totalrows);
538544
vac_update_relstats(Irel[ind],
539545
RelationGetNumberOfBlocks(Irel[ind]),
540-
totalindexrows, false, InvalidTransactionId);
546+
totalindexrows,
547+
false,
548+
InvalidTransactionId,
549+
in_outer_xact);
541550
}
542551
}
543552

src/backend/commands/vacuum.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
204204
*/
205205
if (use_own_xacts)
206206
{
207+
Assert(!in_outer_xact);
208+
207209
/* ActiveSnapshot is not set by autovacuum */
208210
if (ActiveSnapshotSet())
209211
PopActiveSnapshot();
@@ -243,7 +245,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
243245
PushActiveSnapshot(GetTransactionSnapshot());
244246
}
245247

246-
analyze_rel(relid, vacstmt, vac_strategy);
248+
analyze_rel(relid, vacstmt, in_outer_xact, vac_strategy);
247249

248250
if (use_own_xacts)
249251
{
@@ -557,20 +559,21 @@ vac_estimate_reltuples(Relation relation, bool is_analyze,
557559
* DDL flags such as relhasindex, by clearing them if no longer correct.
558560
* It's safe to do this in VACUUM, which can't run in parallel with
559561
* CREATE INDEX/RULE/TRIGGER and can't be part of a transaction block.
560-
* However, it's *not* safe to do it in an ANALYZE that's within a
561-
* transaction block, because for example the current transaction might
562+
* However, it's *not* safe to do it in an ANALYZE that's within an
563+
* outer transaction, because for example the current transaction might
562564
* have dropped the last index; then we'd think relhasindex should be
563565
* cleared, but if the transaction later rolls back this would be wrong.
564-
* So we refrain from updating the DDL flags if we're inside a
565-
* transaction block. This is OK since postponing the flag maintenance
566-
* is always allowable.
566+
* So we refrain from updating the DDL flags if we're inside an outer
567+
* transaction. This is OK since postponing the flag maintenance is
568+
* always allowable.
567569
*
568570
* This routine is shared by VACUUM and ANALYZE.
569571
*/
570572
void
571573
vac_update_relstats(Relation relation,
572574
BlockNumber num_pages, double num_tuples,
573-
bool hasindex, TransactionId frozenxid)
575+
bool hasindex, TransactionId frozenxid,
576+
bool in_outer_xact)
574577
{
575578
Oid relid = RelationGetRelid(relation);
576579
Relation rd;
@@ -601,9 +604,9 @@ vac_update_relstats(Relation relation,
601604
dirty = true;
602605
}
603606

604-
/* Apply DDL updates, but not inside a transaction block (see above) */
607+
/* Apply DDL updates, but not inside an outer transaction (see above) */
605608

606-
if (!IsTransactionBlock())
609+
if (!in_outer_xact)
607610
{
608611
/*
609612
* If we didn't find any indexes, reset relhasindex.

src/backend/commands/vacuumlazy.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
266266
vac_update_relstats(onerel,
267267
new_rel_pages, new_rel_tuples,
268268
vacrelstats->hasindex,
269-
new_frozen_xid);
269+
new_frozen_xid,
270+
false);
270271

271272
/* report results to the stats collector, too */
272273
pgstat_report_vacuum(RelationGetRelid(onerel),
@@ -1091,7 +1092,9 @@ lazy_cleanup_index(Relation indrel,
10911092
if (!stats->estimated_count)
10921093
vac_update_relstats(indrel,
10931094
stats->num_pages, stats->num_index_tuples,
1094-
false, InvalidTransactionId);
1095+
false,
1096+
InvalidTransactionId,
1097+
false);
10951098

10961099
ereport(elevel,
10971100
(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
@@ -146,7 +146,8 @@ extern void vac_update_relstats(Relation relation,
146146
BlockNumber num_pages,
147147
double num_tuples,
148148
bool hasindex,
149-
TransactionId frozenxid);
149+
TransactionId frozenxid,
150+
bool in_outer_xact);
150151
extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
151152
bool sharedRel,
152153
TransactionId *oldestXmin,
@@ -161,6 +162,6 @@ extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
161162

162163
/* in commands/analyze.c */
163164
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
164-
BufferAccessStrategy bstrategy);
165+
bool in_outer_xact, BufferAccessStrategy bstrategy);
165166

166167
#endif /* VACUUM_H */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy