PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeHashjoin.h File Reference
#include "access/parallel.h"
#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 ExecShutdownHashJoin (HashJoinState *node)
 
void ExecHashJoinEstimate (HashJoinState *state, ParallelContext *pcxt)
 
void ExecHashJoinInitializeDSM (HashJoinState *state, ParallelContext *pcxt)
 
void ExecHashJoinReInitializeDSM (HashJoinState *state, ParallelContext *pcxt)
 
void ExecHashJoinInitializeWorker (HashJoinState *state, ParallelWorkerContext *pwcxt)
 
void ExecHashJoinSaveTuple (MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr, HashJoinTable hashtable)
 

Function Documentation

◆ ExecEndHashJoin()

void ExecEndHashJoin ( HashJoinState node)
extern

Definition at line 1062 of file nodeHashjoin.c.

1063{
1065
1066 /*
1067 * Free tuple stores if we made them (must do this before
1068 * ExecHashTableDestroy deletes hashCxt)
1069 */
1070 if (node->hj_NullOuterTupleStore)
1071 {
1074 }
1075 if (hashNode->null_tuple_store)
1076 {
1077 tuplestore_end(hashNode->null_tuple_store);
1078 hashNode->null_tuple_store = NULL;
1079 }
1080
1081 /*
1082 * Free hash table
1083 */
1084 if (node->hj_HashTable)
1085 {
1087 node->hj_HashTable = NULL;
1088 }
1089
1090 /*
1091 * clean up subtrees
1092 */
1095}
void ExecEndNode(PlanState *node)
#define outerPlanState(node)
Definition execnodes.h:1273
#define innerPlanState(node)
Definition execnodes.h:1272
void ExecHashTableDestroy(HashJoinTable hashtable)
Definition nodeHash.c:981
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static int fb(int x)
Tuplestorestate * hj_NullOuterTupleStore
Definition execnodes.h:2232
HashJoinTable hj_HashTable
Definition execnodes.h:2223
void tuplestore_end(Tuplestorestate *state)
Definition tuplestore.c:493

References castNode, ExecEndNode(), ExecHashTableDestroy(), fb(), HashJoinState::hj_HashTable, HashJoinState::hj_NullOuterTupleStore, innerPlanState, outerPlanState, and tuplestore_end().

Referenced by ExecEndNode().

◆ ExecHashJoinEstimate()

void ExecHashJoinEstimate ( HashJoinState state,
ParallelContext pcxt 
)
extern

Definition at line 1843 of file nodeHashjoin.c.

1844{
1847}
#define shm_toc_estimate_chunk(e, sz)
Definition shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition shm_toc.h:53
shm_toc_estimator estimator
Definition parallel.h:43

References ParallelContext::estimator, shm_toc_estimate_chunk, and shm_toc_estimate_keys.

Referenced by ExecParallelEstimate().

◆ ExecHashJoinInitializeDSM()

void ExecHashJoinInitializeDSM ( HashJoinState state,
ParallelContext pcxt 
)
extern

Definition at line 1850 of file nodeHashjoin.c.

1851{
1852 int plan_node_id = state->js.ps.plan->plan_node_id;
1854 ParallelHashJoinState *pstate;
1855
1856 /*
1857 * Disable shared hash table mode if we failed to create a real DSM
1858 * segment, because that means that we don't have a DSA area to work with.
1859 */
1860 if (pcxt->seg == NULL)
1861 return;
1862
1864
1865 /*
1866 * Set up the state needed to coordinate access to the shared hash
1867 * table(s), using the plan node ID as the toc key.
1868 */
1869 pstate = shm_toc_allocate(pcxt->toc, sizeof(ParallelHashJoinState));
1870 shm_toc_insert(pcxt->toc, plan_node_id, pstate);
1871
1872 /*
1873 * Set up the shared hash join state with no batches initially.
1874 * ExecHashTableCreate() will prepare at least one later and set nbatch
1875 * and space_allowed.
1876 */
1877 pstate->nbatch = 0;
1878 pstate->space_allowed = 0;
1879 pstate->batches = InvalidDsaPointer;
1881 pstate->nbuckets = 0;
1882 pstate->growth = PHJ_GROWTH_OK;
1884 pg_atomic_init_u32(&pstate->distributor, 0);
1885 pstate->nparticipants = pcxt->nworkers + 1;
1886 pstate->total_tuples = 0;
1887 LWLockInitialize(&pstate->lock,
1889 BarrierInit(&pstate->build_barrier, 0);
1890 BarrierInit(&pstate->grow_batches_barrier, 0);
1891 BarrierInit(&pstate->grow_buckets_barrier, 0);
1892
1893 /* Set up the space we'll use for shared temporary files. */
1894 SharedFileSetInit(&pstate->fileset, pcxt->seg);
1895
1896 /* Initialize the shared state in the hash node. */
1898 hashNode->parallel_state = pstate;
1899}
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition atomics.h:219
void BarrierInit(Barrier *barrier, int participants)
Definition barrier.c:100
#define InvalidDsaPointer
Definition dsa.h:78
void ExecSetExecProcNode(PlanState *node, ExecProcNodeMtd function)
@ PHJ_GROWTH_OK
Definition hashjoin.h:244
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:699
static TupleTableSlot * ExecParallelHashJoin(PlanState *pstate)
void SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition shm_toc.c:171
dsm_segment * seg
Definition parallel.h:44
shm_toc * toc
Definition parallel.h:46
Barrier grow_batches_barrier
Definition hashjoin.h:272
dsa_pointer old_batches
Definition hashjoin.h:260
dsa_pointer chunk_work_queue
Definition hashjoin.h:265
Barrier grow_buckets_barrier
Definition hashjoin.h:273
ParallelHashGrowth growth
Definition hashjoin.h:264
pg_atomic_uint32 distributor
Definition hashjoin.h:274
SharedFileSet fileset
Definition hashjoin.h:276
dsa_pointer batches
Definition hashjoin.h:259

References BarrierInit(), ParallelHashJoinState::batches, ParallelHashJoinState::build_barrier, ParallelHashJoinState::chunk_work_queue, ParallelHashJoinState::distributor, ExecParallelHashJoin(), ExecSetExecProcNode(), fb(), ParallelHashJoinState::fileset, ParallelHashJoinState::grow_batches_barrier, ParallelHashJoinState::grow_buckets_barrier, ParallelHashJoinState::growth, innerPlanState, InvalidDsaPointer, ParallelHashJoinState::lock, LWLockInitialize(), ParallelHashJoinState::nbatch, ParallelHashJoinState::nbuckets, ParallelHashJoinState::nparticipants, ParallelContext::nworkers, ParallelHashJoinState::old_batches, pg_atomic_init_u32(), PHJ_GROWTH_OK, ParallelContext::seg, SharedFileSetInit(), shm_toc_allocate(), shm_toc_insert(), ParallelHashJoinState::space_allowed, ParallelContext::toc, and ParallelHashJoinState::total_tuples.

Referenced by ExecParallelInitializeDSM().

◆ ExecHashJoinInitializeWorker()

void ExecHashJoinInitializeWorker ( HashJoinState state,
ParallelWorkerContext pwcxt 
)
extern

Definition at line 1961 of file nodeHashjoin.c.

1963{
1965 int plan_node_id = state->js.ps.plan->plan_node_id;
1966 ParallelHashJoinState *pstate =
1967 shm_toc_lookup(pwcxt->toc, plan_node_id, false);
1968
1969 /* Attach to the space for shared temporary files. */
1970 SharedFileSetAttach(&pstate->fileset, pwcxt->seg);
1971
1972 /* Attach to the shared state in the hash node. */
1974 hashNode->parallel_state = pstate;
1975
1977}
void SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition shm_toc.c:232

References ExecParallelHashJoin(), ExecSetExecProcNode(), fb(), ParallelHashJoinState::fileset, innerPlanState, SharedFileSetAttach(), and shm_toc_lookup().

Referenced by ExecParallelInitializeWorker().

◆ ExecHashJoinReInitializeDSM()

void ExecHashJoinReInitializeDSM ( HashJoinState state,
ParallelContext pcxt 
)
extern

Definition at line 1908 of file nodeHashjoin.c.

1909{
1910 int plan_node_id = state->js.ps.plan->plan_node_id;
1911 ParallelHashJoinState *pstate;
1913
1914 /* Nothing to do if we failed to create a DSM segment. */
1915 if (pcxt->seg == NULL)
1916 return;
1917
1918 pstate = shm_toc_lookup(pcxt->toc, plan_node_id, false);
1919
1920 /*
1921 * It would be possible to reuse the shared hash table in single-batch
1922 * cases by resetting and then fast-forwarding build_barrier to
1923 * PHJ_BUILD_FREE and batch 0's batch_barrier to PHJ_BATCH_PROBE, but
1924 * currently shared hash tables are already freed by now (by the last
1925 * participant to detach from the batch). We could consider keeping it
1926 * around for single-batch joins. We'd also need to adjust
1927 * finalize_plan() so that it doesn't record a dummy dependency for
1928 * Parallel Hash nodes, preventing the rescan optimization. For now we
1929 * don't try.
1930 */
1931
1932 /* Detach, freeing any remaining shared memory. */
1933 if (state->hj_HashTable != NULL)
1934 {
1935 ExecHashTableDetachBatch(state->hj_HashTable);
1936 ExecHashTableDetach(state->hj_HashTable);
1937 }
1938
1939 /* Clear any shared batch files. */
1941
1942 /* We'd better clear our local null-key tuplestores, too. */
1943 if (state->hj_NullOuterTupleStore)
1944 {
1945 tuplestore_end(state->hj_NullOuterTupleStore);
1946 state->hj_NullOuterTupleStore = NULL;
1947 }
1949 if (hashNode->null_tuple_store)
1950 {
1951 tuplestore_end(hashNode->null_tuple_store);
1952 hashNode->null_tuple_store = NULL;
1953 }
1954
1955
1956 /* Reset build_barrier to PHJ_BUILD_ELECT so we can go around again. */
1957 BarrierInit(&pstate->build_barrier, 0);
1958}
void ExecHashTableDetachBatch(HashJoinTable hashtable)
Definition nodeHash.c:3367
void ExecHashTableDetach(HashJoinTable hashtable)
Definition nodeHash.c:3459
void SharedFileSetDeleteAll(SharedFileSet *fileset)

References BarrierInit(), ParallelHashJoinState::build_barrier, ExecHashTableDetach(), ExecHashTableDetachBatch(), fb(), ParallelHashJoinState::fileset, innerPlanState, ParallelContext::seg, SharedFileSetDeleteAll(), shm_toc_lookup(), ParallelContext::toc, and tuplestore_end().

Referenced by ExecParallelReInitializeDSM().

◆ ExecHashJoinSaveTuple()

void ExecHashJoinSaveTuple ( MinimalTuple  tuple,
uint32  hashvalue,
BufFile **  fileptr,
HashJoinTable  hashtable 
)
extern

Definition at line 1571 of file nodeHashjoin.c.

1573{
1574 BufFile *file = *fileptr;
1575
1576 /*
1577 * The batch file is lazily created. If this is the first tuple written to
1578 * this batch, the batch file is created and its buffer is allocated in
1579 * the spillCxt context, NOT in the batchCxt.
1580 *
1581 * During the build phase, buffered files are created for inner batches.
1582 * Each batch's buffered file is closed (and its buffer freed) after the
1583 * batch is loaded into memory during the outer side scan. Therefore, it
1584 * is necessary to allocate the batch file buffer in a memory context
1585 * which outlives the batch itself.
1586 *
1587 * Also, we use spillCxt instead of hashCxt for a better accounting of the
1588 * spilling memory consumption.
1589 */
1590 if (file == NULL)
1591 {
1593
1594 file = BufFileCreateTemp(false);
1595 *fileptr = file;
1596
1598 }
1599
1600 BufFileWrite(file, &hashvalue, sizeof(uint32));
1601 BufFileWrite(file, tuple, tuple->t_len);
1602}
BufFile * BufFileCreateTemp(bool interXact)
Definition buffile.c:194
void BufFileWrite(BufFile *file, const void *ptr, size_t size)
Definition buffile.c:677
uint32_t uint32
Definition c.h:618
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
MemoryContext spillCxt
Definition hashjoin.h:370

References BufFileCreateTemp(), BufFileWrite(), fb(), MemoryContextSwitchTo(), HashJoinTableData::spillCxt, and MinimalTupleData::t_len.

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

◆ ExecInitHashJoin()

HashJoinState * ExecInitHashJoin ( HashJoin node,
EState estate,
int  eflags 
)
extern

Definition at line 834 of file nodeHashjoin.c.

835{
838 Hash *hashNode;
840 innerDesc;
841 const TupleTableSlotOps *ops;
842
843 /* check for unsupported flags */
845
846 /*
847 * create state structure
848 */
850 hjstate->js.ps.plan = (Plan *) node;
851 hjstate->js.ps.state = estate;
852
853 /*
854 * See ExecHashJoinInitializeDSM() and ExecHashJoinInitializeWorker()
855 * where this function may be replaced with a parallel version, if we
856 * managed to launch a parallel query.
857 */
858 hjstate->js.ps.ExecProcNode = ExecHashJoin;
859 hjstate->js.jointype = node->join.jointype;
860
861 /*
862 * Miscellaneous initialization
863 *
864 * create expression context for node
865 */
866 ExecAssignExprContext(estate, &hjstate->js.ps);
867
868 /*
869 * initialize child nodes
870 *
871 * Note: we could suppress the REWIND flag for the inner input, which
872 * would amount to betting that the hash will be a single batch. Not
873 * clear if this would be a win or not.
874 */
875 outerNode = outerPlan(node);
876 hashNode = (Hash *) innerPlan(node);
877
878 outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);
880 innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);
882
883 /*
884 * Initialize result slot, type and projection.
885 */
888
889 /*
890 * tuple table initialization
891 */
893 hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc,
894 ops);
895
896 /*
897 * detect whether we need only consider the first matching inner tuple
898 */
899 hjstate->js.single_match = (node->join.inner_unique ||
900 node->join.jointype == JOIN_SEMI);
901
902 /* set up null tuples for outer joins, if needed */
903 switch (node->join.jointype)
904 {
905 case JOIN_INNER:
906 case JOIN_SEMI:
907 case JOIN_RIGHT_SEMI:
908 break;
909 case JOIN_LEFT:
910 case JOIN_ANTI:
911 hjstate->hj_NullInnerTupleSlot =
913 break;
914 case JOIN_RIGHT:
915 case JOIN_RIGHT_ANTI:
916 hjstate->hj_NullOuterTupleSlot =
918 break;
919 case JOIN_FULL:
920 hjstate->hj_NullOuterTupleSlot =
922 hjstate->hj_NullInnerTupleSlot =
924 break;
925 default:
926 elog(ERROR, "unrecognized join type: %d",
927 (int) node->join.jointype);
928 }
929
930 /*
931 * now for some voodoo. our temporary tuple slot is actually the result
932 * tuple slot of the Hash node (which is our inner plan). we can do this
933 * because Hash nodes don't return tuples via ExecProcNode() -- instead
934 * the hash join node uses ExecScanHashBucket() to get at the contents of
935 * the hash table. -cim 6/9/91
936 */
937 {
939 Hash *hash = (Hash *) hashstate->ps.plan;
940 TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
943 bool *hash_strict;
944 ListCell *lc;
945 int nkeys;
946
947
948 hjstate->hj_HashTupleSlot = slot;
949
950 /*
951 * Build ExprStates to obtain hash values for either side of the join.
952 * Note: must build the ExprStates before ExecHashTableCreate() so we
953 * properly attribute any SubPlans that exist in the hash expressions
954 * to the correct PlanState.
955 */
956 nkeys = list_length(node->hashoperators);
957
960 hash_strict = palloc_array(bool, nkeys);
961
962 /*
963 * Determine the hash function for each side of the join for the given
964 * join operator, and detect whether the join operator is strict.
965 */
966 foreach(lc, node->hashoperators)
967 {
970
974 elog(ERROR,
975 "could not find hash function for hash operator %u",
976 hashop);
978 }
979
980 /*
981 * Build an ExprState to generate the hash value for the expressions
982 * on the outer side of the join.
983 */
984 hjstate->hj_OuterHash =
985 ExecBuildHash32Expr(hjstate->js.ps.ps_ResultTupleDesc,
986 hjstate->js.ps.resultops,
988 node->hashcollations,
989 node->hashkeys,
991 &hjstate->js.ps,
992 0);
993
994 /* As above, but for the inner side of the join */
995 hashstate->hash_expr =
996 ExecBuildHash32Expr(hashstate->ps.ps_ResultTupleDesc,
997 hashstate->ps.resultops,
999 node->hashcollations,
1000 hash->hashkeys,
1002 &hashstate->ps,
1003 0);
1004
1005 /* Remember whether we need to save tuples with null join keys */
1006 hjstate->hj_KeepNullTuples = HJ_FILL_OUTER(hjstate);
1007 hashstate->keep_null_tuples = HJ_FILL_INNER(hjstate);
1008
1009 /*
1010 * Set up the skew table hash function while we have a record of the
1011 * first key's hash function Oid.
1012 */
1013 if (OidIsValid(hash->skewTable))
1014 {
1015 hashstate->skew_hashfunction = palloc0_object(FmgrInfo);
1016 hashstate->skew_collation = linitial_oid(node->hashcollations);
1017 fmgr_info(outer_hashfuncid[0], hashstate->skew_hashfunction);
1018 }
1019
1020 /* no need to keep these */
1024 }
1025
1026 /*
1027 * initialize child expressions
1028 */
1029 hjstate->js.ps.qual =
1030 ExecInitQual(node->join.plan.qual, (PlanState *) hjstate);
1031 hjstate->js.joinqual =
1033 hjstate->hashclauses =
1035
1036 /*
1037 * initialize hash-specific info
1038 */
1039 hjstate->hj_HashTable = NULL;
1040 hjstate->hj_NullOuterTupleStore = NULL;
1041 hjstate->hj_FirstOuterTupleSlot = NULL;
1042
1043 hjstate->hj_CurHashValue = 0;
1044 hjstate->hj_CurBucketNo = 0;
1045 hjstate->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO;
1046 hjstate->hj_CurTuple = NULL;
1047
1048 hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;
1049 hjstate->hj_MatchedOuter = false;
1050 hjstate->hj_OuterNotEmpty = false;
1051
1052 return hjstate;
1053}
#define Assert(condition)
Definition c.h:945
#define OidIsValid(objectId)
Definition c.h:860
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
ExprState * ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops, const Oid *hashfunc_oids, const List *collations, const List *hash_exprs, const bool *opstrict, PlanState *parent, uint32 init_value)
Definition execExpr.c:4329
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType, const TupleTableSlotOps *tts_ops)
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition execUtils.c:588
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition execUtils.c:509
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
#define EXEC_FLAG_MARK
Definition executor.h:71
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#define INVALID_SKEW_BUCKET_NO
Definition hashjoin.h:131
int i
Definition isn.c:77
bool op_strict(Oid opno)
Definition lsyscache.c:1697
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition lsyscache.c:577
void pfree(void *pointer)
Definition mcxt.c:1616
#define HJ_FILL_INNER(hjstate)
#define HJ_FILL_OUTER(hjstate)
static TupleTableSlot * ExecHashJoin(PlanState *pstate)
#define HJ_BUILD_HASHTABLE
#define makeNode(_type_)
Definition nodes.h:161
@ JOIN_SEMI
Definition nodes.h:317
@ JOIN_FULL
Definition nodes.h:305
@ JOIN_INNER
Definition nodes.h:303
@ JOIN_RIGHT
Definition nodes.h:306
@ JOIN_RIGHT_SEMI
Definition nodes.h:319
@ JOIN_LEFT
Definition nodes.h:304
@ JOIN_RIGHT_ANTI
Definition nodes.h:320
@ JOIN_ANTI
Definition nodes.h:318
static int list_length(const List *l)
Definition pg_list.h:152
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define linitial_oid(l)
Definition pg_list.h:180
#define lfirst_oid(lc)
Definition pg_list.h:174
#define innerPlan(node)
Definition plannodes.h:264
#define outerPlan(node)
Definition plannodes.h:265
unsigned int Oid
static unsigned hash(unsigned *uv, int n)
Definition rege_dfa.c:715
List * hashcollations
Definition plannodes.h:1065
List * hashclauses
Definition plannodes.h:1063
List * hashoperators
Definition plannodes.h:1064
Join join
Definition plannodes.h:1062
List * hashkeys
Definition plannodes.h:1071
Plan plan
Definition plannodes.h:1419
List * joinqual
Definition plannodes.h:988
JoinType jointype
Definition plannodes.h:985
bool inner_unique
Definition plannodes.h:986

References Assert, elog, ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildHash32Expr(), ExecGetResultSlotOps(), ExecGetResultType(), ExecHashJoin(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitNullTupleSlot(), ExecInitQual(), ExecInitResultTupleSlotTL(), fb(), fmgr_info(), foreach_current_index, get_op_hash_functions(), hash(), HashJoin::hashclauses, HashJoin::hashcollations, HashJoin::hashkeys, HashJoin::hashoperators, HJ_BUILD_HASHTABLE, HJ_FILL_INNER, HJ_FILL_OUTER, i, Join::inner_unique, innerPlan, innerPlanState, INVALID_SKEW_BUCKET_NO, HashJoin::join, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_RIGHT_ANTI, JOIN_RIGHT_SEMI, JOIN_SEMI, Join::joinqual, Join::jointype, lfirst_oid, linitial_oid, list_length(), makeNode, OidIsValid, op_strict(), outerPlan, outerPlanState, palloc0_object, palloc_array, pfree(), Hash::plan, and TTSOpsVirtual.

Referenced by ExecInitNode().

◆ ExecReScanHashJoin()

void ExecReScanHashJoin ( HashJoinState node)
extern

Definition at line 1651 of file nodeHashjoin.c.

1652{
1655
1656 /*
1657 * We're always going to rescan the outer rel, so drop the associated
1658 * null-keys tuplestore; we'll rebuild it during the rescan. (Must do
1659 * this before ExecHashTableDestroy deletes hashCxt.)
1660 */
1661 if (node->hj_NullOuterTupleStore)
1662 {
1665 }
1666
1667 /*
1668 * In a multi-batch join, we currently have to do rescans the hard way,
1669 * primarily because batch temp files may have already been released. But
1670 * if it's a single-batch join, and there is no parameter change for the
1671 * inner subnode, then we can just re-use the existing hash table without
1672 * rebuilding it.
1673 */
1674 if (node->hj_HashTable != NULL)
1675 {
1677
1678 Assert(hashNode->hashtable == node->hj_HashTable);
1679
1680 if (node->hj_HashTable->nbatch == 1 &&
1681 innerPlan->chgParam == NULL)
1682 {
1683 /*
1684 * Okay to reuse the hash table; needn't rescan inner, either.
1685 *
1686 * However, if it's a right/right-anti/right-semi/full join, we'd
1687 * better reset the inner-tuple match flags contained in the
1688 * table.
1689 */
1690 if (HJ_FILL_INNER(node) || node->js.jointype == JOIN_RIGHT_SEMI)
1692
1693 /*
1694 * Also, we need to reset our state about the emptiness of the
1695 * outer relation, so that the new scan of the outer will update
1696 * it correctly if it turns out to be empty this time. (There's no
1697 * harm in clearing it now because ExecHashJoin won't need the
1698 * info. In the other cases, where the hash table doesn't exist
1699 * or we are destroying it, we leave this state alone because
1700 * ExecHashJoin will need it the first time through.)
1701 */
1702 node->hj_OuterNotEmpty = false;
1703
1704 /*
1705 * Also, rewind inner null-key tuplestore so that we can return
1706 * those tuples again.
1707 */
1708 if (hashNode->null_tuple_store)
1709 tuplestore_rescan(hashNode->null_tuple_store);
1710
1711 /* ExecHashJoin can skip the BUILD_HASHTABLE step */
1713 }
1714 else
1715 {
1716 /* must destroy and rebuild hash table */
1717
1718 /* accumulate stats from old hash table, if wanted */
1719 /* (this should match ExecShutdownHash) */
1720 if (hashNode->ps.instrument && !hashNode->hinstrument)
1722 if (hashNode->hinstrument)
1724 hashNode->hashtable);
1725
1726 /* free inner null-key tuplestore before ExecHashTableDestroy */
1727 if (hashNode->null_tuple_store)
1728 {
1729 tuplestore_end(hashNode->null_tuple_store);
1730 hashNode->null_tuple_store = NULL;
1731 }
1732
1733 /* for safety, be sure to clear child plan node's pointer too */
1734 hashNode->hashtable = NULL;
1735
1737 node->hj_HashTable = NULL;
1739
1740 /*
1741 * if chgParam of subnode is not null then plan will be re-scanned
1742 * by first ExecProcNode.
1743 */
1744 if (innerPlan->chgParam == NULL)
1746 }
1747 }
1748
1749 /* Always reset intra-tuple state */
1750 node->hj_CurHashValue = 0;
1751 node->hj_CurBucketNo = 0;
1753 node->hj_CurTuple = NULL;
1754
1755 node->hj_MatchedOuter = false;
1757
1758 /*
1759 * if chgParam of subnode is not null then plan will be re-scanned by
1760 * first ExecProcNode.
1761 */
1762 if (outerPlan->chgParam == NULL)
1764}
void ExecReScan(PlanState *node)
Definition execAmi.c:78
void ExecHashAccumInstrumentation(HashInstrumentation *instrument, HashJoinTable hashtable)
Definition nodeHash.c:2935
void ExecHashTableResetMatchFlags(HashJoinTable hashtable)
Definition nodeHash.c:2381
#define HJ_NEED_NEW_OUTER
HashJoinTuple hj_CurTuple
Definition execnodes.h:2227
int hj_CurSkewBucketNo
Definition execnodes.h:2226
bool hj_OuterNotEmpty
Definition execnodes.h:2237
JoinState js
Definition execnodes.h:2220
TupleTableSlot * hj_FirstOuterTupleSlot
Definition execnodes.h:2233
bool hj_MatchedOuter
Definition execnodes.h:2236
uint32 hj_CurHashValue
Definition execnodes.h:2224
JoinType jointype
Definition execnodes.h:2116
void tuplestore_rescan(Tuplestorestate *state)

References Assert, castNode, ExecHashAccumInstrumentation(), ExecHashTableDestroy(), ExecHashTableResetMatchFlags(), ExecReScan(), fb(), 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_NullOuterTupleStore, HashJoinState::hj_OuterNotEmpty, innerPlan, innerPlanState, INVALID_SKEW_BUCKET_NO, JOIN_RIGHT_SEMI, JoinState::jointype, HashJoinState::js, HashJoinTableData::nbatch, outerPlan, outerPlanState, palloc0_object, tuplestore_end(), and tuplestore_rescan().

Referenced by ExecReScan().

◆ ExecShutdownHashJoin()

void ExecShutdownHashJoin ( HashJoinState node)
extern

Definition at line 1767 of file nodeHashjoin.c.

1768{
1769 if (node->hj_HashTable)
1770 {
1771 /*
1772 * Detach from shared state before DSM memory goes away. This makes
1773 * sure that we don't have any pointers into DSM memory by the time
1774 * ExecEndHashJoin runs.
1775 */
1778 }
1779}

References ExecHashTableDetach(), ExecHashTableDetachBatch(), and HashJoinState::hj_HashTable.

Referenced by ExecShutdownNode_walker().