PostgreSQL Source Code git master
execGrouping.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * execGrouping.c
4 * executor utility routines for grouping, hashing, and aggregation
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/executor/execGrouping.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include <math.h>
18
19#include "access/htup_details.h"
20#include "access/parallel.h"
21#include "common/hashfn.h"
22#include "executor/executor.h"
23#include "miscadmin.h"
24#include "utils/lsyscache.h"
25
26static int TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2);
27static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb,
28 MinimalTuple tuple);
30 TupleTableSlot *slot,
31 bool *isnew, uint32 hash);
32
33/*
34 * Define parameters for tuple hash table code generation. The interface is
35 * *also* declared in execnodes.h (to generate the types, which are externally
36 * visible).
37 */
38#define SH_PREFIX tuplehash
39#define SH_ELEMENT_TYPE TupleHashEntryData
40#define SH_KEY_TYPE MinimalTuple
41#define SH_KEY firstTuple
42#define SH_HASH_KEY(tb, key) TupleHashTableHash_internal(tb, key)
43#define SH_EQUAL(tb, a, b) TupleHashTableMatch(tb, a, b) == 0
44#define SH_SCOPE extern
45#define SH_STORE_HASH
46#define SH_GET_HASH(tb, a) a->hash
47#define SH_DEFINE
48#include "lib/simplehash.h"
49
50
51/*****************************************************************************
52 * Utility routines for grouping tuples together
53 *****************************************************************************/
54
55/*
56 * execTuplesMatchPrepare
57 * Build expression that can be evaluated using ExecQual(), returning
58 * whether an ExprContext's inner/outer tuples are NOT DISTINCT
59 */
62 int numCols,
63 const AttrNumber *keyColIdx,
64 const Oid *eqOperators,
65 const Oid *collations,
66 PlanState *parent)
67{
68 Oid *eqFunctions;
69 int i;
70 ExprState *expr;
71
72 if (numCols == 0)
73 return NULL;
74
75 eqFunctions = (Oid *) palloc(numCols * sizeof(Oid));
76
77 /* lookup equality functions */
78 for (i = 0; i < numCols; i++)
79 eqFunctions[i] = get_opcode(eqOperators[i]);
80
81 /* build actual expression */
82 expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
83 numCols, keyColIdx, eqFunctions, collations,
84 parent);
85
86 return expr;
87}
88
89/*
90 * execTuplesHashPrepare
91 * Look up the equality and hashing functions needed for a TupleHashTable.
92 *
93 * This is similar to execTuplesMatchPrepare, but we also need to find the
94 * hash functions associated with the equality operators. *eqFunctions and
95 * *hashFunctions receive the palloc'd result arrays.
96 *
97 * Note: we expect that the given operators are not cross-type comparisons.
98 */
99void
101 const Oid *eqOperators,
102 Oid **eqFuncOids,
103 FmgrInfo **hashFunctions)
104{
105 int i;
106
107 *eqFuncOids = (Oid *) palloc(numCols * sizeof(Oid));
108 *hashFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
109
110 for (i = 0; i < numCols; i++)
111 {
112 Oid eq_opr = eqOperators[i];
113 Oid eq_function;
114 Oid left_hash_function;
115 Oid right_hash_function;
116
117 eq_function = get_opcode(eq_opr);
118 if (!get_op_hash_functions(eq_opr,
119 &left_hash_function, &right_hash_function))
120 elog(ERROR, "could not find hash function for hash operator %u",
121 eq_opr);
122 /* We're not supporting cross-type cases here */
123 Assert(left_hash_function == right_hash_function);
124 (*eqFuncOids)[i] = eq_function;
125 fmgr_info(right_hash_function, &(*hashFunctions)[i]);
126 }
127}
128
129
130/*****************************************************************************
131 * Utility routines for all-in-memory hash tables
132 *
133 * These routines build hash tables for grouping tuples together (eg, for
134 * hash aggregation). There is one entry for each not-distinct set of tuples
135 * presented.
136 *****************************************************************************/
137
138/*
139 * Construct an empty TupleHashTable
140 *
141 * parent: PlanState node that will own this hash table
142 * inputDesc: tuple descriptor for input tuples
143 * inputOps: slot ops for input tuples, or NULL if unknown or not fixed
144 * numCols: number of columns to be compared (length of next 4 arrays)
145 * keyColIdx: indexes of tuple columns to compare
146 * eqfuncoids: OIDs of equality comparison functions to use
147 * hashfunctions: FmgrInfos of datatype-specific hashing functions to use
148 * collations: collations to use in comparisons
149 * nelements: initial estimate of hashtable size
150 * additionalsize: size of data that may be stored along with the hash entry
151 * metacxt: memory context for long-lived data and the simplehash table
152 * tuplescxt: memory context in which to store the hashed tuples themselves
153 * tempcxt: short-lived context for evaluation hash and comparison functions
154 * use_variable_hash_iv: if true, adjust hash IV per-parallel-worker
155 *
156 * The hashfunctions array may be made with execTuplesHashPrepare(). Note they
157 * are not cross-type functions, but expect to see the table datatype(s)
158 * on both sides.
159 *
160 * Note that the keyColIdx, hashfunctions, and collations arrays must be
161 * allocated in storage that will live as long as the hashtable does.
162 *
163 * The metacxt and tuplescxt are separate because it's usually desirable for
164 * tuplescxt to be a BumpContext to avoid memory wastage, while metacxt must
165 * support pfree in case the simplehash table needs to be enlarged. (We could
166 * simplify the API of TupleHashTables by managing the tuplescxt internally.
167 * But that would be disadvantageous to nodeAgg.c and nodeSubplan.c, which use
168 * a single tuplescxt for multiple TupleHashTables that are reset together.)
169 *
170 * LookupTupleHashEntry, FindTupleHashEntry, and related functions may leak
171 * memory in the tempcxt. It is caller's responsibility to reset that context
172 * reasonably often, typically once per tuple. (We do it that way, rather
173 * than managing an extra context within the hashtable, because in many cases
174 * the caller can specify a tempcxt that it needs to reset per-tuple anyway.)
175 *
176 * We don't currently provide DestroyTupleHashTable functionality; the hash
177 * table will be cleaned up at destruction of the metacxt. (Some callers
178 * bother to delete the tuplescxt explicitly, though it'd be sufficient to
179 * ensure it's a child of the metacxt.) There's not much point in working
180 * harder than this so long as the expression-evaluation infrastructure
181 * behaves similarly.
182 */
185 TupleDesc inputDesc,
186 const TupleTableSlotOps *inputOps,
187 int numCols,
188 AttrNumber *keyColIdx,
189 const Oid *eqfuncoids,
190 FmgrInfo *hashfunctions,
191 Oid *collations,
192 double nelements,
193 Size additionalsize,
194 MemoryContext metacxt,
195 MemoryContext tuplescxt,
196 MemoryContext tempcxt,
197 bool use_variable_hash_iv)
198{
199 TupleHashTable hashtable;
200 uint32 nbuckets;
201 MemoryContext oldcontext;
202 uint32 hash_iv = 0;
203
204 /*
205 * tuplehash_create requires a uint32 element count, so we had better
206 * clamp the given nelements to fit in that. As long as we have to do
207 * that, we might as well protect against completely insane input like
208 * zero or NaN. But it is not our job here to enforce issues like staying
209 * within hash_mem: the caller should have done that, and we don't have
210 * enough info to second-guess.
211 */
212 if (isnan(nelements) || nelements <= 0)
213 nbuckets = 1;
214 else if (nelements >= PG_UINT32_MAX)
215 nbuckets = PG_UINT32_MAX;
216 else
217 nbuckets = (uint32) nelements;
218
219 /* tuplescxt must be separate, else ResetTupleHashTable breaks things */
220 Assert(metacxt != tuplescxt);
221
222 /* ensure additionalsize is maxalign'ed */
223 additionalsize = MAXALIGN(additionalsize);
224
225 oldcontext = MemoryContextSwitchTo(metacxt);
226
227 hashtable = (TupleHashTable) palloc(sizeof(TupleHashTableData));
228
229 hashtable->numCols = numCols;
230 hashtable->keyColIdx = keyColIdx;
231 hashtable->tab_collations = collations;
232 hashtable->tuplescxt = tuplescxt;
233 hashtable->tempcxt = tempcxt;
234 hashtable->additionalsize = additionalsize;
235 hashtable->tableslot = NULL; /* will be made on first lookup */
236 hashtable->inputslot = NULL;
237 hashtable->in_hash_expr = NULL;
238 hashtable->cur_eq_func = NULL;
239
240 /*
241 * If parallelism is in use, even if the leader backend is performing the
242 * scan itself, we don't want to create the hashtable exactly the same way
243 * in all workers. As hashtables are iterated over in keyspace-order,
244 * doing so in all processes in the same way is likely to lead to
245 * "unbalanced" hashtables when the table size initially is
246 * underestimated.
247 */
248 if (use_variable_hash_iv)
250
251 hashtable->hashtab = tuplehash_create(metacxt, nbuckets, hashtable);
252
253 /*
254 * We copy the input tuple descriptor just for safety --- we assume all
255 * input tuples will have equivalent descriptors.
256 */
259
260 /* build hash ExprState for all columns */
261 hashtable->tab_hash_expr = ExecBuildHash32FromAttrs(inputDesc,
262 inputOps,
263 hashfunctions,
264 collations,
265 numCols,
266 keyColIdx,
267 parent,
268 hash_iv);
269
270 /* build comparator for all columns */
271 hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
272 inputOps,
274 numCols,
275 keyColIdx, eqfuncoids, collations,
276 parent);
277
278 /*
279 * While not pretty, it's ok to not shut down this context, but instead
280 * rely on the containing memory context being reset, as
281 * ExecBuildGroupingEqual() only builds a very simple expression calling
282 * functions (i.e. nothing that'd employ RegisterExprContextCallback()).
283 */
285
286 MemoryContextSwitchTo(oldcontext);
287
288 return hashtable;
289}
290
291/*
292 * Reset contents of the hashtable to be empty, preserving all the non-content
293 * state.
294 *
295 * Note: in usages where several TupleHashTables share a tuplescxt, all must
296 * be reset together, as the first one's reset call will destroy all their
297 * data. The additional reset calls for the rest will redundantly reset the
298 * tuplescxt. But because of mcxt.c's isReset flag, that's cheap enough that
299 * we need not avoid it.
300 */
301void
303{
304 tuplehash_reset(hashtable->hashtab);
305 MemoryContextReset(hashtable->tuplescxt);
306}
307
308/*
309 * Estimate the amount of space needed for a TupleHashTable with nentries
310 * entries, if the tuples have average data width tupleWidth and the caller
311 * requires additionalsize extra space per entry.
312 *
313 * Return SIZE_MAX if it'd overflow size_t.
314 *
315 * nentries is "double" because this is meant for use by the planner,
316 * which typically works with double rowcount estimates. So we'd need to
317 * clamp to integer somewhere and that might as well be here. We do expect
318 * the value not to be NaN or negative, else the result will be garbage.
319 */
320Size
322 Size tupleWidth,
323 Size additionalsize)
324{
325 Size sh_space;
326 double tuples_space;
327
328 /* First estimate the space needed for the simplehash table */
329 sh_space = tuplehash_estimate_space(nentries);
330
331 /* Give up if that's already too big */
332 if (sh_space >= SIZE_MAX)
333 return sh_space;
334
335 /*
336 * Compute space needed for hashed tuples with additional data. nentries
337 * must be somewhat sane, so it should be safe to compute this product.
338 *
339 * We assume that the hashed tuples will be kept in a BumpContext so that
340 * there is not additional per-tuple overhead.
341 *
342 * (Note that this is only accurate if MEMORY_CONTEXT_CHECKING is off,
343 * else bump.c will add a MemoryChunk header to each tuple. However, it
344 * seems undesirable for debug builds to make different planning choices
345 * than production builds, so we assume the production behavior always.)
346 */
347 tuples_space = nentries * (MAXALIGN(SizeofMinimalTupleHeader) +
348 MAXALIGN(tupleWidth) +
349 MAXALIGN(additionalsize));
350
351 /*
352 * Check for size_t overflow. This coding is trickier than it may appear,
353 * because on 64-bit machines SIZE_MAX cannot be represented exactly as a
354 * double. We must cast it explicitly to suppress compiler warnings about
355 * an inexact conversion, and we must trust that any double value that
356 * compares strictly less than "(double) SIZE_MAX" will cast to a
357 * representable size_t value.
358 */
359 if (sh_space + tuples_space >= (double) SIZE_MAX)
360 return SIZE_MAX;
361
362 /* We don't bother estimating size of the miscellaneous overhead data */
363 return (Size) (sh_space + tuples_space);
364}
365
366/*
367 * Find or create a hashtable entry for the tuple group containing the
368 * given tuple. The tuple must be the same type as the hashtable entries.
369 *
370 * If isnew is NULL, we do not create new entries; we return NULL if no
371 * match is found.
372 *
373 * If hash is not NULL, we set it to the calculated hash value. This allows
374 * callers access to the hash value even if no entry is returned.
375 *
376 * If isnew isn't NULL, then a new entry is created if no existing entry
377 * matches. On return, *isnew is true if the entry is newly created,
378 * false if it existed already. The additional data in the new entry has
379 * been zeroed.
380 */
383 bool *isnew, uint32 *hash)
384{
385 TupleHashEntry entry;
386 MemoryContext oldContext;
387 uint32 local_hash;
388
389 /* Need to run the hash functions in short-lived context */
390 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
391
392 /* set up data needed by hash and match functions */
393 hashtable->inputslot = slot;
394 hashtable->in_hash_expr = hashtable->tab_hash_expr;
395 hashtable->cur_eq_func = hashtable->tab_eq_func;
396
397 local_hash = TupleHashTableHash_internal(hashtable->hashtab, NULL);
398 entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, local_hash);
399
400 if (hash != NULL)
401 *hash = local_hash;
402
403 Assert(entry == NULL || entry->hash == local_hash);
404
405 MemoryContextSwitchTo(oldContext);
406
407 return entry;
408}
409
410/*
411 * Compute the hash value for a tuple
412 */
413uint32
415{
416 MemoryContext oldContext;
417 uint32 hash;
418
419 hashtable->inputslot = slot;
420 hashtable->in_hash_expr = hashtable->tab_hash_expr;
421
422 /* Need to run the hash functions in short-lived context */
423 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
424
425 hash = TupleHashTableHash_internal(hashtable->hashtab, NULL);
426
427 MemoryContextSwitchTo(oldContext);
428
429 return hash;
430}
431
432/*
433 * A variant of LookupTupleHashEntry for callers that have already computed
434 * the hash value.
435 */
438 bool *isnew, uint32 hash)
439{
440 TupleHashEntry entry;
441 MemoryContext oldContext;
442
443 /* Need to run the hash functions in short-lived context */
444 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
445
446 /* set up data needed by hash and match functions */
447 hashtable->inputslot = slot;
448 hashtable->in_hash_expr = hashtable->tab_hash_expr;
449 hashtable->cur_eq_func = hashtable->tab_eq_func;
450
451 entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, hash);
452 Assert(entry == NULL || entry->hash == hash);
453
454 MemoryContextSwitchTo(oldContext);
455
456 return entry;
457}
458
459/*
460 * Search for a hashtable entry matching the given tuple. No entry is
461 * created if there's not a match. This is similar to the non-creating
462 * case of LookupTupleHashEntry, except that it supports cross-type
463 * comparisons, in which the given tuple is not of the same type as the
464 * table entries. The caller must provide the hash ExprState to use for
465 * the input tuple, as well as the equality ExprState, since these may be
466 * different from the table's internal functions.
467 */
470 ExprState *eqcomp,
471 ExprState *hashexpr)
472{
473 TupleHashEntry entry;
474 MemoryContext oldContext;
476
477 /* Need to run the hash functions in short-lived context */
478 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
479
480 /* Set up data needed by hash and match functions */
481 hashtable->inputslot = slot;
482 hashtable->in_hash_expr = hashexpr;
483 hashtable->cur_eq_func = eqcomp;
484
485 /* Search the hash table */
486 key = NULL; /* flag to reference inputslot */
487 entry = tuplehash_lookup(hashtable->hashtab, key);
488 MemoryContextSwitchTo(oldContext);
489
490 return entry;
491}
492
493/*
494 * If tuple is NULL, use the input slot instead. This convention avoids the
495 * need to materialize virtual input tuples unless they actually need to get
496 * copied into the table.
497 *
498 * Also, the caller must select an appropriate memory context for running
499 * the hash functions.
500 */
501static uint32
502TupleHashTableHash_internal(struct tuplehash_hash *tb,
503 MinimalTuple tuple)
504{
505 TupleHashTable hashtable = (TupleHashTable) tb->private_data;
506 uint32 hashkey;
507 TupleTableSlot *slot;
508 bool isnull;
509
510 if (tuple == NULL)
511 {
512 /* Process the current input tuple for the table */
513 hashtable->exprcontext->ecxt_innertuple = hashtable->inputslot;
514 hashkey = DatumGetUInt32(ExecEvalExpr(hashtable->in_hash_expr,
515 hashtable->exprcontext,
516 &isnull));
517 }
518 else
519 {
520 /*
521 * Process a tuple already stored in the table.
522 *
523 * (this case never actually occurs due to the way simplehash.h is
524 * used, as the hash-value is stored in the entries)
525 */
526 slot = hashtable->exprcontext->ecxt_innertuple = hashtable->tableslot;
527 ExecStoreMinimalTuple(tuple, slot, false);
528 hashkey = DatumGetUInt32(ExecEvalExpr(hashtable->tab_hash_expr,
529 hashtable->exprcontext,
530 &isnull));
531 }
532
533 /*
534 * The hashing done above, even with an initial value, doesn't tend to
535 * result in good hash perturbation. Running the value produced above
536 * through murmurhash32 leads to near perfect hash perturbation.
537 */
538 return murmurhash32(hashkey);
539}
540
541/*
542 * Does the work of LookupTupleHashEntry and LookupTupleHashEntryHash. Useful
543 * so that we can avoid switching the memory context multiple times for
544 * LookupTupleHashEntry.
545 *
546 * NB: This function may or may not change the memory context. Caller is
547 * expected to change it back.
548 */
549static inline TupleHashEntry
551 bool *isnew, uint32 hash)
552{
553 TupleHashEntryData *entry;
554 bool found;
556
557 key = NULL; /* flag to reference inputslot */
558
559 if (isnew)
560 {
561 entry = tuplehash_insert_hash(hashtable->hashtab, key, hash, &found);
562
563 if (found)
564 {
565 /* found pre-existing entry */
566 *isnew = false;
567 }
568 else
569 {
570 /* created new entry */
571 *isnew = true;
572
574
575 /*
576 * Copy the first tuple into the tuples context, and request
577 * additionalsize extra bytes before the allocation.
578 *
579 * The caller can get a pointer to the additional data with
580 * TupleHashEntryGetAdditional(), and store arbitrary data there.
581 * Placing both the tuple and additional data in the same
582 * allocation avoids the need to store an extra pointer in
583 * TupleHashEntryData or allocate an additional chunk.
584 */
586 hashtable->additionalsize);
587 }
588 }
589 else
590 {
591 entry = tuplehash_lookup_hash(hashtable->hashtab, key, hash);
592 }
593
594 return entry;
595}
596
597/*
598 * See whether two tuples (presumably of the same hash value) match
599 */
600static int
601TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2)
602{
603 TupleTableSlot *slot1;
604 TupleTableSlot *slot2;
605 TupleHashTable hashtable = (TupleHashTable) tb->private_data;
606 ExprContext *econtext = hashtable->exprcontext;
607
608 /*
609 * We assume that simplehash.h will only ever call us with the first
610 * argument being an actual table entry, and the second argument being
611 * LookupTupleHashEntry's dummy TupleHashEntryData. The other direction
612 * could be supported too, but is not currently required.
613 */
614 Assert(tuple1 != NULL);
615 slot1 = hashtable->tableslot;
616 ExecStoreMinimalTuple(tuple1, slot1, false);
617 Assert(tuple2 == NULL);
618 slot2 = hashtable->inputslot;
619
620 /* For crosstype comparisons, the inputslot must be first */
621 econtext->ecxt_innertuple = slot2;
622 econtext->ecxt_outertuple = slot1;
623 return !ExecQualAndReset(hashtable->cur_eq_func, econtext);
624}
int16 AttrNumber
Definition: attnum.h:21
int ParallelWorkerNumber
Definition: parallel.c:115
#define MAXALIGN(LEN)
Definition: c.h:815
#define PG_UINT32_MAX
Definition: c.h:600
uint32_t uint32
Definition: c.h:543
size_t Size
Definition: c.h:615
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
ExprState * ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, Oid *collations, int numCols, AttrNumber *keyColIdx, PlanState *parent, uint32 init_value)
Definition: execExpr.c:4141
ExprState * ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, const Oid *collations, PlanState *parent)
Definition: execExpr.c:4465
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:61
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:100
static int TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2)
Definition: execGrouping.c:601
TupleHashTable BuildTupleHashTable(PlanState *parent, TupleDesc inputDesc, const TupleTableSlotOps *inputOps, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, double nelements, Size additionalsize, MemoryContext metacxt, MemoryContext tuplescxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:184
TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
Definition: execGrouping.c:437
static uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb, MinimalTuple tuple)
Definition: execGrouping.c:502
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
Definition: execGrouping.c:382
uint32 TupleHashTableHash(TupleHashTable hashtable, TupleTableSlot *slot)
Definition: execGrouping.c:414
TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, ExprState *eqcomp, ExprState *hashexpr)
Definition: execGrouping.c:469
Size EstimateTupleHashTableSpace(double nentries, Size tupleWidth, Size additionalsize)
Definition: execGrouping.c:321
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:302
static TupleHashEntry LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
Definition: execGrouping.c:550
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1427
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1635
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
ExprContext * CreateStandaloneExprContext(void)
Definition: execUtils.c:357
struct TupleHashTableData * TupleHashTable
Definition: execnodes.h:845
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:546
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:393
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:128
static uint32 murmurhash32(uint32 data)
Definition: hashfn.h:92
Assert(PointerIsAligned(start, uint64))
#define SizeofMinimalTupleHeader
Definition: htup_details.h:699
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1452
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:582
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
void * palloc(Size size)
Definition: mcxt.c:1365
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:232
unsigned int Oid
Definition: postgres_ext.h:32
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:275
Definition: fmgr.h:57
MinimalTuple firstTuple
Definition: execnodes.h:855
AttrNumber * keyColIdx
Definition: execnodes.h:872
tuplehash_hash * hashtab
Definition: execnodes.h:870
ExprState * in_hash_expr
Definition: execnodes.h:882
ExprState * tab_hash_expr
Definition: execnodes.h:873
MemoryContext tempcxt
Definition: execnodes.h:877
ExprState * tab_eq_func
Definition: execnodes.h:874
TupleTableSlot * tableslot
Definition: execnodes.h:879
ExprContext * exprcontext
Definition: execnodes.h:884
TupleTableSlot * inputslot
Definition: execnodes.h:881
ExprState * cur_eq_func
Definition: execnodes.h:883
MemoryContext tuplescxt
Definition: execnodes.h:876
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:252
static MinimalTuple ExecCopySlotMinimalTupleExtra(TupleTableSlot *slot, Size extra)
Definition: tuptable.h:507