Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa042ab

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 7da1021 commit fa042ab

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
@@ -104,6 +104,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
104104
volatile bool in_outer_xact,
105105
use_own_xacts;
106106
List *relations;
107+
static bool in_vacuum = false;
107108

108109
/* sanity checks on options */
109110
Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
@@ -129,6 +130,14 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
129130
else
130131
in_outer_xact = IsInTransactionChain(isTopLevel);
131132

133+
/*
134+
* Due to static variables vac_context, anl_context and vac_strategy,
135+
* vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
136+
* calls a hostile index expression that itself calls ANALYZE.
137+
*/
138+
if (in_vacuum)
139+
elog(ERROR, "%s cannot be executed from VACUUM or ANALYZE", stmttype);
140+
132141
/*
133142
* Send info about dead objects to the statistics collector, unless we are
134143
* in autovacuum --- autovacuum.c does this for itself.
@@ -221,6 +230,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
221230
{
222231
ListCell *cur;
223232

233+
in_vacuum = true;
224234
VacuumCostActive = (VacuumCostDelay > 0);
225235
VacuumCostBalance = 0;
226236
VacuumPageHit = 0;
@@ -265,13 +275,13 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
265275
}
266276
PG_CATCH();
267277
{
268-
/* Make sure cost accounting is turned off after error */
278+
in_vacuum = false;
269279
VacuumCostActive = false;
270280
PG_RE_THROW();
271281
}
272282
PG_END_TRY();
273283

274-
/* Turn off vacuum cost accounting */
284+
in_vacuum = false;
275285
VacuumCostActive = false;
276286

277287
/*

src/test/regress/expected/vacuum.out

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,24 @@ VACUUM (FULL, FREEZE) vactst;
6060
VACUUM (ANALYZE, FULL) vactst;
6161
CREATE TABLE vaccluster (i INT PRIMARY KEY);
6262
ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey;
63-
INSERT INTO vaccluster SELECT * FROM vactst;
6463
CLUSTER vaccluster;
64+
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
65+
AS 'ANALYZE pg_am';
66+
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
67+
AS 'SELECT $1 FROM do_analyze()';
68+
CREATE INDEX ON vactst(wrap_do_analyze(i));
69+
INSERT INTO vactst VALUES (1), (2);
70+
ANALYZE vactst;
71+
ERROR: ANALYZE cannot be executed from VACUUM or ANALYZE
72+
CONTEXT: SQL function "do_analyze" statement 1
73+
SQL function "wrap_do_analyze" statement 1
6574
VACUUM FULL pg_am;
6675
VACUUM FULL pg_class;
6776
VACUUM FULL pg_database;
6877
VACUUM FULL vaccluster;
6978
VACUUM FULL vactst;
79+
ERROR: ANALYZE cannot be executed from VACUUM or ANALYZE
80+
CONTEXT: SQL function "do_analyze" statement 1
81+
SQL function "wrap_do_analyze" statement 1
7082
DROP TABLE vaccluster;
7183
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)