/* * find_all_inheritors - * Returns a list of relation OIDs including the given rel plus * all relations that inherit from it, directly or indirectly. * Optionally, it also returns the number of parents found for * each such relation within the inheritance tree rooted at the * given rel. * * The specified lock type is acquired on all child relations (but not on the * given rel; caller should already have locked it). If lockmode is NoLock * then no locks are acquired, but caller must beware of race conditions * against possible DROPs of child relations. */ List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents) { List *rels_list, *rel_numparents; ListCell *l; /* * We build a list starting with the given rel and adding all direct and * indirect children. We can use a single list as both the record of * already-found rels and the agenda of rels yet to be scanned for more * children. This is a bit tricky but works because the foreach() macro * doesn't fetch the next list element until the bottom of the loop. */ rels_list = list_make1_oid(parentrelId); rel_numparents = list_make1_int(0); foreach(l, rels_list) { Oid currentrel = lfirst_oid(l); List *currentchildren; ListCell *lc; /* Get the direct children of this rel */ currentchildren = find_inheritance_children(currentrel, lockmode); /* * Add to the queue only those children not already seen. This avoids * making duplicate entries in case of multiple inheritance paths from * the same parent. (It'll also keep us from getting into an infinite * loop, though theoretically there can't be any cycles in the * inheritance graph anyway.) */ foreach(lc, currentchildren) { Oid child_oid = lfirst_oid(lc); bool found = false; ListCell *lo; ListCell *li; /* if the rel is already there, bump number-of-parents counter */ forboth(lo, rels_list, li, rel_numparents) { if (lfirst_oid(lo) == child_oid) { lfirst_int(li)++; found = true; break; } } /* if it's not there, add it. expect 1 parent, initially. */ if (!found) { rels_list = lappend_oid(rels_list, child_oid); rel_numparents = lappend_int(rel_numparents, 1); } }
/* * InsertPidIntoDynamicTableScanInfo * Inserts a partition oid into the dynamicTableScanInfo's * pidIndexes at the provided index. If partOid is an invalid * oid, it doesn't insert that, but ensures that the dynahash * exists at the index position in dynamicTableScanInfo. */ void InsertPidIntoDynamicTableScanInfo(int32 index, Oid partOid, int32 selectorId) { Assert(dynamicTableScanInfo != NULL && dynamicTableScanInfo->memoryContext != NULL); /* It's 1 based indexing */ Assert(index > 0); MemoryContext oldCxt = MemoryContextSwitchTo(dynamicTableScanInfo->memoryContext); if (index > dynamicTableScanInfo->numScans) { increaseScanArraySize(index); } Assert(index <= dynamicTableScanInfo->numScans); if ((dynamicTableScanInfo->pidIndexes)[index - 1] == NULL) { dynamicTableScanInfo->pidIndexes[index - 1] = createPidIndex(index); } Assert(dynamicTableScanInfo->pidIndexes[index - 1] != NULL); if (partOid != InvalidOid) { bool found = false; PartOidEntry *hashEntry = hash_search(dynamicTableScanInfo->pidIndexes[index - 1], &partOid, HASH_ENTER, &found); if (found) { Assert(hashEntry->partOid == partOid); Assert(NIL != hashEntry->selectorList); hashEntry->selectorList = list_append_unique_int(hashEntry->selectorList, selectorId); } else { hashEntry->partOid = partOid; hashEntry->selectorList = list_make1_int(selectorId); } } MemoryContextSwitchTo(oldCxt); }
/* * find_all_inheritors - * Returns a list of relation OIDs including the given rel plus * all relations that inherit from it, directly or indirectly. * Optionally, it also returns the number of parents found for * each such relation within the inheritance tree rooted at the * given rel. * * The specified lock type is acquired on all child relations (but not on the * given rel; caller should already have locked it). If lockmode is NoLock * then no locks are acquired, but caller must beware of race conditions * against possible DROPs of child relations. */ List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents) { /* hash table for O(1) rel_oid -> rel_numparents cell lookup */ HTAB *seen_rels; HASHCTL ctl; List *rels_list, *rel_numparents; ListCell *l; memset(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(SeenRelsEntry); ctl.hcxt = CurrentMemoryContext; seen_rels = hash_create("find_all_inheritors temporary table", 32, /* start small and extend */ &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); /* * We build a list starting with the given rel and adding all direct and * indirect children. We can use a single list as both the record of * already-found rels and the agenda of rels yet to be scanned for more * children. This is a bit tricky but works because the foreach() macro * doesn't fetch the next list element until the bottom of the loop. */ rels_list = list_make1_oid(parentrelId); rel_numparents = list_make1_int(0); foreach(l, rels_list) { Oid currentrel = lfirst_oid(l); List *currentchildren; ListCell *lc; /* Get the direct children of this rel */ currentchildren = find_inheritance_children(currentrel, lockmode); /* * Add to the queue only those children not already seen. This avoids * making duplicate entries in case of multiple inheritance paths from * the same parent. (It'll also keep us from getting into an infinite * loop, though theoretically there can't be any cycles in the * inheritance graph anyway.) */ foreach(lc, currentchildren) { Oid child_oid = lfirst_oid(lc); bool found; SeenRelsEntry *hash_entry; hash_entry = hash_search(seen_rels, &child_oid, HASH_ENTER, &found); if (found) { /* if the rel is already there, bump number-of-parents counter */ lfirst_int(hash_entry->numparents_cell)++; } else { /* if it's not there, add it. expect 1 parent, initially. */ rels_list = lappend_oid(rels_list, child_oid); rel_numparents = lappend_int(rel_numparents, 1); hash_entry->numparents_cell = rel_numparents->tail; } }