#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
+#include "utils/memutils.h"
+/*
+ * Entry of a hash table used in find_all_inheritors. See below.
+ */
+typedef struct SeenRelsEntry
+{
+ Oid rel_id; /* relation oid */
+ ListCell *numparents_cell; /* corresponding list cell */
+} SeenRelsEntry;
/*
* find_inheritance_children
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;
+ MemoryContext new_ctx;
List *rels_list,
*rel_numparents;
ListCell *l;
+ /*
+ * We need a separate memory context for a hash table. This is because
+ * hash table is used only in this procedure. To free a memory we need to
+ * call hash_destroy which is just a wrapper around MemoryContextDelete.
+ */
+ new_ctx = AllocSetContextCreate(CurrentMemoryContext,
+ "FindAllInheritorsSeenRelsContext",
+ ALLOCSET_DEFAULT_SIZES);
+
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.keysize = sizeof(Oid);
+ ctl.entrysize = sizeof(SeenRelsEntry);
+ ctl.hcxt = new_ctx;
+
+ 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
foreach(lc, currentchildren)
{
Oid child_oid = lfirst_oid(lc);
- bool found = false;
- ListCell *lo;
- ListCell *li;
+ bool found;
+ SeenRelsEntry *hash_entry;
- /* if the rel is already there, bump number-of-parents counter */
- forboth(lo, rels_list, li, rel_numparents)
+ hash_entry = hash_search(seen_rels, &child_oid, HASH_ENTER, &found);
+ if (found)
{
- if (lfirst_oid(lo) == child_oid)
- {
- lfirst_int(li)++;
- found = true;
- break;
- }
+ /* if the rel is already there, bump number-of-parents counter */
+ lfirst_int(hash_entry->numparents_cell)++;
}
-
- /* if it's not there, add it. expect 1 parent, initially. */
- if (!found)
+ 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;
}
}
}
*numparents = rel_numparents;
else
list_free(rel_numparents);
+
+ hash_destroy(seen_rels);
+
return rels_list;
}