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 ;
160173List * rels_list ,
161174* rel_numparents ;
162175ListCell * 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)
190222foreach (lc ,currentchildren )
191223{
192224Oid 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. */
211237rels_list = lappend_oid (rels_list ,child_oid );
212238rel_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 ;
219246else
220247list_free (rel_numparents );
248+
249+ hash_destroy (seen_rels );
250+
221251return rels_list ;
222252}
223253