PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeHash.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeHash.c
4  * Routines to hash relations for hashjoin
5  *
6  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/nodeHash.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  * MultiExecHash - generate an in-memory hash table of the relation
18  * ExecInitHash - initialize node and subnodes
19  * ExecEndHash - shutdown node and subnodes
20  */
21 
22 #include "postgres.h"
23 
24 #include <math.h>
25 #include <limits.h>
26 
27 #include "access/htup_details.h"
28 #include "catalog/pg_statistic.h"
29 #include "commands/tablespace.h"
30 #include "executor/execdebug.h"
31 #include "executor/hashjoin.h"
32 #include "executor/nodeHash.h"
33 #include "executor/nodeHashjoin.h"
34 #include "miscadmin.h"
35 #include "utils/dynahash.h"
36 #include "utils/memutils.h"
37 #include "utils/lsyscache.h"
38 #include "utils/syscache.h"
39 
40 
41 static void ExecHashIncreaseNumBatches(HashJoinTable hashtable);
42 static void ExecHashIncreaseNumBuckets(HashJoinTable hashtable);
43 static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node,
44  int mcvsToUse);
45 static void ExecHashSkewTableInsert(HashJoinTable hashtable,
46  TupleTableSlot *slot,
47  uint32 hashvalue,
48  int bucketNumber);
49 static void ExecHashRemoveNextSkewBucket(HashJoinTable hashtable);
50 
51 static void *dense_alloc(HashJoinTable hashtable, Size size);
52 
53 /* ----------------------------------------------------------------
54  * ExecHash
55  *
56  * stub for pro forma compliance
57  * ----------------------------------------------------------------
58  */
61 {
62  elog(ERROR, "Hash node does not support ExecProcNode call convention");
63  return NULL;
64 }
65 
66 /* ----------------------------------------------------------------
67  * MultiExecHash
68  *
69  * build hash table for hashjoin, doing partitioning if more
70  * than one batch is required.
71  * ----------------------------------------------------------------
72  */
73 Node *
75 {
76  PlanState *outerNode;
77  List *hashkeys;
78  HashJoinTable hashtable;
79  TupleTableSlot *slot;
80  ExprContext *econtext;
81  uint32 hashvalue;
82 
83  /* must provide our own instrumentation support */
84  if (node->ps.instrument)
86 
87  /*
88  * get state info from node
89  */
90  outerNode = outerPlanState(node);
91  hashtable = node->hashtable;
92 
93  /*
94  * set expression context
95  */
96  hashkeys = node->hashkeys;
97  econtext = node->ps.ps_ExprContext;
98 
99  /*
100  * get all inner tuples and insert into the hash table (or temp files)
101  */
102  for (;;)
103  {
104  slot = ExecProcNode(outerNode);
105  if (TupIsNull(slot))
106  break;
107  /* We have to compute the hash value */
108  econtext->ecxt_innertuple = slot;
109  if (ExecHashGetHashValue(hashtable, econtext, hashkeys,
110  false, hashtable->keepNulls,
111  &hashvalue))
112  {
113  int bucketNumber;
114 
115  bucketNumber = ExecHashGetSkewBucket(hashtable, hashvalue);
116  if (bucketNumber != INVALID_SKEW_BUCKET_NO)
117  {
118  /* It's a skew tuple, so put it into that hash table */
119  ExecHashSkewTableInsert(hashtable, slot, hashvalue,
120  bucketNumber);
121  hashtable->skewTuples += 1;
122  }
123  else
124  {
125  /* Not subject to skew optimization, so insert normally */
126  ExecHashTableInsert(hashtable, slot, hashvalue);
127  }
128  hashtable->totalTuples += 1;
129  }
130  }
131 
132  /* resize the hash table if needed (NTUP_PER_BUCKET exceeded) */
133  if (hashtable->nbuckets != hashtable->nbuckets_optimal)
134  {
135  /* We never decrease the number of buckets. */
136  Assert(hashtable->nbuckets_optimal > hashtable->nbuckets);
137 
138 #ifdef HJDEBUG
139  printf("Increasing nbuckets %d => %d\n",
140  hashtable->nbuckets, hashtable->nbuckets_optimal);
141 #endif
142 
143  ExecHashIncreaseNumBuckets(hashtable);
144  }
145 
146  /* Account for the buckets in spaceUsed (reported in EXPLAIN ANALYZE) */
147  hashtable->spaceUsed += hashtable->nbuckets * sizeof(HashJoinTuple);
148  if (hashtable->spaceUsed > hashtable->spacePeak)
149  hashtable->spacePeak = hashtable->spaceUsed;
150 
151  /* must provide our own instrumentation support */
152  if (node->ps.instrument)
153  InstrStopNode(node->ps.instrument, hashtable->totalTuples);
154 
155  /*
156  * We do not return the hash table directly because it's not a subtype of
157  * Node, and so would violate the MultiExecProcNode API. Instead, our
158  * parent Hashjoin node is expected to know how to fish it out of our node
159  * state. Ugly but not really worth cleaning up, since Hashjoin knows
160  * quite a bit more about Hash besides that.
161  */
162  return NULL;
163 }
164 
165 /* ----------------------------------------------------------------
166  * ExecInitHash
167  *
168  * Init routine for Hash node
169  * ----------------------------------------------------------------
170  */
171 HashState *
172 ExecInitHash(Hash *node, EState *estate, int eflags)
173 {
174  HashState *hashstate;
175 
176  /* check for unsupported flags */
177  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
178 
179  /*
180  * create state structure
181  */
182  hashstate = makeNode(HashState);
183  hashstate->ps.plan = (Plan *) node;
184  hashstate->ps.state = estate;
185  hashstate->hashtable = NULL;
186  hashstate->hashkeys = NIL; /* will be set by parent HashJoin */
187 
188  /*
189  * Miscellaneous initialization
190  *
191  * create expression context for node
192  */
193  ExecAssignExprContext(estate, &hashstate->ps);
194 
195  /*
196  * initialize our result slot
197  */
198  ExecInitResultTupleSlot(estate, &hashstate->ps);
199 
200  /*
201  * initialize child expressions
202  */
203  hashstate->ps.targetlist = (List *)
204  ExecInitExpr((Expr *) node->plan.targetlist,
205  (PlanState *) hashstate);
206  hashstate->ps.qual = (List *)
207  ExecInitExpr((Expr *) node->plan.qual,
208  (PlanState *) hashstate);
209 
210  /*
211  * initialize child nodes
212  */
213  outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags);
214 
215  /*
216  * initialize tuple type. no need to initialize projection info because
217  * this node doesn't do projections
218  */
219  ExecAssignResultTypeFromTL(&hashstate->ps);
220  hashstate->ps.ps_ProjInfo = NULL;
221 
222  return hashstate;
223 }
224 
225 /* ---------------------------------------------------------------
226  * ExecEndHash
227  *
228  * clean up routine for Hash node
229  * ----------------------------------------------------------------
230  */
231 void
233 {
235 
236  /*
237  * free exprcontext
238  */
239  ExecFreeExprContext(&node->ps);
240 
241  /*
242  * shut down the subplan
243  */
244  outerPlan = outerPlanState(node);
245  ExecEndNode(outerPlan);
246 }
247 
248 
249 /* ----------------------------------------------------------------
250  * ExecHashTableCreate
251  *
252  * create an empty hashtable data structure for hashjoin.
253  * ----------------------------------------------------------------
254  */
256 ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
257 {
258  HashJoinTable hashtable;
259  Plan *outerNode;
260  int nbuckets;
261  int nbatch;
262  int num_skew_mcvs;
263  int log2_nbuckets;
264  int nkeys;
265  int i;
266  ListCell *ho;
267  MemoryContext oldcxt;
268 
269  /*
270  * Get information about the size of the relation to be hashed (it's the
271  * "outer" subtree of this node, but the inner relation of the hashjoin).
272  * Compute the appropriate size of the hash table.
273  */
274  outerNode = outerPlan(node);
275 
276  ExecChooseHashTableSize(outerNode->plan_rows, outerNode->plan_width,
277  OidIsValid(node->skewTable),
278  &nbuckets, &nbatch, &num_skew_mcvs);
279 
280 #ifdef HJDEBUG
281  printf("nbatch = %d, nbuckets = %d\n", nbatch, nbuckets);
282 #endif
283 
284  /* nbuckets must be a power of 2 */
285  log2_nbuckets = my_log2(nbuckets);
286  Assert(nbuckets == (1 << log2_nbuckets));
287 
288  /*
289  * Initialize the hash table control block.
290  *
291  * The hashtable control block is just palloc'd from the executor's
292  * per-query memory context.
293  */
294  hashtable = (HashJoinTable) palloc(sizeof(HashJoinTableData));
295  hashtable->nbuckets = nbuckets;
296  hashtable->nbuckets_original = nbuckets;
297  hashtable->nbuckets_optimal = nbuckets;
298  hashtable->log2_nbuckets = log2_nbuckets;
299  hashtable->log2_nbuckets_optimal = log2_nbuckets;
300  hashtable->buckets = NULL;
301  hashtable->keepNulls = keepNulls;
302  hashtable->skewEnabled = false;
303  hashtable->skewBucket = NULL;
304  hashtable->skewBucketLen = 0;
305  hashtable->nSkewBuckets = 0;
306  hashtable->skewBucketNums = NULL;
307  hashtable->nbatch = nbatch;
308  hashtable->curbatch = 0;
309  hashtable->nbatch_original = nbatch;
310  hashtable->nbatch_outstart = nbatch;
311  hashtable->growEnabled = true;
312  hashtable->totalTuples = 0;
313  hashtable->skewTuples = 0;
314  hashtable->innerBatchFile = NULL;
315  hashtable->outerBatchFile = NULL;
316  hashtable->spaceUsed = 0;
317  hashtable->spacePeak = 0;
318  hashtable->spaceAllowed = work_mem * 1024L;
319  hashtable->spaceUsedSkew = 0;
320  hashtable->spaceAllowedSkew =
321  hashtable->spaceAllowed * SKEW_WORK_MEM_PERCENT / 100;
322  hashtable->chunks = NULL;
323 
324  /*
325  * Get info about the hash functions to be used for each hash key. Also
326  * remember whether the join operators are strict.
327  */
328  nkeys = list_length(hashOperators);
329  hashtable->outer_hashfunctions =
330  (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
331  hashtable->inner_hashfunctions =
332  (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
333  hashtable->hashStrict = (bool *) palloc(nkeys * sizeof(bool));
334  i = 0;
335  foreach(ho, hashOperators)
336  {
337  Oid hashop = lfirst_oid(ho);
338  Oid left_hashfn;
339  Oid right_hashfn;
340 
341  if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
342  elog(ERROR, "could not find hash function for hash operator %u",
343  hashop);
344  fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]);
345  fmgr_info(right_hashfn, &hashtable->inner_hashfunctions[i]);
346  hashtable->hashStrict[i] = op_strict(hashop);
347  i++;
348  }
349 
350  /*
351  * Create temporary memory contexts in which to keep the hashtable working
352  * storage. See notes in executor/hashjoin.h.
353  */
355  "HashTableContext",
359 
360  hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
361  "HashBatchContext",
365 
366  /* Allocate data that will live for the life of the hashjoin */
367 
368  oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
369 
370  if (nbatch > 1)
371  {
372  /*
373  * allocate and initialize the file arrays in hashCxt
374  */
375  hashtable->innerBatchFile = (BufFile **)
376  palloc0(nbatch * sizeof(BufFile *));
377  hashtable->outerBatchFile = (BufFile **)
378  palloc0(nbatch * sizeof(BufFile *));
379  /* The files will not be opened until needed... */
380  /* ... but make sure we have temp tablespaces established for them */
382  }
383 
384  /*
385  * Prepare context for the first-scan space allocations; allocate the
386  * hashbucket array therein, and set each bucket "empty".
387  */
388  MemoryContextSwitchTo(hashtable->batchCxt);
389 
390  hashtable->buckets = (HashJoinTuple *)
391  palloc0(nbuckets * sizeof(HashJoinTuple));
392 
393  /*
394  * Set up for skew optimization, if possible and there's a need for more
395  * than one batch. (In a one-batch join, there's no point in it.)
396  */
397  if (nbatch > 1)
398  ExecHashBuildSkewHash(hashtable, node, num_skew_mcvs);
399 
400  MemoryContextSwitchTo(oldcxt);
401 
402  return hashtable;
403 }
404 
405 
406 /*
407  * Compute appropriate size for hashtable given the estimated size of the
408  * relation to be hashed (number of rows and average row width).
409  *
410  * This is exported so that the planner's costsize.c can use it.
411  */
412 
413 /* Target bucket loading (tuples per bucket) */
414 #define NTUP_PER_BUCKET 1
415 
416 void
417 ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew,
418  int *numbuckets,
419  int *numbatches,
420  int *num_skew_mcvs)
421 {
422  int tupsize;
423  double inner_rel_bytes;
424  long bucket_bytes;
425  long hash_table_bytes;
426  long skew_table_bytes;
427  long max_pointers;
428  int nbatch = 1;
429  int nbuckets;
430  double dbuckets;
431 
432  /* Force a plausible relation size if no info */
433  if (ntuples <= 0.0)
434  ntuples = 1000.0;
435 
436  /*
437  * Estimate tupsize based on footprint of tuple in hashtable... note this
438  * does not allow for any palloc overhead. The manipulations of spaceUsed
439  * don't count palloc overhead either.
440  */
441  tupsize = HJTUPLE_OVERHEAD +
443  MAXALIGN(tupwidth);
444  inner_rel_bytes = ntuples * tupsize;
445 
446  /*
447  * Target in-memory hashtable size is work_mem kilobytes.
448  */
449  hash_table_bytes = work_mem * 1024L;
450 
451  /*
452  * If skew optimization is possible, estimate the number of skew buckets
453  * that will fit in the memory allowed, and decrement the assumed space
454  * available for the main hash table accordingly.
455  *
456  * We make the optimistic assumption that each skew bucket will contain
457  * one inner-relation tuple. If that turns out to be low, we will recover
458  * at runtime by reducing the number of skew buckets.
459  *
460  * hashtable->skewBucket will have up to 8 times as many HashSkewBucket
461  * pointers as the number of MCVs we allow, since ExecHashBuildSkewHash
462  * will round up to the next power of 2 and then multiply by 4 to reduce
463  * collisions.
464  */
465  if (useskew)
466  {
467  skew_table_bytes = hash_table_bytes * SKEW_WORK_MEM_PERCENT / 100;
468 
469  /*----------
470  * Divisor is:
471  * size of a hash tuple +
472  * worst-case size of skewBucket[] per MCV +
473  * size of skewBucketNums[] entry +
474  * size of skew bucket struct itself
475  *----------
476  */
477  *num_skew_mcvs = skew_table_bytes / (tupsize +
478  (8 * sizeof(HashSkewBucket *)) +
479  sizeof(int) +
481  if (*num_skew_mcvs > 0)
482  hash_table_bytes -= skew_table_bytes;
483  }
484  else
485  *num_skew_mcvs = 0;
486 
487  /*
488  * Set nbuckets to achieve an average bucket load of NTUP_PER_BUCKET when
489  * memory is filled, assuming a single batch. The Min() step limits the
490  * results so that the pointer arrays we'll try to allocate do not exceed
491  * work_mem.
492  */
493  max_pointers = (work_mem * 1024L) / sizeof(void *);
494  /* also ensure we avoid integer overflow in nbatch and nbuckets */
495  max_pointers = Min(max_pointers, INT_MAX / 2);
496  dbuckets = ceil(ntuples / NTUP_PER_BUCKET);
497  dbuckets = Min(dbuckets, max_pointers);
498  nbuckets = Max((int) dbuckets, 1024);
499  nbuckets = 1 << my_log2(nbuckets);
500  bucket_bytes = sizeof(HashJoinTuple) * nbuckets;
501 
502  /*
503  * If there's not enough space to store the projected number of tuples and
504  * the required bucket headers, we will need multiple batches.
505  */
506  if (inner_rel_bytes + bucket_bytes > hash_table_bytes)
507  {
508  /* We'll need multiple batches */
509  long lbuckets;
510  double dbatch;
511  int minbatch;
512  long bucket_size;
513 
514  /*
515  * Estimate the number of buckets we'll want to have when work_mem is
516  * entirely full. Each bucket will contain a bucket pointer plus
517  * NTUP_PER_BUCKET tuples, whose projected size already includes
518  * overhead for the hash code, pointer to the next tuple, etc.
519  */
520  bucket_size = (tupsize * NTUP_PER_BUCKET + sizeof(HashJoinTuple));
521  lbuckets = 1L << my_log2(hash_table_bytes / bucket_size);
522  lbuckets = Min(lbuckets, max_pointers);
523  nbuckets = (int) lbuckets;
524  bucket_bytes = nbuckets * sizeof(HashJoinTuple);
525 
526  /*
527  * Buckets are simple pointers to hashjoin tuples, while tupsize
528  * includes the pointer, hash code, and MinimalTupleData. So buckets
529  * should never really exceed 25% of work_mem (even for
530  * NTUP_PER_BUCKET=1); except maybe for work_mem values that are not
531  * 2^N bytes, where we might get more because of doubling. So let's
532  * look for 50% here.
533  */
534  Assert(bucket_bytes <= hash_table_bytes / 2);
535 
536  /* Calculate required number of batches. */
537  dbatch = ceil(inner_rel_bytes / (hash_table_bytes - bucket_bytes));
538  dbatch = Min(dbatch, max_pointers);
539  minbatch = (int) dbatch;
540  nbatch = 2;
541  while (nbatch < minbatch)
542  nbatch <<= 1;
543  }
544 
545  Assert(nbuckets > 0);
546  Assert(nbatch > 0);
547 
548  *numbuckets = nbuckets;
549  *numbatches = nbatch;
550 }
551 
552 
553 /* ----------------------------------------------------------------
554  * ExecHashTableDestroy
555  *
556  * destroy a hash table
557  * ----------------------------------------------------------------
558  */
559 void
561 {
562  int i;
563 
564  /*
565  * Make sure all the temp files are closed. We skip batch 0, since it
566  * can't have any temp files (and the arrays might not even exist if
567  * nbatch is only 1).
568  */
569  for (i = 1; i < hashtable->nbatch; i++)
570  {
571  if (hashtable->innerBatchFile[i])
572  BufFileClose(hashtable->innerBatchFile[i]);
573  if (hashtable->outerBatchFile[i])
574  BufFileClose(hashtable->outerBatchFile[i]);
575  }
576 
577  /* Release working memory (batchCxt is a child, so it goes away too) */
578  MemoryContextDelete(hashtable->hashCxt);
579 
580  /* And drop the control block */
581  pfree(hashtable);
582 }
583 
584 /*
585  * ExecHashIncreaseNumBatches
586  * increase the original number of batches in order to reduce
587  * current memory consumption
588  */
589 static void
591 {
592  int oldnbatch = hashtable->nbatch;
593  int curbatch = hashtable->curbatch;
594  int nbatch;
595  MemoryContext oldcxt;
596  long ninmemory;
597  long nfreed;
598  HashMemoryChunk oldchunks;
599 
600  /* do nothing if we've decided to shut off growth */
601  if (!hashtable->growEnabled)
602  return;
603 
604  /* safety check to avoid overflow */
605  if (oldnbatch > Min(INT_MAX / 2, MaxAllocSize / (sizeof(void *) * 2)))
606  return;
607 
608  nbatch = oldnbatch * 2;
609  Assert(nbatch > 1);
610 
611 #ifdef HJDEBUG
612  printf("Increasing nbatch to %d because space = %lu\n",
613  nbatch, (unsigned long) hashtable->spaceUsed);
614 #endif
615 
616  oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
617 
618  if (hashtable->innerBatchFile == NULL)
619  {
620  /* we had no file arrays before */
621  hashtable->innerBatchFile = (BufFile **)
622  palloc0(nbatch * sizeof(BufFile *));
623  hashtable->outerBatchFile = (BufFile **)
624  palloc0(nbatch * sizeof(BufFile *));
625  /* time to establish the temp tablespaces, too */
627  }
628  else
629  {
630  /* enlarge arrays and zero out added entries */
631  hashtable->innerBatchFile = (BufFile **)
632  repalloc(hashtable->innerBatchFile, nbatch * sizeof(BufFile *));
633  hashtable->outerBatchFile = (BufFile **)
634  repalloc(hashtable->outerBatchFile, nbatch * sizeof(BufFile *));
635  MemSet(hashtable->innerBatchFile + oldnbatch, 0,
636  (nbatch - oldnbatch) * sizeof(BufFile *));
637  MemSet(hashtable->outerBatchFile + oldnbatch, 0,
638  (nbatch - oldnbatch) * sizeof(BufFile *));
639  }
640 
641  MemoryContextSwitchTo(oldcxt);
642 
643  hashtable->nbatch = nbatch;
644 
645  /*
646  * Scan through the existing hash table entries and dump out any that are
647  * no longer of the current batch.
648  */
649  ninmemory = nfreed = 0;
650 
651  /* If know we need to resize nbuckets, we can do it while rebatching. */
652  if (hashtable->nbuckets_optimal != hashtable->nbuckets)
653  {
654  /* we never decrease the number of buckets */
655  Assert(hashtable->nbuckets_optimal > hashtable->nbuckets);
656 
657  hashtable->nbuckets = hashtable->nbuckets_optimal;
658  hashtable->log2_nbuckets = hashtable->log2_nbuckets_optimal;
659 
660  hashtable->buckets = repalloc(hashtable->buckets,
661  sizeof(HashJoinTuple) * hashtable->nbuckets);
662  }
663 
664  /*
665  * We will scan through the chunks directly, so that we can reset the
666  * buckets now and not have to keep track which tuples in the buckets have
667  * already been processed. We will free the old chunks as we go.
668  */
669  memset(hashtable->buckets, 0, sizeof(HashJoinTuple) * hashtable->nbuckets);
670  oldchunks = hashtable->chunks;
671  hashtable->chunks = NULL;
672 
673  /* so, let's scan through the old chunks, and all tuples in each chunk */
674  while (oldchunks != NULL)
675  {
676  HashMemoryChunk nextchunk = oldchunks->next;
677 
678  /* position within the buffer (up to oldchunks->used) */
679  size_t idx = 0;
680 
681  /* process all tuples stored in this chunk (and then free it) */
682  while (idx < oldchunks->used)
683  {
684  HashJoinTuple hashTuple = (HashJoinTuple) (oldchunks->data + idx);
685  MinimalTuple tuple = HJTUPLE_MINTUPLE(hashTuple);
686  int hashTupleSize = (HJTUPLE_OVERHEAD + tuple->t_len);
687  int bucketno;
688  int batchno;
689 
690  ninmemory++;
691  ExecHashGetBucketAndBatch(hashtable, hashTuple->hashvalue,
692  &bucketno, &batchno);
693 
694  if (batchno == curbatch)
695  {
696  /* keep tuple in memory - copy it into the new chunk */
697  HashJoinTuple copyTuple;
698 
699  copyTuple = (HashJoinTuple) dense_alloc(hashtable, hashTupleSize);
700  memcpy(copyTuple, hashTuple, hashTupleSize);
701 
702  /* and add it back to the appropriate bucket */
703  copyTuple->next = hashtable->buckets[bucketno];
704  hashtable->buckets[bucketno] = copyTuple;
705  }
706  else
707  {
708  /* dump it out */
709  Assert(batchno > curbatch);
711  hashTuple->hashvalue,
712  &hashtable->innerBatchFile[batchno]);
713 
714  hashtable->spaceUsed -= hashTupleSize;
715  nfreed++;
716  }
717 
718  /* next tuple in this chunk */
719  idx += MAXALIGN(hashTupleSize);
720  }
721 
722  /* we're done with this chunk - free it and proceed to the next one */
723  pfree(oldchunks);
724  oldchunks = nextchunk;
725  }
726 
727 #ifdef HJDEBUG
728  printf("Freed %ld of %ld tuples, space now %lu\n",
729  nfreed, ninmemory, (unsigned long) hashtable->spaceUsed);
730 #endif
731 
732  /*
733  * If we dumped out either all or none of the tuples in the table, disable
734  * further expansion of nbatch. This situation implies that we have
735  * enough tuples of identical hashvalues to overflow spaceAllowed.
736  * Increasing nbatch will not fix it since there's no way to subdivide the
737  * group any more finely. We have to just gut it out and hope the server
738  * has enough RAM.
739  */
740  if (nfreed == 0 || nfreed == ninmemory)
741  {
742  hashtable->growEnabled = false;
743 #ifdef HJDEBUG
744  printf("Disabling further increase of nbatch\n");
745 #endif
746  }
747 }
748 
749 /*
750  * ExecHashIncreaseNumBuckets
751  * increase the original number of buckets in order to reduce
752  * number of tuples per bucket
753  */
754 static void
756 {
757  HashMemoryChunk chunk;
758 
759  /* do nothing if not an increase (it's called increase for a reason) */
760  if (hashtable->nbuckets >= hashtable->nbuckets_optimal)
761  return;
762 
763  /*
764  * We already know the optimal number of buckets, so let's just compute
765  * the log2_nbuckets for it.
766  */
767  hashtable->nbuckets = hashtable->nbuckets_optimal;
768  hashtable->log2_nbuckets = my_log2(hashtable->nbuckets_optimal);
769 
770  Assert(hashtable->nbuckets > 1);
771  Assert(hashtable->nbuckets <= (INT_MAX / 2));
772  Assert(hashtable->nbuckets == (1 << hashtable->log2_nbuckets));
773 
774 #ifdef HJDEBUG
775  printf("Increasing nbuckets to %d\n", hashtable->nbuckets);
776 #endif
777 
778  /*
779  * Just reallocate the proper number of buckets - we don't need to walk
780  * through them - we can walk the dense-allocated chunks (just like in
781  * ExecHashIncreaseNumBatches, but without all the copying into new
782  * chunks)
783  */
784  hashtable->buckets =
785  (HashJoinTuple *) repalloc(hashtable->buckets,
786  hashtable->nbuckets * sizeof(HashJoinTuple));
787 
788  memset(hashtable->buckets, 0, sizeof(void *) * hashtable->nbuckets);
789 
790  /* scan through all tuples in all chunks to rebuild the hash table */
791  for (chunk = hashtable->chunks; chunk != NULL; chunk = chunk->next)
792  {
793  /* process all tuples stored in this chunk */
794  size_t idx = 0;
795 
796  while (idx < chunk->used)
797  {
798  HashJoinTuple hashTuple = (HashJoinTuple) (chunk->data + idx);
799  int bucketno;
800  int batchno;
801 
802  ExecHashGetBucketAndBatch(hashtable, hashTuple->hashvalue,
803  &bucketno, &batchno);
804 
805  /* add the tuple to the proper bucket */
806  hashTuple->next = hashtable->buckets[bucketno];
807  hashtable->buckets[bucketno] = hashTuple;
808 
809  /* advance index past the tuple */
810  idx += MAXALIGN(HJTUPLE_OVERHEAD +
811  HJTUPLE_MINTUPLE(hashTuple)->t_len);
812  }
813  }
814 
815 #ifdef HJDEBUG
816  printf("Nbuckets increased to %d, average items per bucket %.1f\n",
817  hashtable->nbuckets, batchTuples / hashtable->nbuckets);
818 #endif
819 }
820 
821 
822 /*
823  * ExecHashTableInsert
824  * insert a tuple into the hash table depending on the hash value
825  * it may just go to a temp file for later batches
826  *
827  * Note: the passed TupleTableSlot may contain a regular, minimal, or virtual
828  * tuple; the minimal case in particular is certain to happen while reloading
829  * tuples from batch files. We could save some cycles in the regular-tuple
830  * case by not forcing the slot contents into minimal form; not clear if it's
831  * worth the messiness required.
832  */
833 void
835  TupleTableSlot *slot,
836  uint32 hashvalue)
837 {
839  int bucketno;
840  int batchno;
841 
842  ExecHashGetBucketAndBatch(hashtable, hashvalue,
843  &bucketno, &batchno);
844 
845  /*
846  * decide whether to put the tuple in the hash table or a temp file
847  */
848  if (batchno == hashtable->curbatch)
849  {
850  /*
851  * put the tuple in hash table
852  */
853  HashJoinTuple hashTuple;
854  int hashTupleSize;
855  double ntuples = (hashtable->totalTuples - hashtable->skewTuples);
856 
857  /* Create the HashJoinTuple */
858  hashTupleSize = HJTUPLE_OVERHEAD + tuple->t_len;
859  hashTuple = (HashJoinTuple) dense_alloc(hashtable, hashTupleSize);
860 
861  hashTuple->hashvalue = hashvalue;
862  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
863 
864  /*
865  * We always reset the tuple-matched flag on insertion. This is okay
866  * even when reloading a tuple from a batch file, since the tuple
867  * could not possibly have been matched to an outer tuple before it
868  * went into the batch file.
869  */
871 
872  /* Push it onto the front of the bucket's list */
873  hashTuple->next = hashtable->buckets[bucketno];
874  hashtable->buckets[bucketno] = hashTuple;
875 
876  /*
877  * Increase the (optimal) number of buckets if we just exceeded the
878  * NTUP_PER_BUCKET threshold, but only when there's still a single
879  * batch.
880  */
881  if ((hashtable->nbatch == 1) &&
882  (hashtable->nbuckets_optimal <= INT_MAX / 2) && /* overflow protection */
883  (ntuples >= (hashtable->nbuckets_optimal * NTUP_PER_BUCKET)))
884  {
885  hashtable->nbuckets_optimal *= 2;
886  hashtable->log2_nbuckets_optimal += 1;
887  }
888 
889  /* Account for space used, and back off if we've used too much */
890  hashtable->spaceUsed += hashTupleSize;
891  if (hashtable->spaceUsed > hashtable->spacePeak)
892  hashtable->spacePeak = hashtable->spaceUsed;
893  if (hashtable->spaceUsed +
894  hashtable->nbuckets_optimal * sizeof(HashJoinTuple)
895  > hashtable->spaceAllowed)
896  ExecHashIncreaseNumBatches(hashtable);
897  }
898  else
899  {
900  /*
901  * put the tuple into a temp file for later batches
902  */
903  Assert(batchno > hashtable->curbatch);
904  ExecHashJoinSaveTuple(tuple,
905  hashvalue,
906  &hashtable->innerBatchFile[batchno]);
907  }
908 }
909 
910 /*
911  * ExecHashGetHashValue
912  * Compute the hash value for a tuple
913  *
914  * The tuple to be tested must be in either econtext->ecxt_outertuple or
915  * econtext->ecxt_innertuple. Vars in the hashkeys expressions should have
916  * varno either OUTER_VAR or INNER_VAR.
917  *
918  * A TRUE result means the tuple's hash value has been successfully computed
919  * and stored at *hashvalue. A FALSE result means the tuple cannot match
920  * because it contains a null attribute, and hence it should be discarded
921  * immediately. (If keep_nulls is true then FALSE is never returned.)
922  */
923 bool
925  ExprContext *econtext,
926  List *hashkeys,
927  bool outer_tuple,
928  bool keep_nulls,
929  uint32 *hashvalue)
930 {
931  uint32 hashkey = 0;
932  FmgrInfo *hashfunctions;
933  ListCell *hk;
934  int i = 0;
935  MemoryContext oldContext;
936 
937  /*
938  * We reset the eval context each time to reclaim any memory leaked in the
939  * hashkey expressions.
940  */
941  ResetExprContext(econtext);
942 
943  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
944 
945  if (outer_tuple)
946  hashfunctions = hashtable->outer_hashfunctions;
947  else
948  hashfunctions = hashtable->inner_hashfunctions;
949 
950  foreach(hk, hashkeys)
951  {
952  ExprState *keyexpr = (ExprState *) lfirst(hk);
953  Datum keyval;
954  bool isNull;
955 
956  /* rotate hashkey left 1 bit at each step */
957  hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
958 
959  /*
960  * Get the join attribute value of the tuple
961  */
962  keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL);
963 
964  /*
965  * If the attribute is NULL, and the join operator is strict, then
966  * this tuple cannot pass the join qual so we can reject it
967  * immediately (unless we're scanning the outside of an outer join, in
968  * which case we must not reject it). Otherwise we act like the
969  * hashcode of NULL is zero (this will support operators that act like
970  * IS NOT DISTINCT, though not any more-random behavior). We treat
971  * the hash support function as strict even if the operator is not.
972  *
973  * Note: currently, all hashjoinable operators must be strict since
974  * the hash index AM assumes that. However, it takes so little extra
975  * code here to allow non-strict that we may as well do it.
976  */
977  if (isNull)
978  {
979  if (hashtable->hashStrict[i] && !keep_nulls)
980  {
981  MemoryContextSwitchTo(oldContext);
982  return false; /* cannot match */
983  }
984  /* else, leave hashkey unmodified, equivalent to hashcode 0 */
985  }
986  else
987  {
988  /* Compute the hash function */
989  uint32 hkey;
990 
991  hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i], keyval));
992  hashkey ^= hkey;
993  }
994 
995  i++;
996  }
997 
998  MemoryContextSwitchTo(oldContext);
999 
1000  *hashvalue = hashkey;
1001  return true;
1002 }
1003 
1004 /*
1005  * ExecHashGetBucketAndBatch
1006  * Determine the bucket number and batch number for a hash value
1007  *
1008  * Note: on-the-fly increases of nbatch must not change the bucket number
1009  * for a given hash code (since we don't move tuples to different hash
1010  * chains), and must only cause the batch number to remain the same or
1011  * increase. Our algorithm is
1012  * bucketno = hashvalue MOD nbuckets
1013  * batchno = (hashvalue DIV nbuckets) MOD nbatch
1014  * where nbuckets and nbatch are both expected to be powers of 2, so we can
1015  * do the computations by shifting and masking. (This assumes that all hash
1016  * functions are good about randomizing all their output bits, else we are
1017  * likely to have very skewed bucket or batch occupancy.)
1018  *
1019  * nbuckets and log2_nbuckets may change while nbatch == 1 because of dynamic
1020  * bucket count growth. Once we start batching, the value is fixed and does
1021  * not change over the course of the join (making it possible to compute batch
1022  * number the way we do here).
1023  *
1024  * nbatch is always a power of 2; we increase it only by doubling it. This
1025  * effectively adds one more bit to the top of the batchno.
1026  */
1027 void
1029  uint32 hashvalue,
1030  int *bucketno,
1031  int *batchno)
1032 {
1033  uint32 nbuckets = (uint32) hashtable->nbuckets;
1034  uint32 nbatch = (uint32) hashtable->nbatch;
1035 
1036  if (nbatch > 1)
1037  {
1038  /* we can do MOD by masking, DIV by shifting */
1039  *bucketno = hashvalue & (nbuckets - 1);
1040  *batchno = (hashvalue >> hashtable->log2_nbuckets) & (nbatch - 1);
1041  }
1042  else
1043  {
1044  *bucketno = hashvalue & (nbuckets - 1);
1045  *batchno = 0;
1046  }
1047 }
1048 
1049 /*
1050  * ExecScanHashBucket
1051  * scan a hash bucket for matches to the current outer tuple
1052  *
1053  * The current outer tuple must be stored in econtext->ecxt_outertuple.
1054  *
1055  * On success, the inner tuple is stored into hjstate->hj_CurTuple and
1056  * econtext->ecxt_innertuple, using hjstate->hj_HashTupleSlot as the slot
1057  * for the latter.
1058  */
1059 bool
1061  ExprContext *econtext)
1062 {
1063  List *hjclauses = hjstate->hashclauses;
1064  HashJoinTable hashtable = hjstate->hj_HashTable;
1065  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
1066  uint32 hashvalue = hjstate->hj_CurHashValue;
1067 
1068  /*
1069  * hj_CurTuple is the address of the tuple last returned from the current
1070  * bucket, or NULL if it's time to start scanning a new bucket.
1071  *
1072  * If the tuple hashed to a skew bucket then scan the skew bucket
1073  * otherwise scan the standard hashtable bucket.
1074  */
1075  if (hashTuple != NULL)
1076  hashTuple = hashTuple->next;
1077  else if (hjstate->hj_CurSkewBucketNo != INVALID_SKEW_BUCKET_NO)
1078  hashTuple = hashtable->skewBucket[hjstate->hj_CurSkewBucketNo]->tuples;
1079  else
1080  hashTuple = hashtable->buckets[hjstate->hj_CurBucketNo];
1081 
1082  while (hashTuple != NULL)
1083  {
1084  if (hashTuple->hashvalue == hashvalue)
1085  {
1086  TupleTableSlot *inntuple;
1087 
1088  /* insert hashtable's tuple into exec slot so ExecQual sees it */
1089  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
1090  hjstate->hj_HashTupleSlot,
1091  false); /* do not pfree */
1092  econtext->ecxt_innertuple = inntuple;
1093 
1094  /* reset temp memory each time to avoid leaks from qual expr */
1095  ResetExprContext(econtext);
1096 
1097  if (ExecQual(hjclauses, econtext, false))
1098  {
1099  hjstate->hj_CurTuple = hashTuple;
1100  return true;
1101  }
1102  }
1103 
1104  hashTuple = hashTuple->next;
1105  }
1106 
1107  /*
1108  * no match
1109  */
1110  return false;
1111 }
1112 
1113 /*
1114  * ExecPrepHashTableForUnmatched
1115  * set up for a series of ExecScanHashTableForUnmatched calls
1116  */
1117 void
1119 {
1120  /*
1121  * ---------- During this scan we use the HashJoinState fields as follows:
1122  *
1123  * hj_CurBucketNo: next regular bucket to scan hj_CurSkewBucketNo: next
1124  * skew bucket (an index into skewBucketNums) hj_CurTuple: last tuple
1125  * returned, or NULL to start next bucket ----------
1126  */
1127  hjstate->hj_CurBucketNo = 0;
1128  hjstate->hj_CurSkewBucketNo = 0;
1129  hjstate->hj_CurTuple = NULL;
1130 }
1131 
1132 /*
1133  * ExecScanHashTableForUnmatched
1134  * scan the hash table for unmatched inner tuples
1135  *
1136  * On success, the inner tuple is stored into hjstate->hj_CurTuple and
1137  * econtext->ecxt_innertuple, using hjstate->hj_HashTupleSlot as the slot
1138  * for the latter.
1139  */
1140 bool
1142 {
1143  HashJoinTable hashtable = hjstate->hj_HashTable;
1144  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
1145 
1146  for (;;)
1147  {
1148  /*
1149  * hj_CurTuple is the address of the tuple last returned from the
1150  * current bucket, or NULL if it's time to start scanning a new
1151  * bucket.
1152  */
1153  if (hashTuple != NULL)
1154  hashTuple = hashTuple->next;
1155  else if (hjstate->hj_CurBucketNo < hashtable->nbuckets)
1156  {
1157  hashTuple = hashtable->buckets[hjstate->hj_CurBucketNo];
1158  hjstate->hj_CurBucketNo++;
1159  }
1160  else if (hjstate->hj_CurSkewBucketNo < hashtable->nSkewBuckets)
1161  {
1162  int j = hashtable->skewBucketNums[hjstate->hj_CurSkewBucketNo];
1163 
1164  hashTuple = hashtable->skewBucket[j]->tuples;
1165  hjstate->hj_CurSkewBucketNo++;
1166  }
1167  else
1168  break; /* finished all buckets */
1169 
1170  while (hashTuple != NULL)
1171  {
1172  if (!HeapTupleHeaderHasMatch(HJTUPLE_MINTUPLE(hashTuple)))
1173  {
1174  TupleTableSlot *inntuple;
1175 
1176  /* insert hashtable's tuple into exec slot */
1177  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
1178  hjstate->hj_HashTupleSlot,
1179  false); /* do not pfree */
1180  econtext->ecxt_innertuple = inntuple;
1181 
1182  /*
1183  * Reset temp memory each time; although this function doesn't
1184  * do any qual eval, the caller will, so let's keep it
1185  * parallel to ExecScanHashBucket.
1186  */
1187  ResetExprContext(econtext);
1188 
1189  hjstate->hj_CurTuple = hashTuple;
1190  return true;
1191  }
1192 
1193  hashTuple = hashTuple->next;
1194  }
1195  }
1196 
1197  /*
1198  * no more unmatched tuples
1199  */
1200  return false;
1201 }
1202 
1203 /*
1204  * ExecHashTableReset
1205  *
1206  * reset hash table header for new batch
1207  */
1208 void
1210 {
1211  MemoryContext oldcxt;
1212  int nbuckets = hashtable->nbuckets;
1213 
1214  /*
1215  * Release all the hash buckets and tuples acquired in the prior pass, and
1216  * reinitialize the context for a new pass.
1217  */
1218  MemoryContextReset(hashtable->batchCxt);
1219  oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
1220 
1221  /* Reallocate and reinitialize the hash bucket headers. */
1222  hashtable->buckets = (HashJoinTuple *)
1223  palloc0(nbuckets * sizeof(HashJoinTuple));
1224 
1225  hashtable->spaceUsed = 0;
1226 
1227  MemoryContextSwitchTo(oldcxt);
1228 
1229  /* Forget the chunks (the memory was freed by the context reset above). */
1230  hashtable->chunks = NULL;
1231 }
1232 
1233 /*
1234  * ExecHashTableResetMatchFlags
1235  * Clear all the HeapTupleHeaderHasMatch flags in the table
1236  */
1237 void
1239 {
1240  HashJoinTuple tuple;
1241  int i;
1242 
1243  /* Reset all flags in the main table ... */
1244  for (i = 0; i < hashtable->nbuckets; i++)
1245  {
1246  for (tuple = hashtable->buckets[i]; tuple != NULL; tuple = tuple->next)
1248  }
1249 
1250  /* ... and the same for the skew buckets, if any */
1251  for (i = 0; i < hashtable->nSkewBuckets; i++)
1252  {
1253  int j = hashtable->skewBucketNums[i];
1254  HashSkewBucket *skewBucket = hashtable->skewBucket[j];
1255 
1256  for (tuple = skewBucket->tuples; tuple != NULL; tuple = tuple->next)
1258  }
1259 }
1260 
1261 
1262 void
1264 {
1265  /*
1266  * if chgParam of subnode is not null then plan will be re-scanned by
1267  * first ExecProcNode.
1268  */
1269  if (node->ps.lefttree->chgParam == NULL)
1270  ExecReScan(node->ps.lefttree);
1271 }
1272 
1273 
1274 /*
1275  * ExecHashBuildSkewHash
1276  *
1277  * Set up for skew optimization if we can identify the most common values
1278  * (MCVs) of the outer relation's join key. We make a skew hash bucket
1279  * for the hash value of each MCV, up to the number of slots allowed
1280  * based on available memory.
1281  */
1282 static void
1283 ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
1284 {
1285  HeapTupleData *statsTuple;
1286  Datum *values;
1287  int nvalues;
1288  float4 *numbers;
1289  int nnumbers;
1290 
1291  /* Do nothing if planner didn't identify the outer relation's join key */
1292  if (!OidIsValid(node->skewTable))
1293  return;
1294  /* Also, do nothing if we don't have room for at least one skew bucket */
1295  if (mcvsToUse <= 0)
1296  return;
1297 
1298  /*
1299  * Try to find the MCV statistics for the outer relation's join key.
1300  */
1301  statsTuple = SearchSysCache3(STATRELATTINH,
1302  ObjectIdGetDatum(node->skewTable),
1303  Int16GetDatum(node->skewColumn),
1304  BoolGetDatum(node->skewInherit));
1305  if (!HeapTupleIsValid(statsTuple))
1306  return;
1307 
1308  if (get_attstatsslot(statsTuple, node->skewColType, node->skewColTypmod,
1310  NULL,
1311  &values, &nvalues,
1312  &numbers, &nnumbers))
1313  {
1314  double frac;
1315  int nbuckets;
1316  FmgrInfo *hashfunctions;
1317  int i;
1318 
1319  if (mcvsToUse > nvalues)
1320  mcvsToUse = nvalues;
1321 
1322  /*
1323  * Calculate the expected fraction of outer relation that will
1324  * participate in the skew optimization. If this isn't at least
1325  * SKEW_MIN_OUTER_FRACTION, don't use skew optimization.
1326  */
1327  frac = 0;
1328  for (i = 0; i < mcvsToUse; i++)
1329  frac += numbers[i];
1330  if (frac < SKEW_MIN_OUTER_FRACTION)
1331  {
1333  values, nvalues, numbers, nnumbers);
1334  ReleaseSysCache(statsTuple);
1335  return;
1336  }
1337 
1338  /*
1339  * Okay, set up the skew hashtable.
1340  *
1341  * skewBucket[] is an open addressing hashtable with a power of 2 size
1342  * that is greater than the number of MCV values. (This ensures there
1343  * will be at least one null entry, so searches will always
1344  * terminate.)
1345  *
1346  * Note: this code could fail if mcvsToUse exceeds INT_MAX/8 or
1347  * MaxAllocSize/sizeof(void *)/8, but that is not currently possible
1348  * since we limit pg_statistic entries to much less than that.
1349  */
1350  nbuckets = 2;
1351  while (nbuckets <= mcvsToUse)
1352  nbuckets <<= 1;
1353  /* use two more bits just to help avoid collisions */
1354  nbuckets <<= 2;
1355 
1356  hashtable->skewEnabled = true;
1357  hashtable->skewBucketLen = nbuckets;
1358 
1359  /*
1360  * We allocate the bucket memory in the hashtable's batch context. It
1361  * is only needed during the first batch, and this ensures it will be
1362  * automatically removed once the first batch is done.
1363  */
1364  hashtable->skewBucket = (HashSkewBucket **)
1365  MemoryContextAllocZero(hashtable->batchCxt,
1366  nbuckets * sizeof(HashSkewBucket *));
1367  hashtable->skewBucketNums = (int *)
1368  MemoryContextAllocZero(hashtable->batchCxt,
1369  mcvsToUse * sizeof(int));
1370 
1371  hashtable->spaceUsed += nbuckets * sizeof(HashSkewBucket *)
1372  + mcvsToUse * sizeof(int);
1373  hashtable->spaceUsedSkew += nbuckets * sizeof(HashSkewBucket *)
1374  + mcvsToUse * sizeof(int);
1375  if (hashtable->spaceUsed > hashtable->spacePeak)
1376  hashtable->spacePeak = hashtable->spaceUsed;
1377 
1378  /*
1379  * Create a skew bucket for each MCV hash value.
1380  *
1381  * Note: it is very important that we create the buckets in order of
1382  * decreasing MCV frequency. If we have to remove some buckets, they
1383  * must be removed in reverse order of creation (see notes in
1384  * ExecHashRemoveNextSkewBucket) and we want the least common MCVs to
1385  * be removed first.
1386  */
1387  hashfunctions = hashtable->outer_hashfunctions;
1388 
1389  for (i = 0; i < mcvsToUse; i++)
1390  {
1391  uint32 hashvalue;
1392  int bucket;
1393 
1394  hashvalue = DatumGetUInt32(FunctionCall1(&hashfunctions[0],
1395  values[i]));
1396 
1397  /*
1398  * While we have not hit a hole in the hashtable and have not hit
1399  * the desired bucket, we have collided with some previous hash
1400  * value, so try the next bucket location. NB: this code must
1401  * match ExecHashGetSkewBucket.
1402  */
1403  bucket = hashvalue & (nbuckets - 1);
1404  while (hashtable->skewBucket[bucket] != NULL &&
1405  hashtable->skewBucket[bucket]->hashvalue != hashvalue)
1406  bucket = (bucket + 1) & (nbuckets - 1);
1407 
1408  /*
1409  * If we found an existing bucket with the same hashvalue, leave
1410  * it alone. It's okay for two MCVs to share a hashvalue.
1411  */
1412  if (hashtable->skewBucket[bucket] != NULL)
1413  continue;
1414 
1415  /* Okay, create a new skew bucket for this hashvalue. */
1416  hashtable->skewBucket[bucket] = (HashSkewBucket *)
1417  MemoryContextAlloc(hashtable->batchCxt,
1418  sizeof(HashSkewBucket));
1419  hashtable->skewBucket[bucket]->hashvalue = hashvalue;
1420  hashtable->skewBucket[bucket]->tuples = NULL;
1421  hashtable->skewBucketNums[hashtable->nSkewBuckets] = bucket;
1422  hashtable->nSkewBuckets++;
1423  hashtable->spaceUsed += SKEW_BUCKET_OVERHEAD;
1424  hashtable->spaceUsedSkew += SKEW_BUCKET_OVERHEAD;
1425  if (hashtable->spaceUsed > hashtable->spacePeak)
1426  hashtable->spacePeak = hashtable->spaceUsed;
1427  }
1428 
1430  values, nvalues, numbers, nnumbers);
1431  }
1432 
1433  ReleaseSysCache(statsTuple);
1434 }
1435 
1436 /*
1437  * ExecHashGetSkewBucket
1438  *
1439  * Returns the index of the skew bucket for this hashvalue,
1440  * or INVALID_SKEW_BUCKET_NO if the hashvalue is not
1441  * associated with any active skew bucket.
1442  */
1443 int
1445 {
1446  int bucket;
1447 
1448  /*
1449  * Always return INVALID_SKEW_BUCKET_NO if not doing skew optimization (in
1450  * particular, this happens after the initial batch is done).
1451  */
1452  if (!hashtable->skewEnabled)
1453  return INVALID_SKEW_BUCKET_NO;
1454 
1455  /*
1456  * Since skewBucketLen is a power of 2, we can do a modulo by ANDing.
1457  */
1458  bucket = hashvalue & (hashtable->skewBucketLen - 1);
1459 
1460  /*
1461  * While we have not hit a hole in the hashtable and have not hit the
1462  * desired bucket, we have collided with some other hash value, so try the
1463  * next bucket location.
1464  */
1465  while (hashtable->skewBucket[bucket] != NULL &&
1466  hashtable->skewBucket[bucket]->hashvalue != hashvalue)
1467  bucket = (bucket + 1) & (hashtable->skewBucketLen - 1);
1468 
1469  /*
1470  * Found the desired bucket?
1471  */
1472  if (hashtable->skewBucket[bucket] != NULL)
1473  return bucket;
1474 
1475  /*
1476  * There must not be any hashtable entry for this hash value.
1477  */
1478  return INVALID_SKEW_BUCKET_NO;
1479 }
1480 
1481 /*
1482  * ExecHashSkewTableInsert
1483  *
1484  * Insert a tuple into the skew hashtable.
1485  *
1486  * This should generally match up with the current-batch case in
1487  * ExecHashTableInsert.
1488  */
1489 static void
1491  TupleTableSlot *slot,
1492  uint32 hashvalue,
1493  int bucketNumber)
1494 {
1496  HashJoinTuple hashTuple;
1497  int hashTupleSize;
1498 
1499  /* Create the HashJoinTuple */
1500  hashTupleSize = HJTUPLE_OVERHEAD + tuple->t_len;
1501  hashTuple = (HashJoinTuple) MemoryContextAlloc(hashtable->batchCxt,
1502  hashTupleSize);
1503  hashTuple->hashvalue = hashvalue;
1504  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1506 
1507  /* Push it onto the front of the skew bucket's list */
1508  hashTuple->next = hashtable->skewBucket[bucketNumber]->tuples;
1509  hashtable->skewBucket[bucketNumber]->tuples = hashTuple;
1510 
1511  /* Account for space used, and back off if we've used too much */
1512  hashtable->spaceUsed += hashTupleSize;
1513  hashtable->spaceUsedSkew += hashTupleSize;
1514  if (hashtable->spaceUsed > hashtable->spacePeak)
1515  hashtable->spacePeak = hashtable->spaceUsed;
1516  while (hashtable->spaceUsedSkew > hashtable->spaceAllowedSkew)
1517  ExecHashRemoveNextSkewBucket(hashtable);
1518 
1519  /* Check we are not over the total spaceAllowed, either */
1520  if (hashtable->spaceUsed > hashtable->spaceAllowed)
1521  ExecHashIncreaseNumBatches(hashtable);
1522 }
1523 
1524 /*
1525  * ExecHashRemoveNextSkewBucket
1526  *
1527  * Remove the least valuable skew bucket by pushing its tuples into
1528  * the main hash table.
1529  */
1530 static void
1532 {
1533  int bucketToRemove;
1534  HashSkewBucket *bucket;
1535  uint32 hashvalue;
1536  int bucketno;
1537  int batchno;
1538  HashJoinTuple hashTuple;
1539 
1540  /* Locate the bucket to remove */
1541  bucketToRemove = hashtable->skewBucketNums[hashtable->nSkewBuckets - 1];
1542  bucket = hashtable->skewBucket[bucketToRemove];
1543 
1544  /*
1545  * Calculate which bucket and batch the tuples belong to in the main
1546  * hashtable. They all have the same hash value, so it's the same for all
1547  * of them. Also note that it's not possible for nbatch to increase while
1548  * we are processing the tuples.
1549  */
1550  hashvalue = bucket->hashvalue;
1551  ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno, &batchno);
1552 
1553  /* Process all tuples in the bucket */
1554  hashTuple = bucket->tuples;
1555  while (hashTuple != NULL)
1556  {
1557  HashJoinTuple nextHashTuple = hashTuple->next;
1558  MinimalTuple tuple;
1559  Size tupleSize;
1560 
1561  /*
1562  * This code must agree with ExecHashTableInsert. We do not use
1563  * ExecHashTableInsert directly as ExecHashTableInsert expects a
1564  * TupleTableSlot while we already have HashJoinTuples.
1565  */
1566  tuple = HJTUPLE_MINTUPLE(hashTuple);
1567  tupleSize = HJTUPLE_OVERHEAD + tuple->t_len;
1568 
1569  /* Decide whether to put the tuple in the hash table or a temp file */
1570  if (batchno == hashtable->curbatch)
1571  {
1572  /* Move the tuple to the main hash table */
1573  hashTuple->next = hashtable->buckets[bucketno];
1574  hashtable->buckets[bucketno] = hashTuple;
1575  /* We have reduced skew space, but overall space doesn't change */
1576  hashtable->spaceUsedSkew -= tupleSize;
1577  }
1578  else
1579  {
1580  /* Put the tuple into a temp file for later batches */
1581  Assert(batchno > hashtable->curbatch);
1582  ExecHashJoinSaveTuple(tuple, hashvalue,
1583  &hashtable->innerBatchFile[batchno]);
1584  pfree(hashTuple);
1585  hashtable->spaceUsed -= tupleSize;
1586  hashtable->spaceUsedSkew -= tupleSize;
1587  }
1588 
1589  hashTuple = nextHashTuple;
1590  }
1591 
1592  /*
1593  * Free the bucket struct itself and reset the hashtable entry to NULL.
1594  *
1595  * NOTE: this is not nearly as simple as it looks on the surface, because
1596  * of the possibility of collisions in the hashtable. Suppose that hash
1597  * values A and B collide at a particular hashtable entry, and that A was
1598  * entered first so B gets shifted to a different table entry. If we were
1599  * to remove A first then ExecHashGetSkewBucket would mistakenly start
1600  * reporting that B is not in the hashtable, because it would hit the NULL
1601  * before finding B. However, we always remove entries in the reverse
1602  * order of creation, so this failure cannot happen.
1603  */
1604  hashtable->skewBucket[bucketToRemove] = NULL;
1605  hashtable->nSkewBuckets--;
1606  pfree(bucket);
1607  hashtable->spaceUsed -= SKEW_BUCKET_OVERHEAD;
1608  hashtable->spaceUsedSkew -= SKEW_BUCKET_OVERHEAD;
1609 
1610  /*
1611  * If we have removed all skew buckets then give up on skew optimization.
1612  * Release the arrays since they aren't useful any more.
1613  */
1614  if (hashtable->nSkewBuckets == 0)
1615  {
1616  hashtable->skewEnabled = false;
1617  pfree(hashtable->skewBucket);
1618  pfree(hashtable->skewBucketNums);
1619  hashtable->skewBucket = NULL;
1620  hashtable->skewBucketNums = NULL;
1621  hashtable->spaceUsed -= hashtable->spaceUsedSkew;
1622  hashtable->spaceUsedSkew = 0;
1623  }
1624 }
1625 
1626 /*
1627  * Allocate 'size' bytes from the currently active HashMemoryChunk
1628  */
1629 static void *
1631 {
1632  HashMemoryChunk newChunk;
1633  char *ptr;
1634 
1635  /* just in case the size is not already aligned properly */
1636  size = MAXALIGN(size);
1637 
1638  /*
1639  * If tuple size is larger than of 1/4 of chunk size, allocate a separate
1640  * chunk.
1641  */
1642  if (size > HASH_CHUNK_THRESHOLD)
1643  {
1644  /* allocate new chunk and put it at the beginning of the list */
1645  newChunk = (HashMemoryChunk) MemoryContextAlloc(hashtable->batchCxt,
1646  offsetof(HashMemoryChunkData, data) + size);
1647  newChunk->maxlen = size;
1648  newChunk->used = 0;
1649  newChunk->ntuples = 0;
1650 
1651  /*
1652  * Add this chunk to the list after the first existing chunk, so that
1653  * we don't lose the remaining space in the "current" chunk.
1654  */
1655  if (hashtable->chunks != NULL)
1656  {
1657  newChunk->next = hashtable->chunks->next;
1658  hashtable->chunks->next = newChunk;
1659  }
1660  else
1661  {
1662  newChunk->next = hashtable->chunks;
1663  hashtable->chunks = newChunk;
1664  }
1665 
1666  newChunk->used += size;
1667  newChunk->ntuples += 1;
1668 
1669  return newChunk->data;
1670  }
1671 
1672  /*
1673  * See if we have enough space for it in the current chunk (if any). If
1674  * not, allocate a fresh chunk.
1675  */
1676  if ((hashtable->chunks == NULL) ||
1677  (hashtable->chunks->maxlen - hashtable->chunks->used) < size)
1678  {
1679  /* allocate new chunk and put it at the beginning of the list */
1680  newChunk = (HashMemoryChunk) MemoryContextAlloc(hashtable->batchCxt,
1682 
1683  newChunk->maxlen = HASH_CHUNK_SIZE;
1684  newChunk->used = size;
1685  newChunk->ntuples = 1;
1686 
1687  newChunk->next = hashtable->chunks;
1688  hashtable->chunks = newChunk;
1689 
1690  return newChunk->data;
1691  }
1692 
1693  /* There is enough space in the current chunk, let's add the tuple */
1694  ptr = hashtable->chunks->data + hashtable->chunks->used;
1695  hashtable->chunks->used += size;
1696  hashtable->chunks->ntuples += 1;
1697 
1698  /* return pointer to the start of the tuple memory */
1699  return ptr;
1700 }
int log2_nbuckets_optimal
Definition: hashjoin.h:134
Oid skewTable
Definition: plannodes.h:767
#define DatumGetUInt32(X)
Definition: postgres.h:494
double skewTuples
Definition: hashjoin.h:157
#define NIL
Definition: pg_list.h:69
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:69
Definition: fmgr.h:53
List * qual
Definition: plannodes.h:115
#define SKEW_BUCKET_OVERHEAD
Definition: hashjoin.h:100
double plan_rows
Definition: plannodes.h:108
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:101
bool op_strict(Oid opno)
Definition: lsyscache.c:1225
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:367
bool skewInherit
Definition: plannodes.h:769
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:203
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:506
HashJoinTable ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
Definition: nodeHash.c:256
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:388
static void ExecHashRemoveNextSkewBucket(HashJoinTable hashtable)
Definition: nodeHash.c:1531
#define SKEW_MIN_OUTER_FRACTION
Definition: hashjoin.h:103
struct HashJoinTupleData ** buckets
Definition: hashjoin.h:137
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1056
Instrumentation * instrument
Definition: execnodes.h:1031
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:603
bool ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
Definition: nodeHash.c:1141
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Definition: execTuples.c:656
#define HASH_CHUNK_SIZE
Definition: hashjoin.h:123
Definition: plannodes.h:95
void ExecPrepHashTableForUnmatched(HashJoinState *hjstate)
Definition: nodeHash.c:1118
ExprContext * ps_ExprContext
Definition: execnodes.h:1055
HashState * ExecInitHash(Hash *node, EState *estate, int eflags)
Definition: nodeHash.c:172
void ExecHashTableReset(HashJoinTable hashtable)
Definition: nodeHash.c:1209
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:128
HashJoinTable hashtable
Definition: execnodes.h:1960
#define Min(x, y)
Definition: c.h:787
void ExecReScan(PlanState *node)
Definition: execAmi.c:71
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:459
List * qual
Definition: execnodes.h:1039
Definition: nodes.h:464
Oid skewColType
Definition: plannodes.h:770
#define MemSet(start, val, len)
Definition: c.h:838
Node * MultiExecHash(HashState *node)
Definition: nodeHash.c:74
List * targetlist
Definition: execnodes.h:1038
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:138
FmgrInfo * inner_hashfunctions
Definition: hashjoin.h:175
bool get_attstatsslot(HeapTuple statstuple, Oid atttype, int32 atttypmod, int reqkind, Oid reqop, Oid *actualop, Datum **values, int *nvalues, float4 **numbers, int *nnumbers)
Definition: lsyscache.c:2808
static void ExecHashIncreaseNumBatches(HashJoinTable hashtable)
Definition: nodeHash.c:590
EState * state
Definition: execnodes.h:1027
void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, int *numbuckets, int *numbatches, int *num_skew_mcvs)
Definition: nodeHash.c:417
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:519
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:696
void BufFileClose(BufFile *file)
Definition: buffile.c:202
#define ALLOCSET_DEFAULT_MINSIZE
Definition: memutils.h:142
int ExecHashGetSkewBucket(HashJoinTable hashtable, uint32 hashvalue)
Definition: nodeHash.c:1444
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:435
static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
Definition: nodeHash.c:1283
struct PlanState * lefttree
Definition: execnodes.h:1040
int * skewBucketNums
Definition: hashjoin.h:146
void ExecHashTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
Definition: nodeHash.c:834
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1028
uint32 hj_CurHashValue
Definition: execnodes.h:1749
int hj_CurSkewBucketNo
Definition: execnodes.h:1751
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4430
void ExecReScanHash(HashState *node)
Definition: nodeHash.c:1263
void pfree(void *pointer)
Definition: mcxt.c:993
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:41
void PrepareTempTablespaces(void)
Definition: tablespace.c:1277
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:882
static void ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
Definition: nodeHash.c:755
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:52
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:160
#define HASH_CHUNK_THRESHOLD
Definition: hashjoin.h:124
struct HashJoinTupleData * HashJoinTuple
Definition: execnodes.h:1738
#define EXEC_FLAG_BACKWARD
Definition: executor.h:59
BufFile ** outerBatchFile
Definition: hashjoin.h:167
#define outerPlanState(node)
Definition: execnodes.h:1069
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1752
AttrNumber skewColumn
Definition: plannodes.h:768
bool ExecScanHashBucket(HashJoinState *hjstate, ExprContext *econtext)
Definition: nodeHash.c:1060
Size spaceAllowedSkew
Definition: hashjoin.h:182
HashJoinTuple tuples
Definition: hashjoin.h:97
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:123
bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
Definition: execQual.c:5209
List * hashkeys
Definition: execnodes.h:1961
#define TupIsNull(slot)
Definition: tuptable.h:138
unsigned int uint32
Definition: c.h:254
PlanState ps
Definition: execnodes.h:1959
struct HashMemoryChunkData * next
Definition: hashjoin.h:115
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define STATISTIC_KIND_MCV
Definition: pg_statistic.h:203
MemoryContext batchCxt
Definition: hashjoin.h:185
struct HashJoinTableData * HashJoinTable
Definition: execnodes.h:1739
Bitmapset * chgParam
Definition: execnodes.h:1049
int my_log2(long num)
Definition: dynahash.c:1599
#define outerPlan(node)
Definition: plannodes.h:144
FmgrInfo * outer_hashfunctions
Definition: hashjoin.h:174
#define MaxAllocSize
Definition: memutils.h:40
int hj_CurBucketNo
Definition: execnodes.h:1750
float float4
Definition: c.h:365
#define SizeofMinimalTupleHeader
Definition: htup_details.h:625
HashSkewBucket ** skewBucket
Definition: hashjoin.h:143
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:436
void * palloc0(Size size)
Definition: mcxt.c:921
uintptr_t Datum
Definition: postgres.h:374
static void * dense_alloc(HashJoinTable hashtable, Size size)
Definition: nodeHash.c:1630
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:989
struct HashMemoryChunkData * HashMemoryChunk
Definition: hashjoin.h:121
#define NTUP_PER_BUCKET
Definition: nodeHash.c:414
int work_mem
Definition: globals.c:109
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:785
#define HJTUPLE_OVERHEAD
Definition: hashjoin.h:71
#define BoolGetDatum(X)
Definition: postgres.h:410
Plan * plan
Definition: execnodes.h:1025
int32 skewColTypmod
Definition: plannodes.h:771
#define InvalidOid
Definition: postgres_ext.h:36
double totalTuples
Definition: hashjoin.h:156
uint32 hashvalue
Definition: hashjoin.h:96
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:72
#define HeapTupleHeaderHasMatch(tup)
Definition: htup_details.h:492
#define Max(x, y)
Definition: c.h:781
#define makeNode(_type_)
Definition: nodes.h:512
int plan_width
Definition: plannodes.h:109
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:215
#define Assert(condition)
Definition: c.h:656
static void ExecHashSkewTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue, int bucketNumber)
Definition: nodeHash.c:1490
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:60
char data[FLEXIBLE_ARRAY_MEMBER]
Definition: hashjoin.h:118
size_t Size
Definition: c.h:341
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:413
BufFile ** innerBatchFile
Definition: hashjoin.h:166
struct HashJoinTupleData * next
Definition: hashjoin.h:66
static int list_length(const List *l)
Definition: pg_list.h:89
#define HeapTupleHeaderClearMatch(tup)
Definition: htup_details.h:502
#define MAXALIGN(LEN)
Definition: c.h:569
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1022
List * targetlist
Definition: plannodes.h:114
HashMemoryChunk chunks
Definition: hashjoin.h:188
List * hashclauses
Definition: execnodes.h:1744
static Datum values[MAXATTR]
Definition: bootstrap.c:159
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1754
Plan plan
Definition: plannodes.h:766
void * palloc(Size size)
Definition: mcxt.c:892
HashJoinTable hj_HashTable
Definition: execnodes.h:1748
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:750
#define SearchSysCache3(cacheId, key1, key2, key3)
Definition: syscache.h:145
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:143
int i
void ExecEndHash(HashState *node)
Definition: nodeHash.c:232
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:566
void ExecHashTableResetMatchFlags(HashJoinTable hashtable)
Definition: nodeHash.c:1238
bool ExecHashGetHashValue(HashJoinTable hashtable, ExprContext *econtext, List *hashkeys, bool outer_tuple, bool keep_nulls, uint32 *hashvalue)
Definition: nodeHash.c:924
bool * hashStrict
Definition: hashjoin.h:176
#define ALLOCSET_DEFAULT_MAXSIZE
Definition: memutils.h:144
MemoryContext hashCxt
Definition: hashjoin.h:184
#define elog
Definition: elog.h:228
#define SKEW_WORK_MEM_PERCENT
Definition: hashjoin.h:102
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:134
Definition: pg_list.h:45
void free_attstatsslot(Oid atttype, Datum *values, int nvalues, float4 *numbers, int nnumbers)
Definition: lsyscache.c:2932
TupleTableSlot * ExecHash(HashState *node)
Definition: nodeHash.c:60
void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
Definition: nodeHashjoin.c:871
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition: nodeHash.c:560
uint32 hashvalue
Definition: hashjoin.h:67
#define offsetof(type, field)
Definition: c.h:536
#define ResetExprContext(econtext)
Definition: executor.h:315
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define ExecEvalExpr(expr, econtext, isNull, isDone)
Definition: executor.h:72