aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-12-07 12:12:00 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2018-12-07 12:12:00 -0500
commit54f24ab76dedb69c03fe4b271c7f53a351637df3 (patch)
treebb3a87ea9152d849f99956e4d163dae3712ee964 /src
parentaaf7b3bd6f715078867092e7e95c94a1e4222646 (diff)
downloadpostgresql-54f24ab76dedb69c03fe4b271c7f53a351637df3.tar.gz
postgresql-54f24ab76dedb69c03fe4b271c7f53a351637df3.zip
Fix misapplication of pgstat_count_truncate to wrong relation.
The stanza of ExecuteTruncate[Guts] that truncates a target table's toast relation re-used the loop local variable "rel" to reference the toast rel. This was safe enough when written, but commit d42358efb added code below that that supposed "rel" still pointed to the parent table. Therefore, the stats counter update was applied to the wrong relcache entry (the toast rel not the user rel); and if we were unlucky and that relcache entry had been flushed during reindex_relation, very bad things could ensue. (I'm surprised that CLOBBER_CACHE_ALWAYS testing hasn't found this. I'm even more surprised that the problem wasn't detected during the development of d42358efb; it must not have been tested in any case with a toast table, as the incorrect stats counts are very obvious.) To fix, replace use of "rel" in that code branch with a more local variable. Adjust test cases added by d42358efb so that some of them use tables with toast tables. Per bug #15540 from Pan Bian. Back-patch to 9.5 where d42358efb came in. Discussion: https://postgr.es/m/15540-01078812338195c0@postgresql.org
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c15
-rw-r--r--src/test/regress/expected/stats.out4
-rw-r--r--src/test/regress/sql/stats.sql4
3 files changed, 13 insertions, 10 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 9e52945ca41..4dfa4a4c49c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1427,19 +1427,22 @@ ExecuteTruncate(TruncateStmt *stmt)
heap_create_init_fork(rel);
heap_relid = RelationGetRelid(rel);
- toast_relid = rel->rd_rel->reltoastrelid;
/*
* The same for the toast table, if any.
*/
+ toast_relid = rel->rd_rel->reltoastrelid;
if (OidIsValid(toast_relid))
{
- rel = relation_open(toast_relid, AccessExclusiveLock);
- RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
+ Relation toastrel = relation_open(toast_relid,
+ AccessExclusiveLock);
+
+ RelationSetNewRelfilenode(toastrel,
+ toastrel->rd_rel->relpersistence,
RecentXmin, minmulti);
- if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
- heap_create_init_fork(rel);
- heap_close(rel, NoLock);
+ if (toastrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+ heap_create_init_fork(toastrel);
+ heap_close(toastrel, NoLock);
}
/*
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index fc91f3ce365..ab6ec7db367 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -79,9 +79,9 @@ end
$$ language plpgsql;
-- test effects of TRUNCATE on n_live_tup/n_dead_tup counters
CREATE TABLE trunc_stats_test(id serial);
-CREATE TABLE trunc_stats_test1(id serial);
+CREATE TABLE trunc_stats_test1(id serial, stuff text);
CREATE TABLE trunc_stats_test2(id serial);
-CREATE TABLE trunc_stats_test3(id serial);
+CREATE TABLE trunc_stats_test3(id serial, stuff text);
CREATE TABLE trunc_stats_test4(id serial);
-- check that n_live_tup is reset to 0 after truncate
INSERT INTO trunc_stats_test DEFAULT VALUES;
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 6e882bf3aca..a4e47d011a9 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -79,9 +79,9 @@ $$ language plpgsql;
-- test effects of TRUNCATE on n_live_tup/n_dead_tup counters
CREATE TABLE trunc_stats_test(id serial);
-CREATE TABLE trunc_stats_test1(id serial);
+CREATE TABLE trunc_stats_test1(id serial, stuff text);
CREATE TABLE trunc_stats_test2(id serial);
-CREATE TABLE trunc_stats_test3(id serial);
+CREATE TABLE trunc_stats_test3(id serial, stuff text);
CREATE TABLE trunc_stats_test4(id serial);
-- check that n_live_tup is reset to 0 after truncate