31
31
#include "utils/fmgroids.h"
32
32
#include "utils/syscache.h"
33
33
#include "utils/tqual.h"
34
+ #include "utils/memutils.h"
34
35
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 ;
35
44
36
45
/*
37
46
* find_inheritance_children
@@ -157,10 +166,33 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
157
166
List *
158
167
find_all_inheritors (Oid parentrelId , LOCKMODE lockmode , List * * numparents )
159
168
{
169
+ /* hash table for O(1) rel_oid -> rel_numparents cell lookup */
170
+ HTAB * seen_rels ;
171
+ HASHCTL ctl ;
172
+ MemoryContext new_ctx ;
160
173
List * rels_list ,
161
174
* rel_numparents ;
162
175
ListCell * l ;
163
176
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
+
164
196
/*
165
197
* We build a list starting with the given rel and adding all direct and
166
198
* 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)
190
222
foreach (lc , currentchildren )
191
223
{
192
224
Oid child_oid = lfirst_oid (lc );
193
- bool found = false;
194
- ListCell * lo ;
195
- ListCell * li ;
225
+ bool found ;
226
+ SeenRelsEntry * hash_entry ;
196
227
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 )
199
230
{
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 )++ ;
206
233
}
207
-
208
- /* if it's not there, add it. expect 1 parent, initially. */
209
- if (!found )
234
+ else
210
235
{
236
+ /* if it's not there, add it. expect 1 parent, initially. */
211
237
rels_list = lappend_oid (rels_list , child_oid );
212
238
rel_numparents = lappend_int (rel_numparents , 1 );
239
+ hash_entry -> numparents_cell = rel_numparents -> tail ;
213
240
}
214
241
}
215
242
}
@@ -218,6 +245,9 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
218
245
* numparents = rel_numparents ;
219
246
else
220
247
list_free (rel_numparents );
248
+
249
+ hash_destroy (seen_rels );
250
+
221
251
return rels_list ;
222
252
}
223
253
0 commit comments