Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8e18d04

Browse files
committed
Refine our definition of what constitutes a system relation.
Although user-defined relations can't be directly created inpg_catalog, it's possible for them to end up there, because you cancreate them in some other schema and then use ALTER TABLE .. SET SCHEMAto move them there. Previously, such relations couldn't afterwardsbe manipulated, because IsSystemRelation()/IsSystemClass() rejectedall attempts to modify objects in the pg_catalog schema, regardlessof their origin. With this patch, they now reject only thoseobjects in pg_catalog which were created at initdb-time, allowingmost operations on user-created tables in pg_catalog to proceednormally.This patch also adds new functions IsCatalogRelation() andIsCatalogClass(), which is similar to IsSystemRelation() andIsSystemClass() but with a slightly narrower definition: only TOASTtables of system catalogs are included, rather than *all* TOAST tables.This is currently used only for making decisions about wheninvalidation messages need to be sent, but upcoming logical decodingpatches will find other uses for this information.Andres Freund, with some modifications by me.
1 parent2fe69ca commit8e18d04

File tree

15 files changed

+149
-31
lines changed

15 files changed

+149
-31
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2465,7 +2465,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
24652465
* because the heaptuples data structure is all in local memory, not in
24662466
* the shared buffer.
24672467
*/
2468-
if (IsSystemRelation(relation))
2468+
if (IsCatalogRelation(relation))
24692469
{
24702470
for (i=0;i<ntuples;i++)
24712471
CacheInvalidateHeapTuple(relation,heaptuples[i],NULL);

‎src/backend/catalog/aclchk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3628,7 +3628,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
36283628
* themselves.ACL_USAGE is if we ever have system sequences.
36293629
*/
36303630
if ((mask& (ACL_INSERT |ACL_UPDATE |ACL_DELETE |ACL_TRUNCATE |ACL_USAGE))&&
3631-
IsSystemClass(classForm)&&
3631+
IsSystemClass(table_oid,classForm)&&
36323632
classForm->relkind!=RELKIND_VIEW&&
36333633
!has_rolcatupdate(roleid)&&
36343634
!allowSystemTableMods)

‎src/backend/catalog/catalog.c

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,22 +97,20 @@ GetDatabasePath(Oid dbNode, Oid spcNode)
9797

9898
/*
9999
* IsSystemRelation
100-
*True iff the relation is a system catalog relation.
100+
*True iff the relation is either a system catalog or toast table.
101+
*By a system catalog, we mean one that created in the pg_catalog schema
102+
* during initdb. User-created relations in pg_catalog don't count as
103+
*system catalogs.
101104
*
102105
*NB: TOAST relations are considered system relations by this test
103106
*for compatibility with the old IsSystemRelationName function.
104107
*This is appropriate in many places but not all. Where it's not,
105-
*also check IsToastRelation.
106-
*
107-
*We now just test if the relation is in the system catalog namespace;
108-
*so it's no longer necessary to forbid user relations from having
109-
*names starting with pg_.
108+
*also check IsToastRelation or use IsCatalogRelation().
110109
*/
111110
bool
112111
IsSystemRelation(Relationrelation)
113112
{
114-
returnIsSystemNamespace(RelationGetNamespace(relation))||
115-
IsToastNamespace(RelationGetNamespace(relation));
113+
returnIsSystemClass(RelationGetRelid(relation),relation->rd_rel);
116114
}
117115

118116
/*
@@ -122,12 +120,60 @@ IsSystemRelation(Relation relation)
122120
*search pg_class directly.
123121
*/
124122
bool
125-
IsSystemClass(Form_pg_classreltuple)
123+
IsSystemClass(Oidrelid,Form_pg_classreltuple)
126124
{
127-
Oidrelnamespace=reltuple->relnamespace;
125+
returnIsToastClass(reltuple)||IsCatalogClass(relid,reltuple);
126+
}
127+
128+
/*
129+
* IsCatalogRelation
130+
*True iff the relation is a system catalog, or the toast table for
131+
*a system catalog. By a system catalog, we mean one that created
132+
*in the pg_catalog schema during initdb. As with IsSystemRelation(),
133+
*user-created relations in pg_catalog don't count as system catalogs.
134+
*
135+
*Note that IsSystemRelation() returns true for ALL toast relations,
136+
*but this function returns true only for toast relations of system
137+
*catalogs.
138+
*/
139+
bool
140+
IsCatalogRelation(Relationrelation)
141+
{
142+
returnIsCatalogClass(RelationGetRelid(relation),relation->rd_rel);
143+
}
128144

129-
returnIsSystemNamespace(relnamespace)||
130-
IsToastNamespace(relnamespace);
145+
/*
146+
* IsCatalogClass
147+
*True iff the relation is a system catalog relation.
148+
*
149+
* Check IsCatalogRelation() for details.
150+
*/
151+
bool
152+
IsCatalogClass(Oidrelid,Form_pg_classreltuple)
153+
{
154+
Oidrelnamespace=reltuple->relnamespace;
155+
156+
/*
157+
* Never consider relations outside pg_catalog/pg_toast to be catalog
158+
* relations.
159+
*/
160+
if (!IsSystemNamespace(relnamespace)&& !IsToastNamespace(relnamespace))
161+
return false;
162+
163+
/* ----
164+
* Check whether the oid was assigned during initdb, when creating the
165+
* initial template database. Minus the relations in information_schema
166+
* excluded above, these are integral part of the system.
167+
* We could instead check whether the relation is pinned in pg_depend, but
168+
* this is noticeably cheaper and doesn't require catalog access.
169+
*
170+
* This test is safe since even a oid wraparound will preserve this
171+
* property (c.f. GetNewObjectId()) and it has the advantage that it works
172+
* correctly even if a user decides to create a relation in the pg_catalog
173+
* namespace.
174+
* ----
175+
*/
176+
returnrelid<FirstNormalObjectId;
131177
}
132178

133179
/*

‎src/backend/catalog/heap.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,17 @@ heap_create(const char *relname,
256256
Assert(OidIsValid(relid));
257257

258258
/*
259-
* sanity checks
259+
* Don't allow creating relations in pg_catalog directly, even though it
260+
* is allowed to move user defined relations there. Semantics with search
261+
* paths including pg_catalog are too confusing for now.
262+
*
263+
* But allow creating indexes on relations in pg_catalog even if
264+
* allow_system_table_mods = off, upper layers already guarantee it's on a
265+
* user defined relation, not a system one.
260266
*/
261267
if (!allow_system_table_mods&&
262-
(IsSystemNamespace(relnamespace)||IsToastNamespace(relnamespace))&&
268+
((IsSystemNamespace(relnamespace)&&relkind!=RELKIND_INDEX)||
269+
IsToastNamespace(relnamespace))&&
263270
IsNormalProcessingMode())
264271
ereport(ERROR,
265272
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

‎src/backend/commands/cluster.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
13541354
* ones the dependency changes would change. It's too late to be
13551355
* making any data changes to the target catalog.
13561356
*/
1357-
if (IsSystemClass(relform1))
1357+
if (IsSystemClass(r1,relform1))
13581358
elog(ERROR,"cannot swap toast files by links for system catalogs");
13591359

13601360
/* Delete old dependencies */

‎src/backend/commands/indexcmds.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
18241824
while ((tuple=heap_getnext(scan,ForwardScanDirection))!=NULL)
18251825
{
18261826
Form_pg_classclasstuple= (Form_pg_class)GETSTRUCT(tuple);
1827+
Oidrelid=HeapTupleGetOid(tuple);
18271828

18281829
if (classtuple->relkind!=RELKIND_RELATION&&
18291830
classtuple->relkind!=RELKIND_MATVIEW)
@@ -1835,7 +1836,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
18351836
continue;
18361837

18371838
/* Check user/system classification, and optionally skip */
1838-
if (IsSystemClass(classtuple))
1839+
if (IsSystemClass(relid,classtuple))
18391840
{
18401841
if (!do_system)
18411842
continue;
@@ -1850,7 +1851,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
18501851
continue;/* got it already */
18511852

18521853
old=MemoryContextSwitchTo(private_context);
1853-
relids=lappend_oid(relids,HeapTupleGetOid(tuple));
1854+
relids=lappend_oid(relids,relid);
18541855
MemoryContextSwitchTo(old);
18551856
}
18561857
heap_endscan(scan);

‎src/backend/commands/tablecmds.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
910910
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_CLASS,
911911
rel->relname);
912912

913-
if (!allowSystemTableMods&&IsSystemClass(classform))
913+
if (!allowSystemTableMods&&IsSystemClass(relOid,classform))
914914
ereport(ERROR,
915915
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
916916
errmsg("permission denied: \"%s\" is a system catalog",
@@ -2105,7 +2105,7 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
21052105
if (!pg_class_ownercheck(myrelid,GetUserId()))
21062106
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_CLASS,
21072107
NameStr(classform->relname));
2108-
if (!allowSystemTableMods&&IsSystemClass(classform))
2108+
if (!allowSystemTableMods&&IsSystemClass(myrelid,classform))
21092109
ereport(ERROR,
21102110
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
21112111
errmsg("permission denied: \"%s\" is a system catalog",
@@ -10872,7 +10872,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
1087210872
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_CLASS,rv->relname);
1087310873

1087410874
/* No system table modifications unless explicitly allowed. */
10875-
if (!allowSystemTableMods&&IsSystemClass(classform))
10875+
if (!allowSystemTableMods&&IsSystemClass(relid,classform))
1087610876
ereport(ERROR,
1087710877
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1087810878
errmsg("permission denied: \"%s\" is a system catalog",

‎src/backend/commands/trigger.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
11741174
/* you must own the table to rename one of its triggers */
11751175
if (!pg_class_ownercheck(relid,GetUserId()))
11761176
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_CLASS,rv->relname);
1177-
if (!allowSystemTableMods&&IsSystemClass(form))
1177+
if (!allowSystemTableMods&&IsSystemClass(relid,form))
11781178
ereport(ERROR,
11791179
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
11801180
errmsg("permission denied: \"%s\" is a system catalog",

‎src/backend/optimizer/util/plancat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
128128
* Don't bother with indexes for an inheritance parent, either.
129129
*/
130130
if (inhparent||
131-
(IgnoreSystemIndexes&&IsSystemClass(relation->rd_rel)))
131+
(IgnoreSystemIndexes&&IsSystemRelation(relation)))
132132
hasindex= false;
133133
else
134134
hasindex=relation->rd_rel->relhasindex;

‎src/backend/rewrite/rewriteDefine.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
858858
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
859859
errmsg("\"%s\" is not a table or view",rv->relname)));
860860

861-
if (!allowSystemTableMods&&IsSystemClass(form))
861+
if (!allowSystemTableMods&&IsSystemClass(relid,form))
862862
ereport(ERROR,
863863
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
864864
errmsg("permission denied: \"%s\" is a system catalog",

‎src/backend/tcop/utility.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
110110
if (noCatalogs)
111111
{
112112
if (!allowSystemTableMods&&
113-
IsSystemClass((Form_pg_class)GETSTRUCT(tuple)))
113+
IsSystemClass(relOid,(Form_pg_class)GETSTRUCT(tuple)))
114114
ereport(ERROR,
115115
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
116116
errmsg("permission denied: \"%s\" is a system catalog",

‎src/backend/utils/cache/inval.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,15 +1040,15 @@ CacheInvalidateHeapTuple(Relation relation,
10401040

10411041
/*
10421042
* We only need to worry about invalidation for tuples that are in system
1043-
*relations; user-relation tuples are never in catcaches and can't affect
1043+
*catalogs; user-relation tuples are never in catcaches and can't affect
10441044
* the relcache either.
10451045
*/
1046-
if (!IsSystemRelation(relation))
1046+
if (!IsCatalogRelation(relation))
10471047
return;
10481048

10491049
/*
1050-
*TOAST tuples can likewise be ignored here. Note thatTOAST tablesare
1051-
*considered system relations so they are not filtered by the above test.
1050+
*IsCatalogRelation() will return true forTOAST tablesof system
1051+
*catalogs, but we don't care about those, either.
10521052
*/
10531053
if (IsToastRelation(relation))
10541054
return;

‎src/include/catalog/catalog.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ extern char *GetDatabasePath(Oid dbNode, Oid spcNode);
2525

2626
externboolIsSystemRelation(Relationrelation);
2727
externboolIsToastRelation(Relationrelation);
28+
externboolIsCatalogRelation(Relationrelation);
2829

29-
externboolIsSystemClass(Form_pg_classreltuple);
30+
externboolIsSystemClass(Oidrelid,Form_pg_classreltuple);
3031
externboolIsToastClass(Form_pg_classreltuple);
32+
externboolIsCatalogClass(Oidrelid,Form_pg_classreltuple);
3133

3234
externboolIsSystemNamespace(OidnamespaceId);
3335
externboolIsToastNamespace(OidnamespaceId);

‎src/test/regress/expected/alter_table.out

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,3 +2337,37 @@ FROM (
23372337
0 | t
23382338
(1 row)
23392339

2340+
-- Checks on creating and manipulation of user defined relations in
2341+
-- pg_catalog.
2342+
--
2343+
-- XXX: It would be useful to add checks around trying to manipulate
2344+
-- catalog tables, but that might have ugly consequences when run
2345+
-- against an existing server with allow_system_table_mods = on.
2346+
SHOW allow_system_table_mods;
2347+
allow_system_table_mods
2348+
-------------------------
2349+
off
2350+
(1 row)
2351+
2352+
-- disallowed because of search_path issues with pg_dump
2353+
CREATE TABLE pg_catalog.new_system_table();
2354+
ERROR: permission denied to create "pg_catalog.new_system_table"
2355+
DETAIL: System catalog modifications are currently disallowed.
2356+
-- instead create in public first, move to catalog
2357+
CREATE TABLE new_system_table(id serial primary key, othercol text);
2358+
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
2359+
-- XXX: it's currently impossible to move relations out of pg_catalog
2360+
ALTER TABLE new_system_table SET SCHEMA public;
2361+
ERROR: cannot remove dependency on schema pg_catalog because it is a system object
2362+
-- move back, will currently error out, already there
2363+
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
2364+
ERROR: table new_system_table is already in schema "pg_catalog"
2365+
ALTER TABLE new_system_table RENAME TO old_system_table;
2366+
CREATE INDEX old_system_table__othercol ON old_system_table (othercol);
2367+
INSERT INTO old_system_table(othercol) VALUES ('somedata'), ('otherdata');
2368+
UPDATE old_system_table SET id = -id;
2369+
DELETE FROM old_system_table WHERE othercol = 'somedata';
2370+
TRUNCATE old_system_table;
2371+
ALTER TABLE old_system_table DROP CONSTRAINT new_system_table_pkey;
2372+
ALTER TABLE old_system_table DROP COLUMN othercol;
2373+
DROP TABLE old_system_table;

‎src/test/regress/sql/alter_table.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,3 +1567,31 @@ FROM (
15671567
FROM pg_class
15681568
WHERE relkindIN ('r','i','S','t','m')
15691569
) mapped;
1570+
1571+
-- Checks on creating and manipulation of user defined relations in
1572+
-- pg_catalog.
1573+
--
1574+
-- XXX: It would be useful to add checks around trying to manipulate
1575+
-- catalog tables, but that might have ugly consequences when run
1576+
-- against an existing server with allow_system_table_mods = on.
1577+
1578+
SHOW allow_system_table_mods;
1579+
-- disallowed because of search_path issues with pg_dump
1580+
CREATETABLEpg_catalog.new_system_table();
1581+
-- instead create in public first, move to catalog
1582+
CREATETABLEnew_system_table(idserialprimary key, othercoltext);
1583+
ALTERTABLE new_system_tableSET SCHEMA pg_catalog;
1584+
1585+
-- XXX: it's currently impossible to move relations out of pg_catalog
1586+
ALTERTABLE new_system_tableSET SCHEMA public;
1587+
-- move back, will currently error out, already there
1588+
ALTERTABLE new_system_tableSET SCHEMA pg_catalog;
1589+
ALTERTABLE new_system_table RENAME TO old_system_table;
1590+
CREATEINDEXold_system_table__othercolON old_system_table (othercol);
1591+
INSERT INTO old_system_table(othercol)VALUES ('somedata'), ('otherdata');
1592+
UPDATE old_system_tableSET id=-id;
1593+
DELETEFROM old_system_tableWHERE othercol='somedata';
1594+
TRUNCATE old_system_table;
1595+
ALTERTABLE old_system_table DROPCONSTRAINT new_system_table_pkey;
1596+
ALTERTABLE old_system_table DROP COLUMN othercol;
1597+
DROPTABLE old_system_table;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp