PostgreSQL Source Code  git master
nodeHashjoin.h File Reference
#include "nodes/execnodes.h"
#include "storage/buffile.h"
Include dependency graph for nodeHashjoin.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

HashJoinStateExecInitHashJoin (HashJoin *node, EState *estate, int eflags)
 
void ExecEndHashJoin (HashJoinState *node)
 
void ExecReScanHashJoin (HashJoinState *node)
 
void ExecHashJoinSaveTuple (MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
 

Function Documentation

◆ ExecEndHashJoin()

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, 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:1600
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * hj_OuterTupleSlot
Definition: execnodes.h:1713
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:523
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:882
#define outerPlanState(node)
Definition: execnodes.h:895
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1714
HashJoinTable hj_HashTable
Definition: execnodes.h:1708
#define innerPlanState(node)
Definition: execnodes.h:894
JoinState js
Definition: execnodes.h:1703
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition: nodeHash.c:560

◆ ExecHashJoinSaveTuple()

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, 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:164
int errcode_for_file_access(void)
Definition: elog.c:598
unsigned int uint32
Definition: c.h:296
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
size_t BufFileWrite(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:408

◆ ExecInitHashJoin()

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, HJ_BUILD_HASHTABLE, 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, Join::jointype, HashJoinState::js, lappend(), lappend_oid(), lfirst_node, linitial, lsecond, makeNode, NIL, OpExpr::opno, outerPlan, outerPlanState, Join::plan, PlanState::plan, JoinState::ps, HashState::ps, PlanState::ps_ResultTupleSlot, Plan::qual, PlanState::qual, 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:1601
#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:1716
ExprState * joinqual
Definition: execnodes.h:1604
PlanState ps
Definition: execnodes.h:1600
List * hashclauses
Definition: plannodes.h:726
bool single_match
Definition: execnodes.h:1602
bool hj_MatchedOuter
Definition: execnodes.h:1719
EState * state
Definition: execnodes.h:851
TupleTableSlot * hj_OuterTupleSlot
Definition: execnodes.h:1713
List * hj_OuterHashKeys
Definition: execnodes.h:1705
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1717
#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:447
JoinType jointype
Definition: plannodes.h:667
uint32 hj_CurHashValue
Definition: execnodes.h:1709
int hj_CurSkewBucketNo
Definition: execnodes.h:1711
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:882
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:1715
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:895
#define innerPlan(node)
Definition: plannodes.h:173
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:494
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1712
PlanState ps
Definition: execnodes.h:1989
List * hj_HashOperators
Definition: execnodes.h:1707
#define outerPlan(node)
Definition: plannodes.h:174
List * lappend(List *list, void *datum)
Definition: list.c:128
int hj_CurBucketNo
Definition: execnodes.h:1710
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:855
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Plan * plan
Definition: execnodes.h:849
#define makeNode(_type_)
Definition: nodes.h:559
bool hj_OuterNotEmpty
Definition: execnodes.h:1720
#define Assert(condition)
Definition: c.h:670
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:425
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:476
ExprState * qual
Definition: execnodes.h:867
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1714
List * hj_InnerHashKeys
Definition: execnodes.h:1706
#define HJ_BUILD_HASHTABLE
Definition: nodeHashjoin.c:30
HashJoinTable hj_HashTable
Definition: execnodes.h:1708
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:894
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
JoinState js
Definition: execnodes.h:1703
List * joinqual
Definition: plannodes.h:669
ExprState * hashclauses
Definition: execnodes.h:1704
Plan plan
Definition: plannodes.h:666

◆ ExecReScanHashJoin()

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, 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;
958  node->hj_FirstOuterTupleSlot = NULL;
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:1600
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
bool hj_MatchedOuter
Definition: execnodes.h:1719
struct PlanState * righttree
Definition: execnodes.h:869
TupleTableSlot * hj_FirstOuterTupleSlot
Definition: execnodes.h:1717
struct PlanState * lefttree
Definition: execnodes.h:868
#define HJ_FILL_INNER(hjstate)
Definition: nodeHashjoin.c:40
uint32 hj_CurHashValue
Definition: execnodes.h:1709
int hj_CurSkewBucketNo
Definition: execnodes.h:1711
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1712
Bitmapset * chgParam
Definition: execnodes.h:877
int hj_CurBucketNo
Definition: execnodes.h:1710
bool hj_OuterNotEmpty
Definition: execnodes.h:1720
#define HJ_NEED_NEW_OUTER
Definition: nodeHashjoin.c:31
#define HJ_BUILD_HASHTABLE
Definition: nodeHashjoin.c:30
HashJoinTable hj_HashTable
Definition: execnodes.h:1708
void ExecHashTableResetMatchFlags(HashJoinTable hashtable)
Definition: nodeHash.c:1245
JoinState js
Definition: execnodes.h:1703
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition: nodeHash.c:560