00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "postgres.h"
00021
00022 #include "access/genam.h"
00023 #include "access/heapam.h"
00024 #include "access/htup_details.h"
00025 #include "catalog/indexing.h"
00026 #include "catalog/pg_inherits.h"
00027 #include "catalog/pg_inherits_fn.h"
00028 #include "parser/parse_type.h"
00029 #include "storage/lmgr.h"
00030 #include "utils/fmgroids.h"
00031 #include "utils/syscache.h"
00032 #include "utils/tqual.h"
00033
00034 static int oid_cmp(const void *p1, const void *p2);
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 List *
00049 find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
00050 {
00051 List *list = NIL;
00052 Relation relation;
00053 SysScanDesc scan;
00054 ScanKeyData key[1];
00055 HeapTuple inheritsTuple;
00056 Oid inhrelid;
00057 Oid *oidarr;
00058 int maxoids,
00059 numoids,
00060 i;
00061
00062
00063
00064
00065
00066 if (!has_subclass(parentrelId))
00067 return NIL;
00068
00069
00070
00071
00072 maxoids = 32;
00073 oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
00074 numoids = 0;
00075
00076 relation = heap_open(InheritsRelationId, AccessShareLock);
00077
00078 ScanKeyInit(&key[0],
00079 Anum_pg_inherits_inhparent,
00080 BTEqualStrategyNumber, F_OIDEQ,
00081 ObjectIdGetDatum(parentrelId));
00082
00083 scan = systable_beginscan(relation, InheritsParentIndexId, true,
00084 SnapshotNow, 1, key);
00085
00086 while ((inheritsTuple = systable_getnext(scan)) != NULL)
00087 {
00088 inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
00089 if (numoids >= maxoids)
00090 {
00091 maxoids *= 2;
00092 oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid));
00093 }
00094 oidarr[numoids++] = inhrelid;
00095 }
00096
00097 systable_endscan(scan);
00098
00099 heap_close(relation, AccessShareLock);
00100
00101
00102
00103
00104
00105
00106
00107 if (numoids > 1)
00108 qsort(oidarr, numoids, sizeof(Oid), oid_cmp);
00109
00110
00111
00112
00113 for (i = 0; i < numoids; i++)
00114 {
00115 inhrelid = oidarr[i];
00116
00117 if (lockmode != NoLock)
00118 {
00119
00120 LockRelationOid(inhrelid, lockmode);
00121
00122
00123
00124
00125
00126
00127 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(inhrelid)))
00128 {
00129
00130 UnlockRelationOid(inhrelid, lockmode);
00131
00132 continue;
00133 }
00134 }
00135
00136 list = lappend_oid(list, inhrelid);
00137 }
00138
00139 pfree(oidarr);
00140
00141 return list;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 List *
00159 find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
00160 {
00161 List *rels_list,
00162 *rel_numparents;
00163 ListCell *l;
00164
00165
00166
00167
00168
00169
00170
00171
00172 rels_list = list_make1_oid(parentrelId);
00173 rel_numparents = list_make1_int(0);
00174
00175 foreach(l, rels_list)
00176 {
00177 Oid currentrel = lfirst_oid(l);
00178 List *currentchildren;
00179 ListCell *lc;
00180
00181
00182 currentchildren = find_inheritance_children(currentrel, lockmode);
00183
00184
00185
00186
00187
00188
00189
00190
00191 foreach(lc, currentchildren)
00192 {
00193 Oid child_oid = lfirst_oid(lc);
00194 bool found = false;
00195 ListCell *lo;
00196 ListCell *li;
00197
00198
00199 forboth(lo, rels_list, li, rel_numparents)
00200 {
00201 if (lfirst_oid(lo) == child_oid)
00202 {
00203 lfirst_int(li)++;
00204 found = true;
00205 break;
00206 }
00207 }
00208
00209
00210 if (!found)
00211 {
00212 rels_list = lappend_oid(rels_list, child_oid);
00213 rel_numparents = lappend_int(rel_numparents, 1);
00214 }
00215 }
00216 }
00217
00218 if (numparents)
00219 *numparents = rel_numparents;
00220 else
00221 list_free(rel_numparents);
00222 return rels_list;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 bool
00243 has_subclass(Oid relationId)
00244 {
00245 HeapTuple tuple;
00246 bool result;
00247
00248 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId));
00249 if (!HeapTupleIsValid(tuple))
00250 elog(ERROR, "cache lookup failed for relation %u", relationId);
00251
00252 result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
00253 ReleaseSysCache(tuple);
00254 return result;
00255 }
00256
00257
00258
00259
00260
00261
00262 bool
00263 typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
00264 {
00265 bool result = false;
00266 Oid subclassRelid;
00267 Oid superclassRelid;
00268 Relation inhrel;
00269 List *visited,
00270 *queue;
00271 ListCell *queue_item;
00272
00273
00274 subclassRelid = typeidTypeRelid(subclassTypeId);
00275 if (subclassRelid == InvalidOid)
00276 return false;
00277 superclassRelid = typeidTypeRelid(superclassTypeId);
00278 if (superclassRelid == InvalidOid)
00279 return false;
00280
00281
00282 if (!has_subclass(superclassRelid))
00283 return false;
00284
00285
00286
00287
00288 queue = list_make1_oid(subclassRelid);
00289 visited = NIL;
00290
00291 inhrel = heap_open(InheritsRelationId, AccessShareLock);
00292
00293
00294
00295
00296
00297
00298
00299 foreach(queue_item, queue)
00300 {
00301 Oid this_relid = lfirst_oid(queue_item);
00302 ScanKeyData skey;
00303 SysScanDesc inhscan;
00304 HeapTuple inhtup;
00305
00306
00307
00308
00309
00310
00311
00312 if (list_member_oid(visited, this_relid))
00313 continue;
00314
00315
00316
00317
00318
00319
00320 visited = lappend_oid(visited, this_relid);
00321
00322 ScanKeyInit(&skey,
00323 Anum_pg_inherits_inhrelid,
00324 BTEqualStrategyNumber, F_OIDEQ,
00325 ObjectIdGetDatum(this_relid));
00326
00327 inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
00328 SnapshotNow, 1, &skey);
00329
00330 while ((inhtup = systable_getnext(inhscan)) != NULL)
00331 {
00332 Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
00333 Oid inhparent = inh->inhparent;
00334
00335
00336 if (inhparent == superclassRelid)
00337 {
00338 result = true;
00339 break;
00340 }
00341
00342
00343 queue = lappend_oid(queue, inhparent);
00344 }
00345
00346 systable_endscan(inhscan);
00347
00348 if (result)
00349 break;
00350 }
00351
00352
00353 heap_close(inhrel, AccessShareLock);
00354
00355 list_free(visited);
00356 list_free(queue);
00357
00358 return result;
00359 }
00360
00361
00362
00363 static int
00364 oid_cmp(const void *p1, const void *p2)
00365 {
00366 Oid v1 = *((const Oid *) p1);
00367 Oid v2 = *((const Oid *) p2);
00368
00369 if (v1 < v2)
00370 return -1;
00371 if (v1 > v2)
00372 return 1;
00373 return 0;
00374 }