3131#include "utils/fmgroids.h"
3232#include "utils/syscache.h"
3333#include "utils/tqual.h"
34+ #include "utils/memutils.h"
3435
36+ /*
37+ * Entry of a hash table used in find_all_inheritors. See below.
38+ */
39+ typedef struct SeenRelsEntry
40+ {
41+ Oid rel_id ; /* relation oid */
42+ ListCell * numparents_cell ; /* corresponding list cell */
43+ } SeenRelsEntry ;
3544
3645/*
3746 * find_inheritance_children
@@ -157,10 +166,33 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
157166List *
158167find_all_inheritors (Oid parentrelId , LOCKMODE lockmode , List * * numparents )
159168{
169+ /* hash table for O(1) rel_oid -> rel_numparents cell lookup */
170+ HTAB * seen_rels ;
171+ HASHCTL ctl ;
172+ MemoryContext new_ctx ;
160173 List * rels_list ,
161174 * rel_numparents ;
162175 ListCell * l ;
163176
177+ /*
178+ * We need a separate memory context for a hash table. This is because
179+ * hash table is used only in this procedure. To free a memory we need to
180+ * call hash_destroy which is just a wrapper around MemoryContextDelete.
181+ */
182+ new_ctx = AllocSetContextCreate (CurrentMemoryContext ,
183+ "FindAllInheritorsSeenRelsContext" ,
184+ ALLOCSET_DEFAULT_SIZES );
185+
186+ memset (& ctl , 0 , sizeof (ctl ));
187+ ctl .keysize = sizeof (Oid );
188+ ctl .entrysize = sizeof (SeenRelsEntry );
189+ ctl .hcxt = new_ctx ;
190+
191+ seen_rels = hash_create (
192+ "find_all_inheritors temporary table" ,
193+ 32 , /* start small and extend */
194+ & ctl , HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
195+
164196 /*
165197 * We build a list starting with the given rel and adding all direct and
166198 * indirect children. We can use a single list as both the record of
@@ -190,26 +222,21 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
190222 foreach (lc , currentchildren )
191223 {
192224 Oid child_oid = lfirst_oid (lc );
193- bool found = false;
194- ListCell * lo ;
195- ListCell * li ;
225+ bool found ;
226+ SeenRelsEntry * hash_entry ;
196227
197- /* if the rel is already there, bump number-of-parents counter */
198- forboth ( lo , rels_list , li , rel_numparents )
228+ hash_entry = hash_search ( seen_rels , & child_oid , HASH_ENTER , & found );
229+ if ( found )
199230 {
200- if (lfirst_oid (lo ) == child_oid )
201- {
202- lfirst_int (li )++ ;
203- found = true;
204- break ;
205- }
231+ /* if the rel is already there, bump number-of-parents counter */
232+ lfirst_int (hash_entry -> numparents_cell )++ ;
206233 }
207-
208- /* if it's not there, add it. expect 1 parent, initially. */
209- if (!found )
234+ else
210235 {
236+ /* if it's not there, add it. expect 1 parent, initially. */
211237 rels_list = lappend_oid (rels_list , child_oid );
212238 rel_numparents = lappend_int (rel_numparents , 1 );
239+ hash_entry -> numparents_cell = rel_numparents -> tail ;
213240 }
214241 }
215242 }
@@ -218,6 +245,9 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
218245 * numparents = rel_numparents ;
219246 else
220247 list_free (rel_numparents );
248+
249+ hash_destroy (seen_rels );
250+
221251 return rels_list ;
222252}
223253
0 commit comments