Skip to content

Commit 16799fc

Browse files
author
Commitfest Bot
committed
[CF 4720] "unexpected duplicate for tablespace" problem in logical replication
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/4720 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CAExHW5vaHu=s6eopJ2jxyGNRG--uEsJwYk92yxa2L_80+Y=1YA@mail.gmail.com Author(s): Shenhao Wang
2 parents fa638ed + c03ebd9 commit 16799fc

File tree

8 files changed

+58
-20
lines changed

8 files changed

+58
-20
lines changed

doc/src/sgml/func.sgml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30317,16 +30317,18 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3031730317
<indexterm>
3031830318
<primary>pg_filenode_relation</primary>
3031930319
</indexterm>
30320-
<function>pg_filenode_relation</function> ( <parameter>tablespace</parameter> <type>oid</type>, <parameter>filenode</parameter> <type>oid</type> )
30320+
<function>pg_filenode_relation</function>
30321+
( <parameter>tablespace</parameter> <type>oid</type>,
30322+
<parameter>filenode</parameter> <type>oid</type>)
3032130323
<returnvalue>regclass</returnvalue>
3032230324
</para>
3032330325
<para>
30324-
Returns a relation's OID given the tablespace OID and filenode it is
30325-
stored under. This is essentially the inverse mapping of
30326-
<function>pg_relation_filepath</function>. For a relation in the
30327-
database's default tablespace, the tablespace can be specified as zero.
30328-
Returns <literal>NULL</literal> if no relation in the current database
30329-
is associated with the given values.
30326+
Returns a permanent relation's OID given the tablespace OID and filenode
30327+
it is stored under. This is essentially the inverse mapping of
30328+
<function>pg_relation_filepath</function> only for permanent relations.
30329+
For a relation in the database's default tablespace, the tablespace can
30330+
be specified as zero. Returns <literal>NULL</literal> if no permanent
30331+
relation in the current database is associated with the given values.
3033030332
</para></entry>
3033130333
</row>
3033230334
</tbody>

src/backend/utils/adt/dbsize.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,8 +933,9 @@ pg_relation_filenode(PG_FUNCTION_ARGS)
933933
*
934934
* This is expected to be used when somebody wants to match an individual file
935935
* on the filesystem back to its table. That's not trivially possible via
936-
* pg_class, because that doesn't contain the relfilenumbers of shared and nailed
937-
* tables.
936+
* pg_class, because that doesn't contain the relfilenumbers of shared and
937+
* nailed tables. This function looks up only permanent relations; see
938+
* RelidByRelfilenumber() for reasons.
938939
*
939940
* We don't fail but return NULL if we cannot find a mapping.
940941
*

src/backend/utils/cache/relfilenumbermap.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,21 @@ InitializeRelfilenumberMap(void)
127127
}
128128

129129
/*
130-
* Map a relation's (tablespace, relfilenumber) to a relation's oid and cache
131-
* the result.
130+
* Map a relation's (tablespace, relfilenumber) to a relation's oid and cache the
131+
* result.
132132
*
133-
* Returns InvalidOid if no relation matching the criteria could be found.
133+
* A temporary relation may share its relfilenumber with a permanent relation,
134+
* or other temporary relations. When looking up a permanent relation, this
135+
* function may get confused by temporary relations which have same
136+
* relfilenumber and throw an error. This behaviour may disturb logical
137+
* replication and autoprewarm, both of which lookup permanent relations.
138+
* Further in order to uniquely identify a temporary relation we also need the
139+
* proc number of the backend which created it. The proc number is not available
140+
* to this function. Given the intended use of this function, ignore temporary
141+
* relations.
142+
*
143+
* Returns InvalidOid if no permanent relation matching the criteria could be
144+
* found.
134145
*/
135146
Oid
136147
RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
@@ -208,6 +219,9 @@ RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
208219
{
209220
Form_pg_class classform = (Form_pg_class) GETSTRUCT(ntp);
210221

222+
if (classform->relpersistence == RELPERSISTENCE_TEMP)
223+
continue;
224+
211225
if (found)
212226
elog(ERROR,
213227
"unexpected duplicate for tablespace %u, relfilenumber %u",

src/include/catalog/pg_proc.dat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7775,7 +7775,7 @@
77757775
{ oid => '2999', descr => 'filenode identifier of relation',
77767776
proname => 'pg_relation_filenode', provolatile => 's', prorettype => 'oid',
77777777
proargtypes => 'regclass', prosrc => 'pg_relation_filenode' },
7778-
{ oid => '3454', descr => 'relation OID for filenode and tablespace',
7778+
{ oid => '3454', descr => 'permanent relation OID for filenode and tablespace',
77797779
proname => 'pg_filenode_relation', provolatile => 's',
77807780
prorettype => 'regclass', proargtypes => 'oid oid',
77817781
prosrc => 'pg_filenode_relation' },

src/test/regress/expected/alter_table.out

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3565,14 +3565,17 @@ SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment F
35653565
-- Check that we map relation oids to filenodes and back correctly. Only
35663566
-- display bad mappings so the test output doesn't change all the time. A
35673567
-- filenode function call can return NULL for a relation dropped concurrently
3568-
-- with the call's surrounding query, so ignore a NULL mapped_oid for
3569-
-- relations that no longer exist after all calls finish.
3568+
-- with the call's surrounding query, so ignore a NULL mapped_oid for relations
3569+
-- that no longer exist after all calls finish. The function maps only permanent
3570+
-- relations, so ignore temporary relations.
35703571
CREATE TEMP TABLE filenode_mapping AS
35713572
SELECT
35723573
oid, mapped_oid, reltablespace, relfilenode, relname
35733574
FROM pg_class,
35743575
pg_filenode_relation(reltablespace, pg_relation_filenode(oid)) AS mapped_oid
3575-
WHERE relkind IN ('r', 'i', 'S', 't', 'm') AND mapped_oid IS DISTINCT FROM oid;
3576+
WHERE relkind IN ('r', 'i', 'S', 't', 'm')
3577+
AND relpersistence != 't'
3578+
AND mapped_oid IS DISTINCT FROM oid;
35763579
SELECT m.* FROM filenode_mapping m LEFT JOIN pg_class c ON c.oid = m.oid
35773580
WHERE c.oid IS NOT NULL OR m.mapped_oid IS NOT NULL;
35783581
oid | mapped_oid | reltablespace | relfilenode | relname

src/test/regress/expected/create_table.out

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ ERROR: tables declared WITH OIDS are not supported
102102
-- but explicitly not adding oids is still supported
103103
CREATE TEMP TABLE withoutoid() WITHOUT OIDS; DROP TABLE withoutoid;
104104
CREATE TEMP TABLE withoutoid() WITH (oids = false); DROP TABLE withoutoid;
105+
-- verify that temporary tables data are not retrieved by pg_filenode_relation
106+
CREATE TEMP TABLE filenoderelationcheck(c1 int);
107+
SELECT pg_filenode_relation (reltablespace, pg_relation_filenode(oid)) FROM pg_class
108+
WHERE relname = 'filenoderelationcheck';
109+
pg_filenode_relation
110+
----------------------
111+
112+
(1 row)
113+
114+
DROP TABLE filenoderelationcheck;
105115
-- check restriction with default expressions
106116
-- invalid use of column reference in default expressions
107117
CREATE TABLE default_expr_column (id int DEFAULT (id));

src/test/regress/sql/alter_table.sql

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,15 +2200,17 @@ SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment F
22002200
-- Check that we map relation oids to filenodes and back correctly. Only
22012201
-- display bad mappings so the test output doesn't change all the time. A
22022202
-- filenode function call can return NULL for a relation dropped concurrently
2203-
-- with the call's surrounding query, so ignore a NULL mapped_oid for
2204-
-- relations that no longer exist after all calls finish.
2203+
-- with the call's surrounding query, so ignore a NULL mapped_oid for relations
2204+
-- that no longer exist after all calls finish. The function maps only permanent
2205+
-- relations, so ignore temporary relations.
22052206
CREATE TEMP TABLE filenode_mapping AS
22062207
SELECT
22072208
oid, mapped_oid, reltablespace, relfilenode, relname
22082209
FROM pg_class,
22092210
pg_filenode_relation(reltablespace, pg_relation_filenode(oid)) AS mapped_oid
2210-
WHERE relkind IN ('r', 'i', 'S', 't', 'm') AND mapped_oid IS DISTINCT FROM oid;
2211-
2211+
WHERE relkind IN ('r', 'i', 'S', 't', 'm')
2212+
AND relpersistence != 't'
2213+
AND mapped_oid IS DISTINCT FROM oid;
22122214
SELECT m.* FROM filenode_mapping m LEFT JOIN pg_class c ON c.oid = m.oid
22132215
WHERE c.oid IS NOT NULL OR m.mapped_oid IS NOT NULL;
22142216

src/test/regress/sql/create_table.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ CREATE TABLE withoid() WITH (oids = true);
6868
CREATE TEMP TABLE withoutoid() WITHOUT OIDS; DROP TABLE withoutoid;
6969
CREATE TEMP TABLE withoutoid() WITH (oids = false); DROP TABLE withoutoid;
7070

71+
-- verify that temporary tables data are not retrieved by pg_filenode_relation
72+
CREATE TEMP TABLE filenoderelationcheck(c1 int);
73+
SELECT pg_filenode_relation (reltablespace, pg_relation_filenode(oid)) FROM pg_class
74+
WHERE relname = 'filenoderelationcheck';
75+
DROP TABLE filenoderelationcheck;
76+
7177
-- check restriction with default expressions
7278
-- invalid use of column reference in default expressions
7379
CREATE TABLE default_expr_column (id int DEFAULT (id));

0 commit comments

Comments
 (0)