Skip to content

Commit 6168300

Browse files
committed
Reject ANALYZE commands during VACUUM FULL or another ANALYZE.
vacuum()'s static variable handling makes it non-reentrant; an ensuing null pointer deference crashed the backend. Back-patch to 9.0 (all supported versions).
1 parent d7b16ee commit 6168300

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

src/backend/commands/vacuum.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
9797
volatile bool in_outer_xact,
9898
use_own_xacts;
9999
List *relations;
100+
static bool in_vacuum = false;
100101

101102
/* sanity checks on options */
102103
Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
@@ -122,6 +123,14 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
122123
else
123124
in_outer_xact = IsInTransactionChain(isTopLevel);
124125

126+
/*
127+
* Due to static variables vac_context, anl_context and vac_strategy,
128+
* vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
129+
* calls a hostile index expression that itself calls ANALYZE.
130+
*/
131+
if (in_vacuum)
132+
elog(ERROR, "%s cannot be executed from VACUUM or ANALYZE", stmttype);
133+
125134
/*
126135
* Send info about dead objects to the statistics collector, unless we are
127136
* in autovacuum --- autovacuum.c does this for itself.
@@ -214,6 +223,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
214223
{
215224
ListCell *cur;
216225

226+
in_vacuum = true;
217227
VacuumCostActive = (VacuumCostDelay > 0);
218228
VacuumCostBalance = 0;
219229

@@ -255,13 +265,13 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
255265
}
256266
PG_CATCH();
257267
{
258-
/* Make sure cost accounting is turned off after error */
268+
in_vacuum = false;
259269
VacuumCostActive = false;
260270
PG_RE_THROW();
261271
}
262272
PG_END_TRY();
263273

264-
/* Turn off vacuum cost accounting */
274+
in_vacuum = false;
265275
VacuumCostActive = false;
266276

267277
/*

src/test/regress/expected/vacuum.out

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,24 @@ VACUUM (ANALYZE, FULL) vactst;
6161
CREATE TABLE vaccluster (i INT PRIMARY KEY);
6262
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "vaccluster_pkey" for table "vaccluster"
6363
ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey;
64-
INSERT INTO vaccluster SELECT * FROM vactst;
6564
CLUSTER vaccluster;
65+
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
66+
AS 'ANALYZE pg_am';
67+
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
68+
AS 'SELECT $1 FROM do_analyze()';
69+
CREATE INDEX ON vactst(wrap_do_analyze(i));
70+
INSERT INTO vactst VALUES (1), (2);
71+
ANALYZE vactst;
72+
ERROR: ANALYZE cannot be executed from VACUUM or ANALYZE
73+
CONTEXT: SQL function "do_analyze" statement 1
74+
SQL function "wrap_do_analyze" statement 1
6675
VACUUM FULL pg_am;
6776
VACUUM FULL pg_class;
6877
VACUUM FULL pg_database;
6978
VACUUM FULL vaccluster;
7079
VACUUM FULL vactst;
80+
ERROR: ANALYZE cannot be executed from VACUUM or ANALYZE
81+
CONTEXT: SQL function "do_analyze" statement 1
82+
SQL function "wrap_do_analyze" statement 1
7183
DROP TABLE vaccluster;
7284
DROP TABLE vactst;

src/test/regress/sql/vacuum.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,16 @@ VACUUM (ANALYZE, FULL) vactst;
4444

4545
CREATE TABLE vaccluster (i INT PRIMARY KEY);
4646
ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey;
47-
INSERT INTO vaccluster SELECT * FROM vactst;
4847
CLUSTER vaccluster;
4948

49+
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
50+
AS 'ANALYZE pg_am';
51+
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
52+
AS 'SELECT $1 FROM do_analyze()';
53+
CREATE INDEX ON vactst(wrap_do_analyze(i));
54+
INSERT INTO vactst VALUES (1), (2);
55+
ANALYZE vactst;
56+
5057
VACUUM FULL pg_am;
5158
VACUUM FULL pg_class;
5259
VACUUM FULL pg_database;

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