Skip to content

Commit 0ada559

Browse files
committed
Do some minor code refactoring in preparation for changing the APIs of
find_inheritance_children() and find_all_inheritors(). I got annoyed that these are buried inside the planner but mostly used elsewhere. So, create a new file catalog/pg_inherits.c and put them there, along with a couple of other functions that search pg_inherits. The code that modifies pg_inherits is (still) in tablecmds.c --- it's kind of entangled with unrelated code that modifies pg_depend and other stuff, so pulling it out seemed like a bigger change than I wanted to make right now. But this file provides a natural home for it if anyone ever gets around to that. This commit just moves code around; it doesn't change anything, except I succumbed to the temptation to make a couple of trivial optimizations in typeInheritsFrom().
1 parent 6480c14 commit 0ada559

File tree

12 files changed

+282
-242
lines changed

12 files changed

+282
-242
lines changed

src/backend/catalog/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Makefile for backend/catalog
44
#
5-
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.69 2009/02/09 20:57:59 alvherre Exp $
5+
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.70 2009/05/12 00:56:05 tgl Exp $
66
#
77
#-------------------------------------------------------------------------
88

@@ -12,8 +12,8 @@ include $(top_builddir)/src/Makefile.global
1212

1313
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
1414
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
15-
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
16-
pg_type.o storage.o toasting.o
15+
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
16+
pg_shdepend.o pg_type.o storage.o toasting.o
1717

1818
BKIFILES = postgres.bki postgres.description postgres.shdescription
1919

src/backend/catalog/pg_inherits.c

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pg_inherits.c
4+
* routines to support manipulation of the pg_inherits relation
5+
*
6+
* Note: currently, this module only contains inquiry functions; the actual
7+
* creation and deletion of pg_inherits entries is done in tablecmds.c.
8+
* Perhaps someday that code should be moved here, but it'd have to be
9+
* disentangled from other stuff such as pg_depend updates.
10+
*
11+
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
12+
* Portions Copyright (c) 1994, Regents of the University of California
13+
*
14+
*
15+
* IDENTIFICATION
16+
* $PostgreSQL: pgsql/src/backend/catalog/pg_inherits.c,v 1.1 2009/05/12 00:56:05 tgl Exp $
17+
*
18+
*-------------------------------------------------------------------------
19+
*/
20+
#include "postgres.h"
21+
22+
#include "access/heapam.h"
23+
#include "catalog/pg_class.h"
24+
#include "catalog/pg_inherits.h"
25+
#include "parser/parse_type.h"
26+
#include "utils/fmgroids.h"
27+
#include "utils/syscache.h"
28+
#include "utils/tqual.h"
29+
30+
31+
/*
32+
* find_inheritance_children
33+
*
34+
* Returns a list containing the OIDs of all relations which
35+
* inherit *directly* from the relation with OID 'parentrelId'.
36+
*/
37+
List *
38+
find_inheritance_children(Oid parentrelId)
39+
{
40+
List *list = NIL;
41+
Relation relation;
42+
HeapScanDesc scan;
43+
ScanKeyData key[1];
44+
HeapTuple inheritsTuple;
45+
Oid inhrelid;
46+
47+
/*
48+
* Can skip the scan if pg_class shows the relation has never had a
49+
* subclass.
50+
*/
51+
if (!has_subclass(parentrelId))
52+
return NIL;
53+
54+
/*
55+
* XXX might be a good idea to create an index on pg_inherits' inhparent
56+
* field, so that we can use an indexscan instead of sequential scan here.
57+
* However, in typical databases pg_inherits won't have enough entries to
58+
* justify an indexscan...
59+
*/
60+
relation = heap_open(InheritsRelationId, AccessShareLock);
61+
ScanKeyInit(&key[0],
62+
Anum_pg_inherits_inhparent,
63+
BTEqualStrategyNumber, F_OIDEQ,
64+
ObjectIdGetDatum(parentrelId));
65+
scan = heap_beginscan(relation, SnapshotNow, 1, key);
66+
while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
67+
{
68+
inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
69+
list = lappend_oid(list, inhrelid);
70+
}
71+
heap_endscan(scan);
72+
heap_close(relation, AccessShareLock);
73+
return list;
74+
}
75+
76+
77+
/*
78+
* find_all_inheritors -
79+
* Returns a list of relation OIDs including the given rel plus
80+
* all relations that inherit from it, directly or indirectly.
81+
*/
82+
List *
83+
find_all_inheritors(Oid parentrelId)
84+
{
85+
List *rels_list;
86+
ListCell *l;
87+
88+
/*
89+
* We build a list starting with the given rel and adding all direct and
90+
* indirect children. We can use a single list as both the record of
91+
* already-found rels and the agenda of rels yet to be scanned for more
92+
* children. This is a bit tricky but works because the foreach() macro
93+
* doesn't fetch the next list element until the bottom of the loop.
94+
*/
95+
rels_list = list_make1_oid(parentrelId);
96+
97+
foreach(l, rels_list)
98+
{
99+
Oid currentrel = lfirst_oid(l);
100+
List *currentchildren;
101+
102+
/* Get the direct children of this rel */
103+
currentchildren = find_inheritance_children(currentrel);
104+
105+
/*
106+
* Add to the queue only those children not already seen. This avoids
107+
* making duplicate entries in case of multiple inheritance paths from
108+
* the same parent. (It'll also keep us from getting into an infinite
109+
* loop, though theoretically there can't be any cycles in the
110+
* inheritance graph anyway.)
111+
*/
112+
rels_list = list_concat_unique_oid(rels_list, currentchildren);
113+
}
114+
115+
return rels_list;
116+
}
117+
118+
119+
/*
120+
* has_subclass - does this relation have any children?
121+
*
122+
* In the current implementation, has_subclass returns whether a
123+
* particular class *might* have a subclass. It will not return the
124+
* correct result if a class had a subclass which was later dropped.
125+
* This is because relhassubclass in pg_class is not updated when a
126+
* subclass is dropped, primarily because of concurrency concerns.
127+
*
128+
* Currently has_subclass is only used as an efficiency hack to skip
129+
* unnecessary inheritance searches, so this is OK.
130+
*
131+
* Although this doesn't actually touch pg_inherits, it seems reasonable
132+
* to keep it here since it's normally used with the other routines here.
133+
*/
134+
bool
135+
has_subclass(Oid relationId)
136+
{
137+
HeapTuple tuple;
138+
bool result;
139+
140+
tuple = SearchSysCache(RELOID,
141+
ObjectIdGetDatum(relationId),
142+
0, 0, 0);
143+
if (!HeapTupleIsValid(tuple))
144+
elog(ERROR, "cache lookup failed for relation %u", relationId);
145+
146+
result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
147+
ReleaseSysCache(tuple);
148+
return result;
149+
}
150+
151+
152+
/*
153+
* Given two type OIDs, determine whether the first is a complex type
154+
* (class type) that inherits from the second.
155+
*/
156+
bool
157+
typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
158+
{
159+
bool result = false;
160+
Oid subclassRelid;
161+
Oid superclassRelid;
162+
Relation inhrel;
163+
List *visited,
164+
*queue;
165+
ListCell *queue_item;
166+
167+
/* We need to work with the associated relation OIDs */
168+
subclassRelid = typeidTypeRelid(subclassTypeId);
169+
if (subclassRelid == InvalidOid)
170+
return false; /* not a complex type */
171+
superclassRelid = typeidTypeRelid(superclassTypeId);
172+
if (superclassRelid == InvalidOid)
173+
return false; /* not a complex type */
174+
175+
/* No point in searching if the superclass has no subclasses */
176+
if (!has_subclass(superclassRelid))
177+
return false;
178+
179+
/*
180+
* Begin the search at the relation itself, so add its relid to the queue.
181+
*/
182+
queue = list_make1_oid(subclassRelid);
183+
visited = NIL;
184+
185+
inhrel = heap_open(InheritsRelationId, AccessShareLock);
186+
187+
/*
188+
* Use queue to do a breadth-first traversal of the inheritance graph from
189+
* the relid supplied up to the root. Notice that we append to the queue
190+
* inside the loop --- this is okay because the foreach() macro doesn't
191+
* advance queue_item until the next loop iteration begins.
192+
*/
193+
foreach(queue_item, queue)
194+
{
195+
Oid this_relid = lfirst_oid(queue_item);
196+
ScanKeyData skey;
197+
HeapScanDesc inhscan;
198+
HeapTuple inhtup;
199+
200+
/*
201+
* If we've seen this relid already, skip it. This avoids extra
202+
* work in multiple-inheritance scenarios, and also protects us
203+
* from an infinite loop in case there is a cycle in pg_inherits
204+
* (though theoretically that shouldn't happen).
205+
*/
206+
if (list_member_oid(visited, this_relid))
207+
continue;
208+
209+
/*
210+
* Okay, this is a not-yet-seen relid. Add it to the list of
211+
* already-visited OIDs, then find all the types this relid inherits
212+
* from and add them to the queue.
213+
*/
214+
visited = lappend_oid(visited, this_relid);
215+
216+
ScanKeyInit(&skey,
217+
Anum_pg_inherits_inhrelid,
218+
BTEqualStrategyNumber, F_OIDEQ,
219+
ObjectIdGetDatum(this_relid));
220+
221+
inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey);
222+
223+
while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL)
224+
{
225+
Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
226+
Oid inhparent = inh->inhparent;
227+
228+
/* If this is the target superclass, we're done */
229+
if (inhparent == superclassRelid)
230+
{
231+
result = true;
232+
break;
233+
}
234+
235+
/* Else add to queue */
236+
queue = lappend_oid(queue, inhparent);
237+
}
238+
239+
heap_endscan(inhscan);
240+
241+
if (result)
242+
break;
243+
}
244+
245+
/* clean up ... */
246+
heap_close(inhrel, AccessShareLock);
247+
248+
list_free(visited);
249+
list_free(queue);
250+
251+
return result;
252+
}

src/backend/commands/lockcmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.21 2009/01/12 08:54:26 petere Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.22 2009/05/12 00:56:05 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
#include "postgres.h"
1616

1717
#include "access/heapam.h"
1818
#include "catalog/namespace.h"
19+
#include "catalog/pg_inherits.h"
1920
#include "commands/lockcmds.h"
2021
#include "miscadmin.h"
21-
#include "optimizer/prep.h"
2222
#include "parser/parse_clause.h"
2323
#include "utils/acl.h"
2424
#include "utils/lsyscache.h"

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.282 2009/05/07 22:58:28 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.283 2009/05/12 00:56:05 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -50,8 +50,6 @@
5050
#include "nodes/nodeFuncs.h"
5151
#include "nodes/parsenodes.h"
5252
#include "optimizer/clauses.h"
53-
#include "optimizer/plancat.h"
54-
#include "optimizer/prep.h"
5553
#include "parser/gramparse.h"
5654
#include "parser/parse_clause.h"
5755
#include "parser/parse_coerce.h"
@@ -1873,7 +1871,6 @@ renameatt(Oid myrelid,
18731871
ListCell *child;
18741872
List *children;
18751873

1876-
/* this routine is actually in the planner */
18771874
children = find_all_inheritors(myrelid);
18781875

18791876
/*
@@ -3292,7 +3289,6 @@ ATSimpleRecursion(List **wqueue, Relation rel,
32923289
ListCell *child;
32933290
List *children;
32943291

3295-
/* this routine is actually in the planner */
32963292
children = find_all_inheritors(relid);
32973293

32983294
/*
@@ -3331,7 +3327,6 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
33313327
ListCell *child;
33323328
List *children;
33333329

3334-
/* this routine is actually in the planner */
33353330
children = find_inheritance_children(relid);
33363331

33373332
foreach(child, children)

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