PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeHashjoin.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "executor/executor.h"
#include "executor/hashjoin.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Include dependency graph for nodeHashjoin.c:

Go to the source code of this file.

Macros

#define HJ_BUILD_HASHTABLE   1
 
#define HJ_NEED_NEW_OUTER   2
 
#define HJ_SCAN_BUCKET   3
 
#define HJ_FILL_OUTER_TUPLE   4
 
#define HJ_FILL_INNER_TUPLES   5
 
#define HJ_NEED_NEW_BATCH   6
 
#define HJ_FILL_OUTER(hjstate)   ((hjstate)->hj_NullInnerTupleSlot != NULL)
 
#define HJ_FILL_INNER(hjstate)   ((hjstate)->hj_NullOuterTupleSlot != NULL)
 

Functions

static TupleTableSlotExecHashJoinOuterGetTuple (PlanState *outerNode, HashJoinState *hjstate, uint32 *hashvalue)
 
static TupleTableSlotExecHashJoinGetSavedTuple (HashJoinState *hjstate, BufFile *file, uint32 *hashvalue, TupleTableSlot *tupleSlot)
 
static bool ExecHashJoinNewBatch (HashJoinState *hjstate)
 
static TupleTableSlotExecHashJoin (PlanState *pstate)
 
HashJoinStateExecInitHashJoin (HashJoin *node, EState *estate, int eflags)
 
void ExecEndHashJoin (HashJoinState *node)
 
void ExecHashJoinSaveTuple (MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
 
void ExecReScanHashJoin (HashJoinState *node)
 

Macro Definition Documentation

#define HJ_BUILD_HASHTABLE   1

Definition at line 30 of file nodeHashjoin.c.

Referenced by ExecHashJoin(), ExecInitHashJoin(), and ExecReScanHashJoin().

#define HJ_FILL_INNER (   hjstate)    ((hjstate)->hj_NullOuterTupleSlot != NULL)

Definition at line 40 of file nodeHashjoin.c.

Referenced by ExecHashJoin(), ExecHashJoinNewBatch(), and ExecReScanHashJoin().

#define HJ_FILL_INNER_TUPLES   5

Definition at line 34 of file nodeHashjoin.c.

Referenced by ExecHashJoin().

#define HJ_FILL_OUTER (   hjstate)    ((hjstate)->hj_NullInnerTupleSlot != NULL)

Definition at line 38 of file nodeHashjoin.c.

Referenced by ExecHashJoin(), ExecHashJoinNewBatch(), and ExecHashJoinOuterGetTuple().

#define HJ_FILL_OUTER_TUPLE   4

Definition at line 33 of file nodeHashjoin.c.

Referenced by ExecHashJoin().

#define HJ_NEED_NEW_BATCH   6

Definition at line 35 of file nodeHashjoin.c.

Referenced by ExecHashJoin().

#define HJ_NEED_NEW_OUTER   2

Definition at line 31 of file nodeHashjoin.c.

Referenced by ExecHashJoin(), and ExecReScanHashJoin().

#define HJ_SCAN_BUCKET   3

Definition at line 32 of file nodeHashjoin.c.

Referenced by ExecHashJoin().

Function Documentation

void ExecEndHashJoin ( HashJoinState node)

Definition at line 551 of file nodeHashjoin.c.

References ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), ExecHashTableDestroy(), HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, HashJoinState::hj_OuterTupleSlot, innerPlanState, HashJoinState::js, NULL, outerPlanState, JoinState::ps, and PlanState::ps_ResultTupleSlot.

Referenced by ExecEndNode().

552 {
553  /*
554  * Free hash table
555  */
556  if (node->hj_HashTable)
557  {
559  node->hj_HashTable = NULL;
560  }
561 
562  /*
563  * Free the exprcontext
564  */
565  ExecFreeExprContext(&node->js.ps);
566 
567  /*
568  * clean out the tuple table
569  */
573 
574  /*
575  * clean up subtrees
576  */
579 }
PlanState ps
Definition: execnodes.h:1587
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * hj_OuterTupleSlot
Definition: execnodes.h:1700
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:521
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:880
#define outerPlanState(node)
Definition: execnodes.h:893
#define NULL
Definition: c.h:229
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1701
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
#define innerPlanState(node)
Definition: execnodes.h:892
JoinState js
Definition: execnodes.h:1690
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition: nodeHash.c:560
static TupleTableSlot* ExecHashJoin ( PlanState pstate)
static

Definition at line 62 of file nodeHashjoin.c.

References Assert, castNode, CHECK_FOR_INTERRUPTS, HashJoinTableData::curbatch, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, elog, ERROR, ExecFetchSlotMinimalTuple(), ExecHashGetBucketAndBatch(), ExecHashGetSkewBucket(), ExecHashJoinNewBatch(), ExecHashJoinOuterGetTuple(), ExecHashJoinSaveTuple(), ExecHashTableCreate(), ExecPrepHashTableForUnmatched(), ExecProcNode(), ExecProject(), ExecQual(), ExecScanHashBucket(), ExecScanHashTableForUnmatched(), HashState::hashtable, HeapTupleHeaderSetMatch, HJ_BUILD_HASHTABLE, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurHashValue, HashJoinState::hj_CurSkewBucketNo, HashJoinState::hj_CurTuple, HJ_FILL_INNER, HJ_FILL_INNER_TUPLES, HJ_FILL_OUTER, HJ_FILL_OUTER_TUPLE, HashJoinState::hj_FirstOuterTupleSlot, HashJoinState::hj_HashOperators, HashJoinState::hj_HashTable, HashJoinState::hj_JoinState, HashJoinState::hj_MatchedOuter, HJ_NEED_NEW_BATCH, HJ_NEED_NEW_OUTER, HashJoinState::hj_NullInnerTupleSlot, HashJoinState::hj_NullOuterTupleSlot, HashJoinState::hj_OuterNotEmpty, HJ_SCAN_BUCKET, HJTUPLE_MINTUPLE, innerPlanState, InstrCountFiltered1, InstrCountFiltered2, INVALID_SKEW_BUCKET_NO, JOIN_ANTI, JoinState::joinqual, JoinState::jointype, HashJoinState::js, MultiExecProcNode(), HashJoinTableData::nbatch, HashJoinTableData::nbatch_outstart, NULL, HashJoinTableData::outerBatchFile, outerPlanState, PlanState::plan, JoinState::ps, HashState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::qual, ResetExprContext, JoinState::single_match, Plan::startup_cost, Plan::total_cost, HashJoinTableData::totalTuples, and TupIsNull.

Referenced by ExecInitHashJoin().

63 {
64  HashJoinState *node = castNode(HashJoinState, pstate);
65  PlanState *outerNode;
66  HashState *hashNode;
67  ExprState *joinqual;
68  ExprState *otherqual;
69  ExprContext *econtext;
70  HashJoinTable hashtable;
71  TupleTableSlot *outerTupleSlot;
72  uint32 hashvalue;
73  int batchno;
74 
75  /*
76  * get information from HashJoin node
77  */
78  joinqual = node->js.joinqual;
79  otherqual = node->js.ps.qual;
80  hashNode = (HashState *) innerPlanState(node);
81  outerNode = outerPlanState(node);
82  hashtable = node->hj_HashTable;
83  econtext = node->js.ps.ps_ExprContext;
84 
85  /*
86  * Reset per-tuple memory context to free any expression evaluation
87  * storage allocated in the previous tuple cycle.
88  */
89  ResetExprContext(econtext);
90 
91  /*
92  * run the hash join state machine
93  */
94  for (;;)
95  {
96  /*
97  * It's possible to iterate this loop many times before returning a
98  * tuple, in some pathological cases such as needing to move much of
99  * the current batch to a later batch. So let's check for interrupts
100  * each time through.
101  */
103 
104  switch (node->hj_JoinState)
105  {
106  case HJ_BUILD_HASHTABLE:
107 
108  /*
109  * First time through: build hash table for inner relation.
110  */
111  Assert(hashtable == NULL);
112 
113  /*
114  * If the outer relation is completely empty, and it's not
115  * right/full join, we can quit without building the hash
116  * table. However, for an inner join it is only a win to
117  * check this when the outer relation's startup cost is less
118  * than the projected cost of building the hash table.
119  * Otherwise it's best to build the hash table first and see
120  * if the inner relation is empty. (When it's a left join, we
121  * should always make this check, since we aren't going to be
122  * able to skip the join on the strength of an empty inner
123  * relation anyway.)
124  *
125  * If we are rescanning the join, we make use of information
126  * gained on the previous scan: don't bother to try the
127  * prefetch if the previous scan found the outer relation
128  * nonempty. This is not 100% reliable since with new
129  * parameters the outer relation might yield different
130  * results, but it's a good heuristic.
131  *
132  * The only way to make the check is to try to fetch a tuple
133  * from the outer plan node. If we succeed, we have to stash
134  * it away for later consumption by ExecHashJoinOuterGetTuple.
135  */
136  if (HJ_FILL_INNER(node))
137  {
138  /* no chance to not build the hash table */
140  }
141  else if (HJ_FILL_OUTER(node) ||
142  (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost &&
143  !node->hj_OuterNotEmpty))
144  {
145  node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode);
147  {
148  node->hj_OuterNotEmpty = false;
149  return NULL;
150  }
151  else
152  node->hj_OuterNotEmpty = true;
153  }
154  else
156 
157  /*
158  * create the hash table
159  */
160  hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan,
161  node->hj_HashOperators,
162  HJ_FILL_INNER(node));
163  node->hj_HashTable = hashtable;
164 
165  /*
166  * execute the Hash node, to build the hash table
167  */
168  hashNode->hashtable = hashtable;
169  (void) MultiExecProcNode((PlanState *) hashNode);
170 
171  /*
172  * If the inner relation is completely empty, and we're not
173  * doing a left outer join, we can quit without scanning the
174  * outer relation.
175  */
176  if (hashtable->totalTuples == 0 && !HJ_FILL_OUTER(node))
177  return NULL;
178 
179  /*
180  * need to remember whether nbatch has increased since we
181  * began scanning the outer relation
182  */
183  hashtable->nbatch_outstart = hashtable->nbatch;
184 
185  /*
186  * Reset OuterNotEmpty for scan. (It's OK if we fetched a
187  * tuple above, because ExecHashJoinOuterGetTuple will
188  * immediately set it again.)
189  */
190  node->hj_OuterNotEmpty = false;
191 
193 
194  /* FALL THRU */
195 
196  case HJ_NEED_NEW_OUTER:
197 
198  /*
199  * We don't have an outer tuple, try to get the next one
200  */
201  outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
202  node,
203  &hashvalue);
204  if (TupIsNull(outerTupleSlot))
205  {
206  /* end of batch, or maybe whole join */
207  if (HJ_FILL_INNER(node))
208  {
209  /* set up to scan for unmatched inner tuples */
212  }
213  else
215  continue;
216  }
217 
218  econtext->ecxt_outertuple = outerTupleSlot;
219  node->hj_MatchedOuter = false;
220 
221  /*
222  * Find the corresponding bucket for this tuple in the main
223  * hash table or skew hash table.
224  */
225  node->hj_CurHashValue = hashvalue;
226  ExecHashGetBucketAndBatch(hashtable, hashvalue,
227  &node->hj_CurBucketNo, &batchno);
228  node->hj_CurSkewBucketNo = ExecHashGetSkewBucket(hashtable,
229  hashvalue);
230  node->hj_CurTuple = NULL;
231 
232  /*
233  * The tuple might not belong to the current batch (where
234  * "current batch" includes the skew buckets if any).
235  */
236  if (batchno != hashtable->curbatch &&
238  {
239  /*
240  * Need to postpone this outer tuple to a later batch.
241  * Save it in the corresponding outer-batch file.
242  */
243  Assert(batchno > hashtable->curbatch);
245  hashvalue,
246  &hashtable->outerBatchFile[batchno]);
247  /* Loop around, staying in HJ_NEED_NEW_OUTER state */
248  continue;
249  }
250 
251  /* OK, let's scan the bucket for matches */
253 
254  /* FALL THRU */
255 
256  case HJ_SCAN_BUCKET:
257 
258  /*
259  * Scan the selected hash bucket for matches to current outer
260  */
261  if (!ExecScanHashBucket(node, econtext))
262  {
263  /* out of matches; check for possible outer-join fill */
265  continue;
266  }
267 
268  /*
269  * We've got a match, but still need to test non-hashed quals.
270  * ExecScanHashBucket already set up all the state needed to
271  * call ExecQual.
272  *
273  * If we pass the qual, then save state for next call and have
274  * ExecProject form the projection, store it in the tuple
275  * table, and return the slot.
276  *
277  * Only the joinquals determine tuple match status, but all
278  * quals must pass to actually return the tuple.
279  */
280  if (joinqual == NULL || ExecQual(joinqual, econtext))
281  {
282  node->hj_MatchedOuter = true;
284 
285  /* In an antijoin, we never return a matched tuple */
286  if (node->js.jointype == JOIN_ANTI)
287  {
289  continue;
290  }
291 
292  /*
293  * If we only need to join to the first matching inner
294  * tuple, then consider returning this one, but after that
295  * continue with next outer tuple.
296  */
297  if (node->js.single_match)
299 
300  if (otherqual == NULL || ExecQual(otherqual, econtext))
301  return ExecProject(node->js.ps.ps_ProjInfo);
302  else
303  InstrCountFiltered2(node, 1);
304  }
305  else
306  InstrCountFiltered1(node, 1);
307  break;
308 
309  case HJ_FILL_OUTER_TUPLE:
310 
311  /*
312  * The current outer tuple has run out of matches, so check
313  * whether to emit a dummy outer-join tuple. Whether we emit
314  * one or not, the next state is NEED_NEW_OUTER.
315  */
317 
318  if (!node->hj_MatchedOuter &&
319  HJ_FILL_OUTER(node))
320  {
321  /*
322  * Generate a fake join tuple with nulls for the inner
323  * tuple, and return it if it passes the non-join quals.
324  */
325  econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
326 
327  if (otherqual == NULL || ExecQual(otherqual, econtext))
328  return ExecProject(node->js.ps.ps_ProjInfo);
329  else
330  InstrCountFiltered2(node, 1);
331  }
332  break;
333 
335 
336  /*
337  * We have finished a batch, but we are doing right/full join,
338  * so any unmatched inner tuples in the hashtable have to be
339  * emitted before we continue to the next batch.
340  */
341  if (!ExecScanHashTableForUnmatched(node, econtext))
342  {
343  /* no more unmatched tuples */
345  continue;
346  }
347 
348  /*
349  * Generate a fake join tuple with nulls for the outer tuple,
350  * and return it if it passes the non-join quals.
351  */
352  econtext->ecxt_outertuple = node->hj_NullOuterTupleSlot;
353 
354  if (otherqual == NULL || ExecQual(otherqual, econtext))
355  return ExecProject(node->js.ps.ps_ProjInfo);
356  else
357  InstrCountFiltered2(node, 1);
358  break;
359 
360  case HJ_NEED_NEW_BATCH:
361 
362  /*
363  * Try to advance to next batch. Done if there are no more.
364  */
365  if (!ExecHashJoinNewBatch(node))
366  return NULL; /* end of join */
368  break;
369 
370  default:
371  elog(ERROR, "unrecognized hashjoin state: %d",
372  (int) node->hj_JoinState);
373  }
374  }
375 }
JoinType jointype
Definition: execnodes.h:1588
#define HJ_NEED_NEW_BATCH
Definition: nodeHashjoin.c:35
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:101
#define HJ_SCAN_BUCKET
Definition: nodeHashjoin.c:32
HashJoinTable ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
Definition: nodeHash.c:243
TupleTableSlot * hj_NullInnerTupleSlot
Definition: execnodes.h:1703
ExprState * joinqual
Definition: execnodes.h:1591
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:882
PlanState ps
Definition: execnodes.h:1587
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
bool ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
Definition: nodeHash.c:1145
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Definition: execTuples.c:652
void ExecPrepHashTableForUnmatched(HashJoinState *hjstate)
Definition: nodeHash.c:1121
ExprContext * ps_ExprContext
Definition: execnodes.h:881
bool single_match
Definition: execnodes.h:1589
HashJoinTable hashtable
Definition: execnodes.h:1959
bool hj_MatchedOuter
Definition: execnodes.h:1706
static TupleTableSlot * ExecHashJoinOuterGetTuple(PlanState *outerNode, HashJoinState *hjstate, uint32 *hashvalue)
Definition: nodeHashjoin.c:594
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1704
int ExecHashGetSkewBucket(HashJoinTable hashtable, uint32 hashvalue)
Definition: nodeHash.c:1444
#define HJ_FILL_INNER(hjstate)
Definition: nodeHashjoin.c:40
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1031
uint32 hj_CurHashValue
Definition: execnodes.h:1696
int hj_CurSkewBucketNo
Definition: execnodes.h:1698
#define ERROR
Definition: elog.h:43
TupleTableSlot * hj_NullOuterTupleSlot
Definition: execnodes.h:1702
BufFile ** outerBatchFile
Definition: hashjoin.h:166
#define outerPlanState(node)
Definition: execnodes.h:893
Cost startup_cost
Definition: plannodes.h:125
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1699
bool ExecScanHashBucket(HashJoinState *hjstate, ExprContext *econtext)
Definition: nodeHash.c:1063
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:198
#define TupIsNull(slot)
Definition: tuptable.h:138
unsigned int uint32
Definition: c.h:268
PlanState ps
Definition: execnodes.h:1958
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:896
List * hj_HashOperators
Definition: execnodes.h:1694
int hj_CurBucketNo
Definition: execnodes.h:1697
#define HJ_FILL_INNER_TUPLES
Definition: nodeHashjoin.c:34
#define HJ_FILL_OUTER(hjstate)
Definition: nodeHashjoin.c:38
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:245
Plan * plan
Definition: execnodes.h:847
double totalTuples
Definition: hashjoin.h:155
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:72
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
bool hj_OuterNotEmpty
Definition: execnodes.h:1707
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:901
#define HJ_NEED_NEW_OUTER
Definition: nodeHashjoin.c:31
ExprState * qual
Definition: execnodes.h:865
#define HJ_BUILD_HASHTABLE
Definition: nodeHashjoin.c:30
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
Node * MultiExecProcNode(PlanState *node)
Definition: execProcnode.c:468
Cost total_cost
Definition: plannodes.h:126
#define HeapTupleHeaderSetMatch(tup)
Definition: htup_details.h:522
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define HJ_FILL_OUTER_TUPLE
Definition: nodeHashjoin.c:33
#define elog
Definition: elog.h:219
#define innerPlanState(node)
Definition: execnodes.h:892
JoinState js
Definition: execnodes.h:1690
static bool ExecHashJoinNewBatch(HashJoinState *hjstate)
Definition: nodeHashjoin.c:671
void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
Definition: nodeHashjoin.c:818
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:328
#define ResetExprContext(econtext)
Definition: executor.h:469
static TupleTableSlot * ExecHashJoinGetSavedTuple ( HashJoinState hjstate,
BufFile file,
uint32 hashvalue,
TupleTableSlot tupleSlot 
)
static

Definition at line 852 of file nodeHashjoin.c.

References BufFileRead(), CHECK_FOR_INTERRUPTS, ereport, errcode_for_file_access(), errmsg(), ERROR, ExecClearTuple(), ExecStoreMinimalTuple(), header(), NULL, palloc(), and MinimalTupleData::t_len.

Referenced by ExecHashJoinNewBatch(), and ExecHashJoinOuterGetTuple().

856 {
857  uint32 header[2];
858  size_t nread;
859  MinimalTuple tuple;
860 
861  /*
862  * We check for interrupts here because this is typically taken as an
863  * alternative code path to an ExecProcNode() call, which would include
864  * such a check.
865  */
867 
868  /*
869  * Since both the hash value and the MinimalTuple length word are uint32,
870  * we can read them both in one BufFileRead() call without any type
871  * cheating.
872  */
873  nread = BufFileRead(file, (void *) header, sizeof(header));
874  if (nread == 0) /* end of file */
875  {
876  ExecClearTuple(tupleSlot);
877  return NULL;
878  }
879  if (nread != sizeof(header))
880  ereport(ERROR,
882  errmsg("could not read from hash-join temporary file: %m")));
883  *hashvalue = header[0];
884  tuple = (MinimalTuple) palloc(header[1]);
885  tuple->t_len = header[1];
886  nread = BufFileRead(file,
887  (void *) ((char *) tuple + sizeof(uint32)),
888  header[1] - sizeof(uint32));
889  if (nread != header[1] - sizeof(uint32))
890  ereport(ERROR,
892  errmsg("could not read from hash-join temporary file: %m")));
893  return ExecStoreMinimalTuple(tuple, tupleSlot, true);
894 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:384
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define ERROR
Definition: elog.h:43
MinimalTupleData * MinimalTuple
Definition: htup.h:27
int errcode_for_file_access(void)
Definition: elog.c:598
unsigned int uint32
Definition: c.h:268
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:207
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
size_t BufFileRead(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:365
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
static bool ExecHashJoinNewBatch ( HashJoinState hjstate)
static

Definition at line 671 of file nodeHashjoin.c.

References BufFileClose(), BufFileSeek(), HashJoinTableData::curbatch, ereport, errcode_for_file_access(), errmsg(), ERROR, ExecHashJoinGetSavedTuple(), ExecHashTableInsert(), ExecHashTableReset(), HJ_FILL_INNER, HJ_FILL_OUTER, HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, HashJoinTableData::innerBatchFile, HashJoinTableData::nbatch, HashJoinTableData::nbatch_original, HashJoinTableData::nbatch_outstart, HashJoinTableData::nSkewBuckets, NULL, HashJoinTableData::outerBatchFile, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketNums, HashJoinTableData::skewEnabled, and HashJoinTableData::spaceUsedSkew.

Referenced by ExecHashJoin().

672 {
673  HashJoinTable hashtable = hjstate->hj_HashTable;
674  int nbatch;
675  int curbatch;
676  BufFile *innerFile;
677  TupleTableSlot *slot;
678  uint32 hashvalue;
679 
680  nbatch = hashtable->nbatch;
681  curbatch = hashtable->curbatch;
682 
683  if (curbatch > 0)
684  {
685  /*
686  * We no longer need the previous outer batch file; close it right
687  * away to free disk space.
688  */
689  if (hashtable->outerBatchFile[curbatch])
690  BufFileClose(hashtable->outerBatchFile[curbatch]);
691  hashtable->outerBatchFile[curbatch] = NULL;
692  }
693  else /* we just finished the first batch */
694  {
695  /*
696  * Reset some of the skew optimization state variables, since we no
697  * longer need to consider skew tuples after the first batch. The
698  * memory context reset we are about to do will release the skew
699  * hashtable itself.
700  */
701  hashtable->skewEnabled = false;
702  hashtable->skewBucket = NULL;
703  hashtable->skewBucketNums = NULL;
704  hashtable->nSkewBuckets = 0;
705  hashtable->spaceUsedSkew = 0;
706  }
707 
708  /*
709  * We can always skip over any batches that are completely empty on both
710  * sides. We can sometimes skip over batches that are empty on only one
711  * side, but there are exceptions:
712  *
713  * 1. In a left/full outer join, we have to process outer batches even if
714  * the inner batch is empty. Similarly, in a right/full outer join, we
715  * have to process inner batches even if the outer batch is empty.
716  *
717  * 2. If we have increased nbatch since the initial estimate, we have to
718  * scan inner batches since they might contain tuples that need to be
719  * reassigned to later inner batches.
720  *
721  * 3. Similarly, if we have increased nbatch since starting the outer
722  * scan, we have to rescan outer batches in case they contain tuples that
723  * need to be reassigned.
724  */
725  curbatch++;
726  while (curbatch < nbatch &&
727  (hashtable->outerBatchFile[curbatch] == NULL ||
728  hashtable->innerBatchFile[curbatch] == NULL))
729  {
730  if (hashtable->outerBatchFile[curbatch] &&
731  HJ_FILL_OUTER(hjstate))
732  break; /* must process due to rule 1 */
733  if (hashtable->innerBatchFile[curbatch] &&
734  HJ_FILL_INNER(hjstate))
735  break; /* must process due to rule 1 */
736  if (hashtable->innerBatchFile[curbatch] &&
737  nbatch != hashtable->nbatch_original)
738  break; /* must process due to rule 2 */
739  if (hashtable->outerBatchFile[curbatch] &&
740  nbatch != hashtable->nbatch_outstart)
741  break; /* must process due to rule 3 */
742  /* We can ignore this batch. */
743  /* Release associated temp files right away. */
744  if (hashtable->innerBatchFile[curbatch])
745  BufFileClose(hashtable->innerBatchFile[curbatch]);
746  hashtable->innerBatchFile[curbatch] = NULL;
747  if (hashtable->outerBatchFile[curbatch])
748  BufFileClose(hashtable->outerBatchFile[curbatch]);
749  hashtable->outerBatchFile[curbatch] = NULL;
750  curbatch++;
751  }
752 
753  if (curbatch >= nbatch)
754  return false; /* no more batches */
755 
756  hashtable->curbatch = curbatch;
757 
758  /*
759  * Reload the hash table with the new inner batch (which could be empty)
760  */
761  ExecHashTableReset(hashtable);
762 
763  innerFile = hashtable->innerBatchFile[curbatch];
764 
765  if (innerFile != NULL)
766  {
767  if (BufFileSeek(innerFile, 0, 0L, SEEK_SET))
768  ereport(ERROR,
770  errmsg("could not rewind hash-join temporary file: %m")));
771 
772  while ((slot = ExecHashJoinGetSavedTuple(hjstate,
773  innerFile,
774  &hashvalue,
775  hjstate->hj_HashTupleSlot)))
776  {
777  /*
778  * NOTE: some tuples may be sent to future batches. Also, it is
779  * possible for hashtable->nbatch to be increased here!
780  */
781  ExecHashTableInsert(hashtable, slot, hashvalue);
782  }
783 
784  /*
785  * after we build the hash table, the inner batch file is no longer
786  * needed
787  */
788  BufFileClose(innerFile);
789  hashtable->innerBatchFile[curbatch] = NULL;
790  }
791 
792  /*
793  * Rewind outer batch file (if present), so that we can start reading it.
794  */
795  if (hashtable->outerBatchFile[curbatch] != NULL)
796  {
797  if (BufFileSeek(hashtable->outerBatchFile[curbatch], 0, 0L, SEEK_SET))
798  ereport(ERROR,
800  errmsg("could not rewind hash-join temporary file: %m")));
801  }
802 
803  return true;
804 }
int BufFileSeek(BufFile *file, int fileno, off_t offset, int whence)
Definition: buffile.c:485
void ExecHashTableReset(HashJoinTable hashtable)
Definition: nodeHash.c:1216
void BufFileClose(BufFile *file)
Definition: buffile.c:203
#define HJ_FILL_INNER(hjstate)
Definition: nodeHashjoin.c:40
int * skewBucketNums
Definition: hashjoin.h:145
void ExecHashTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
Definition: nodeHash.c:833
#define ERROR
Definition: elog.h:43
BufFile ** outerBatchFile
Definition: hashjoin.h:166
int errcode_for_file_access(void)
Definition: elog.c:598
unsigned int uint32
Definition: c.h:268
#define ereport(elevel, rest)
Definition: elog.h:122
#define HJ_FILL_OUTER(hjstate)
Definition: nodeHashjoin.c:38
HashSkewBucket ** skewBucket
Definition: hashjoin.h:142
#define NULL
Definition: c.h:229
BufFile ** innerBatchFile
Definition: hashjoin.h:165
static TupleTableSlot * ExecHashJoinGetSavedTuple(HashJoinState *hjstate, BufFile *file, uint32 *hashvalue, TupleTableSlot *tupleSlot)
Definition: nodeHashjoin.c:852
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1701
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
int errmsg(const char *fmt,...)
Definition: elog.c:797
static TupleTableSlot * ExecHashJoinOuterGetTuple ( PlanState outerNode,
HashJoinState hjstate,
uint32 hashvalue 
)
static

Definition at line 594 of file nodeHashjoin.c.

References HashJoinTableData::curbatch, ExprContext::ecxt_outertuple, ExecHashGetHashValue(), ExecHashJoinGetSavedTuple(), ExecProcNode(), HJ_FILL_OUTER, HashJoinState::hj_FirstOuterTupleSlot, HashJoinState::hj_HashTable, HashJoinState::hj_OuterHashKeys, HashJoinState::hj_OuterNotEmpty, HashJoinState::hj_OuterTupleSlot, HashJoinState::js, NULL, HashJoinTableData::outerBatchFile, JoinState::ps, PlanState::ps_ExprContext, and TupIsNull.

Referenced by ExecHashJoin().

597 {
598  HashJoinTable hashtable = hjstate->hj_HashTable;
599  int curbatch = hashtable->curbatch;
600  TupleTableSlot *slot;
601 
602  if (curbatch == 0) /* if it is the first pass */
603  {
604  /*
605  * Check to see if first outer tuple was already fetched by
606  * ExecHashJoin() and not used yet.
607  */
608  slot = hjstate->hj_FirstOuterTupleSlot;
609  if (!TupIsNull(slot))
610  hjstate->hj_FirstOuterTupleSlot = NULL;
611  else
612  slot = ExecProcNode(outerNode);
613 
614  while (!TupIsNull(slot))
615  {
616  /*
617  * We have to compute the tuple's hash value.
618  */
619  ExprContext *econtext = hjstate->js.ps.ps_ExprContext;
620 
621  econtext->ecxt_outertuple = slot;
622  if (ExecHashGetHashValue(hashtable, econtext,
623  hjstate->hj_OuterHashKeys,
624  true, /* outer tuple */
625  HJ_FILL_OUTER(hjstate),
626  hashvalue))
627  {
628  /* remember outer relation is not empty for possible rescan */
629  hjstate->hj_OuterNotEmpty = true;
630 
631  return slot;
632  }
633 
634  /*
635  * That tuple couldn't match because of a NULL, so discard it and
636  * continue with the next one.
637  */
638  slot = ExecProcNode(outerNode);
639  }
640  }
641  else if (curbatch < hashtable->nbatch)
642  {
643  BufFile *file = hashtable->outerBatchFile[curbatch];
644 
645  /*
646  * In outer-join cases, we could get here even though the batch file
647  * is empty.
648  */
649  if (file == NULL)
650  return NULL;
651 
652  slot = ExecHashJoinGetSavedTuple(hjstate,
653  file,
654  hashvalue,
655  hjstate->hj_OuterTupleSlot);
656  if (!TupIsNull(slot))
657  return slot;
658  }
659 
660  /* End of this batch */
661  return NULL;
662 }
PlanState ps
Definition: execnodes.h:1587
ExprContext * ps_ExprContext
Definition: execnodes.h:881
TupleTableSlot * hj_OuterTupleSlot
Definition: execnodes.h:1700
List * hj_OuterHashKeys
Definition: execnodes.h:1692
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1704
BufFile ** outerBatchFile
Definition: hashjoin.h:166
#define TupIsNull(slot)
Definition: tuptable.h:138
#define HJ_FILL_OUTER(hjstate)
Definition: nodeHashjoin.c:38
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:245
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
bool hj_OuterNotEmpty
Definition: execnodes.h:1707
#define NULL
Definition: c.h:229
static TupleTableSlot * ExecHashJoinGetSavedTuple(HashJoinState *hjstate, BufFile *file, uint32 *hashvalue, TupleTableSlot *tupleSlot)
Definition: nodeHashjoin.c:852
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
bool ExecHashGetHashValue(HashJoinTable hashtable, ExprContext *econtext, List *hashkeys, bool outer_tuple, bool keep_nulls, uint32 *hashvalue)
Definition: nodeHash.c:927
JoinState js
Definition: execnodes.h:1690
void ExecHashJoinSaveTuple ( MinimalTuple  tuple,
uint32  hashvalue,
BufFile **  fileptr 
)

Definition at line 818 of file nodeHashjoin.c.

References BufFileCreateTemp(), BufFileWrite(), ereport, errcode_for_file_access(), errmsg(), ERROR, NULL, and MinimalTupleData::t_len.

Referenced by ExecHashIncreaseNumBatches(), ExecHashJoin(), ExecHashRemoveNextSkewBucket(), and ExecHashTableInsert().

820 {
821  BufFile *file = *fileptr;
822  size_t written;
823 
824  if (file == NULL)
825  {
826  /* First write to this batch file, so open it. */
827  file = BufFileCreateTemp(false);
828  *fileptr = file;
829  }
830 
831  written = BufFileWrite(file, (void *) &hashvalue, sizeof(uint32));
832  if (written != sizeof(uint32))
833  ereport(ERROR,
835  errmsg("could not write to hash-join temporary file: %m")));
836 
837  written = BufFileWrite(file, (void *) tuple, tuple->t_len);
838  if (written != tuple->t_len)
839  ereport(ERROR,
841  errmsg("could not write to hash-join temporary file: %m")));
842 }
#define ERROR
Definition: elog.h:43
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:167
int errcode_for_file_access(void)
Definition: elog.c:598
unsigned int uint32
Definition: c.h:268
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:797
size_t BufFileWrite(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:412
HashJoinState* ExecInitHashJoin ( HashJoin node,
EState estate,
int  eflags 
)

Definition at line 384 of file nodeHashjoin.c.

References OpExpr::args, Assert, elog, ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecGetResultType(), ExecHashJoin(), ExecInitExpr(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitNullTupleSlot(), ExecInitQual(), ExecInitResultTupleSlot(), PlanState::ExecProcNode, ExecSetSlotDescriptor(), HashJoin::hashclauses, HashJoinState::hashclauses, HJ_BUILD_HASHTABLE, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurHashValue, HashJoinState::hj_CurSkewBucketNo, HashJoinState::hj_CurTuple, HashJoinState::hj_FirstOuterTupleSlot, HashJoinState::hj_HashOperators, HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, HashJoinState::hj_InnerHashKeys, HashJoinState::hj_JoinState, HashJoinState::hj_MatchedOuter, HashJoinState::hj_NullInnerTupleSlot, HashJoinState::hj_NullOuterTupleSlot, HashJoinState::hj_OuterHashKeys, HashJoinState::hj_OuterNotEmpty, HashJoinState::hj_OuterTupleSlot, Join::inner_unique, innerPlan, innerPlanState, INVALID_SKEW_BUCKET_NO, HashJoin::join, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, Join::joinqual, JoinState::joinqual, Join::jointype, JoinState::jointype, HashJoinState::js, lappend(), lappend_oid(), lfirst_node, linitial, lsecond, makeNode, NIL, NULL, OpExpr::opno, outerPlan, outerPlanState, Join::plan, PlanState::plan, JoinState::ps, HashState::ps, PlanState::ps_ResultTupleSlot, Plan::qual, PlanState::qual, JoinState::single_match, and PlanState::state.

Referenced by ExecInitNode().

385 {
386  HashJoinState *hjstate;
387  Plan *outerNode;
388  Hash *hashNode;
389  List *lclauses;
390  List *rclauses;
391  List *hoperators;
392  ListCell *l;
393 
394  /* check for unsupported flags */
395  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
396 
397  /*
398  * create state structure
399  */
400  hjstate = makeNode(HashJoinState);
401  hjstate->js.ps.plan = (Plan *) node;
402  hjstate->js.ps.state = estate;
403  hjstate->js.ps.ExecProcNode = ExecHashJoin;
404 
405  /*
406  * Miscellaneous initialization
407  *
408  * create expression context for node
409  */
410  ExecAssignExprContext(estate, &hjstate->js.ps);
411 
412  /*
413  * initialize child expressions
414  */
415  hjstate->js.ps.qual =
416  ExecInitQual(node->join.plan.qual, (PlanState *) hjstate);
417  hjstate->js.jointype = node->join.jointype;
418  hjstate->js.joinqual =
419  ExecInitQual(node->join.joinqual, (PlanState *) hjstate);
420  hjstate->hashclauses =
421  ExecInitQual(node->hashclauses, (PlanState *) hjstate);
422 
423  /*
424  * initialize child nodes
425  *
426  * Note: we could suppress the REWIND flag for the inner input, which
427  * would amount to betting that the hash will be a single batch. Not
428  * clear if this would be a win or not.
429  */
430  outerNode = outerPlan(node);
431  hashNode = (Hash *) innerPlan(node);
432 
433  outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);
434  innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);
435 
436  /*
437  * tuple table initialization
438  */
439  ExecInitResultTupleSlot(estate, &hjstate->js.ps);
440  hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
441 
442  /*
443  * detect whether we need only consider the first matching inner tuple
444  */
445  hjstate->js.single_match = (node->join.inner_unique ||
446  node->join.jointype == JOIN_SEMI);
447 
448  /* set up null tuples for outer joins, if needed */
449  switch (node->join.jointype)
450  {
451  case JOIN_INNER:
452  case JOIN_SEMI:
453  break;
454  case JOIN_LEFT:
455  case JOIN_ANTI:
456  hjstate->hj_NullInnerTupleSlot =
457  ExecInitNullTupleSlot(estate,
459  break;
460  case JOIN_RIGHT:
461  hjstate->hj_NullOuterTupleSlot =
462  ExecInitNullTupleSlot(estate,
464  break;
465  case JOIN_FULL:
466  hjstate->hj_NullOuterTupleSlot =
467  ExecInitNullTupleSlot(estate,
469  hjstate->hj_NullInnerTupleSlot =
470  ExecInitNullTupleSlot(estate,
472  break;
473  default:
474  elog(ERROR, "unrecognized join type: %d",
475  (int) node->join.jointype);
476  }
477 
478  /*
479  * now for some voodoo. our temporary tuple slot is actually the result
480  * tuple slot of the Hash node (which is our inner plan). we can do this
481  * because Hash nodes don't return tuples via ExecProcNode() -- instead
482  * the hash join node uses ExecScanHashBucket() to get at the contents of
483  * the hash table. -cim 6/9/91
484  */
485  {
486  HashState *hashstate = (HashState *) innerPlanState(hjstate);
487  TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
488 
489  hjstate->hj_HashTupleSlot = slot;
490  }
491 
492  /*
493  * initialize tuple type and projection info
494  */
495  ExecAssignResultTypeFromTL(&hjstate->js.ps);
496  ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
497 
500 
501  /*
502  * initialize hash-specific info
503  */
504  hjstate->hj_HashTable = NULL;
505  hjstate->hj_FirstOuterTupleSlot = NULL;
506 
507  hjstate->hj_CurHashValue = 0;
508  hjstate->hj_CurBucketNo = 0;
510  hjstate->hj_CurTuple = NULL;
511 
512  /*
513  * Deconstruct the hash clauses into outer and inner argument values, so
514  * that we can evaluate those subexpressions separately. Also make a list
515  * of the hash operator OIDs, in preparation for looking up the hash
516  * functions to use.
517  */
518  lclauses = NIL;
519  rclauses = NIL;
520  hoperators = NIL;
521  foreach(l, node->hashclauses)
522  {
523  OpExpr *hclause = lfirst_node(OpExpr, l);
524 
525  lclauses = lappend(lclauses, ExecInitExpr(linitial(hclause->args),
526  (PlanState *) hjstate));
527  rclauses = lappend(rclauses, ExecInitExpr(lsecond(hclause->args),
528  (PlanState *) hjstate));
529  hoperators = lappend_oid(hoperators, hclause->opno);
530  }
531  hjstate->hj_OuterHashKeys = lclauses;
532  hjstate->hj_InnerHashKeys = rclauses;
533  hjstate->hj_HashOperators = hoperators;
534  /* child Hash node needs to evaluate inner hash keys, too */
535  ((HashState *) innerPlanState(hjstate))->hashkeys = rclauses;
536 
537  hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;
538  hjstate->hj_MatchedOuter = false;
539  hjstate->hj_OuterNotEmpty = false;
540 
541  return hjstate;
542 }
JoinType jointype
Definition: execnodes.h:1588
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:145
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:101
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
TupleTableSlot * hj_NullInnerTupleSlot
Definition: execnodes.h:1703
ExprState * joinqual
Definition: execnodes.h:1591
PlanState ps
Definition: execnodes.h:1587
List * hashclauses
Definition: plannodes.h:726
bool single_match
Definition: execnodes.h:1589
bool hj_MatchedOuter
Definition: execnodes.h:1706
EState * state
Definition: execnodes.h:849
TupleTableSlot * hj_OuterTupleSlot
Definition: execnodes.h:1700
List * hj_OuterHashKeys
Definition: execnodes.h:1692
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1704
#define lsecond(l)
Definition: pg_list.h:116
Join join
Definition: plannodes.h:725
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:445
JoinType jointype
Definition: plannodes.h:667
uint32 hj_CurHashValue
Definition: execnodes.h:1696
int hj_CurSkewBucketNo
Definition: execnodes.h:1698
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:880
TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
Definition: execTuples.c:866
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
TupleTableSlot * hj_NullOuterTupleSlot
Definition: execnodes.h:1702
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define outerPlanState(node)
Definition: execnodes.h:893
#define innerPlan(node)
Definition: plannodes.h:173
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:492
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1699
PlanState ps
Definition: execnodes.h:1958
List * hj_HashOperators
Definition: execnodes.h:1694
#define outerPlan(node)
Definition: plannodes.h:174
List * lappend(List *list, void *datum)
Definition: list.c:128
int hj_CurBucketNo
Definition: execnodes.h:1697
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:853
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Plan * plan
Definition: execnodes.h:847
#define makeNode(_type_)
Definition: nodes.h:557
bool hj_OuterNotEmpty
Definition: execnodes.h:1707
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:423
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:474
ExprState * qual
Definition: execnodes.h:865
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1701
List * hj_InnerHashKeys
Definition: execnodes.h:1693
#define HJ_BUILD_HASHTABLE
Definition: nodeHashjoin.c:30
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
static TupleTableSlot * ExecHashJoin(PlanState *pstate)
Definition: nodeHashjoin.c:62
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
Oid opno
Definition: primnodes.h:496
#define elog
Definition: elog.h:219
bool inner_unique
Definition: plannodes.h:668
List * args
Definition: primnodes.h:502
#define innerPlanState(node)
Definition: execnodes.h:892
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
JoinState js
Definition: execnodes.h:1690
List * joinqual
Definition: plannodes.h:669
ExprState * hashclauses
Definition: execnodes.h:1691
Plan plan
Definition: plannodes.h:666
void ExecReScanHashJoin ( HashJoinState node)

Definition at line 898 of file nodeHashjoin.c.

References PlanState::chgParam, ExecHashTableDestroy(), ExecHashTableResetMatchFlags(), ExecReScan(), HJ_BUILD_HASHTABLE, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurHashValue, HashJoinState::hj_CurSkewBucketNo, HashJoinState::hj_CurTuple, HJ_FILL_INNER, HashJoinState::hj_FirstOuterTupleSlot, HashJoinState::hj_HashTable, HashJoinState::hj_JoinState, HashJoinState::hj_MatchedOuter, HJ_NEED_NEW_OUTER, HashJoinState::hj_OuterNotEmpty, INVALID_SKEW_BUCKET_NO, HashJoinState::js, PlanState::lefttree, HashJoinTableData::nbatch, NULL, JoinState::ps, and PlanState::righttree.

Referenced by ExecReScan().

899 {
900  /*
901  * In a multi-batch join, we currently have to do rescans the hard way,
902  * primarily because batch temp files may have already been released. But
903  * if it's a single-batch join, and there is no parameter change for the
904  * inner subnode, then we can just re-use the existing hash table without
905  * rebuilding it.
906  */
907  if (node->hj_HashTable != NULL)
908  {
909  if (node->hj_HashTable->nbatch == 1 &&
910  node->js.ps.righttree->chgParam == NULL)
911  {
912  /*
913  * Okay to reuse the hash table; needn't rescan inner, either.
914  *
915  * However, if it's a right/full join, we'd better reset the
916  * inner-tuple match flags contained in the table.
917  */
918  if (HJ_FILL_INNER(node))
920 
921  /*
922  * Also, we need to reset our state about the emptiness of the
923  * outer relation, so that the new scan of the outer will update
924  * it correctly if it turns out to be empty this time. (There's no
925  * harm in clearing it now because ExecHashJoin won't need the
926  * info. In the other cases, where the hash table doesn't exist
927  * or we are destroying it, we leave this state alone because
928  * ExecHashJoin will need it the first time through.)
929  */
930  node->hj_OuterNotEmpty = false;
931 
932  /* ExecHashJoin can skip the BUILD_HASHTABLE step */
934  }
935  else
936  {
937  /* must destroy and rebuild hash table */
939  node->hj_HashTable = NULL;
941 
942  /*
943  * if chgParam of subnode is not null then plan will be re-scanned
944  * by first ExecProcNode.
945  */
946  if (node->js.ps.righttree->chgParam == NULL)
947  ExecReScan(node->js.ps.righttree);
948  }
949  }
950 
951  /* Always reset intra-tuple state */
952  node->hj_CurHashValue = 0;
953  node->hj_CurBucketNo = 0;
955  node->hj_CurTuple = NULL;
956 
957  node->hj_MatchedOuter = false;
959 
960  /*
961  * if chgParam of subnode is not null then plan will be re-scanned by
962  * first ExecProcNode.
963  */
964  if (node->js.ps.lefttree->chgParam == NULL)
965  ExecReScan(node->js.ps.lefttree);
966 }
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:101
PlanState ps
Definition: execnodes.h:1587
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
bool hj_MatchedOuter
Definition: execnodes.h:1706
struct PlanState * righttree
Definition: execnodes.h:867
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1704
struct PlanState * lefttree
Definition: execnodes.h:866
#define HJ_FILL_INNER(hjstate)
Definition: nodeHashjoin.c:40
uint32 hj_CurHashValue
Definition: execnodes.h:1696
int hj_CurSkewBucketNo
Definition: execnodes.h:1698
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1699
Bitmapset * chgParam
Definition: execnodes.h:875
int hj_CurBucketNo
Definition: execnodes.h:1697
bool hj_OuterNotEmpty
Definition: execnodes.h:1707
#define NULL
Definition: c.h:229
#define HJ_NEED_NEW_OUTER
Definition: nodeHashjoin.c:31
#define HJ_BUILD_HASHTABLE
Definition: nodeHashjoin.c:30
HashJoinTable hj_HashTable
Definition: execnodes.h:1695
void ExecHashTableResetMatchFlags(HashJoinTable hashtable)
Definition: nodeHash.c:1245
JoinState js
Definition: execnodes.h:1690
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition: nodeHash.c:560