diff options
Diffstat (limited to 'src/backend/executor/nodeHash.c')
-rw-r--r-- | src/backend/executor/nodeHash.c | 190 |
1 files changed, 38 insertions, 152 deletions
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 61480733a12..570a90ebe15 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -47,7 +47,8 @@ static void ExecHashIncreaseNumBatches(HashJoinTable hashtable); static void ExecHashIncreaseNumBuckets(HashJoinTable hashtable); static void ExecParallelHashIncreaseNumBatches(HashJoinTable hashtable); static void ExecParallelHashIncreaseNumBuckets(HashJoinTable hashtable); -static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, +static void ExecHashBuildSkewHash(HashState *hashstate, + HashJoinTable hashtable, Hash *node, int mcvsToUse); static void ExecHashSkewTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, @@ -138,11 +139,9 @@ static void MultiExecPrivateHash(HashState *node) { PlanState *outerNode; - List *hashkeys; HashJoinTable hashtable; TupleTableSlot *slot; ExprContext *econtext; - uint32 hashvalue; /* * get state info from node @@ -153,7 +152,6 @@ MultiExecPrivateHash(HashState *node) /* * set expression context */ - hashkeys = node->hashkeys; econtext = node->ps.ps_ExprContext; /* @@ -162,15 +160,23 @@ MultiExecPrivateHash(HashState *node) */ for (;;) { + bool isnull; + Datum hashdatum; + slot = ExecProcNode(outerNode); if (TupIsNull(slot)) break; /* We have to compute the hash value */ econtext->ecxt_outertuple = slot; - if (ExecHashGetHashValue(hashtable, econtext, hashkeys, - false, hashtable->keepNulls, - &hashvalue)) + + ResetExprContext(econtext); + + hashdatum = ExecEvalExprSwitchContext(node->hash_expr, econtext, + &isnull); + + if (!isnull) { + uint32 hashvalue = DatumGetUInt32(hashdatum); int bucketNumber; bucketNumber = ExecHashGetSkewBucket(hashtable, hashvalue); @@ -215,7 +221,6 @@ MultiExecParallelHash(HashState *node) { ParallelHashJoinState *pstate; PlanState *outerNode; - List *hashkeys; HashJoinTable hashtable; TupleTableSlot *slot; ExprContext *econtext; @@ -232,7 +237,6 @@ MultiExecParallelHash(HashState *node) /* * set expression context */ - hashkeys = node->hashkeys; econtext = node->ps.ps_ExprContext; /* @@ -279,13 +283,20 @@ MultiExecParallelHash(HashState *node) ExecParallelHashTableSetCurrentBatch(hashtable, 0); for (;;) { + bool isnull; + slot = ExecProcNode(outerNode); if (TupIsNull(slot)) break; econtext->ecxt_outertuple = slot; - if (ExecHashGetHashValue(hashtable, econtext, hashkeys, - false, hashtable->keepNulls, - &hashvalue)) + + ResetExprContext(econtext); + + hashvalue = DatumGetUInt32(ExecEvalExprSwitchContext(node->hash_expr, + econtext, + &isnull)); + + if (!isnull) ExecParallelHashTableInsert(hashtable, slot, hashvalue); hashtable->partialTuples++; } @@ -371,8 +382,8 @@ ExecInitHash(Hash *node, EState *estate, int eflags) hashstate->ps.plan = (Plan *) node; hashstate->ps.state = estate; hashstate->ps.ExecProcNode = ExecHash; + /* delay building hashtable until ExecHashTableCreate() in executor run */ hashstate->hashtable = NULL; - hashstate->hashkeys = NIL; /* will be set by parent HashJoin */ /* * Miscellaneous initialization @@ -393,12 +404,16 @@ ExecInitHash(Hash *node, EState *estate, int eflags) ExecInitResultTupleSlotTL(&hashstate->ps, &TTSOpsMinimalTuple); hashstate->ps.ps_ProjInfo = NULL; + Assert(node->plan.qual == NIL); + /* - * initialize child expressions + * Delay initialization of hash_expr until ExecInitHashJoin(). We cannot + * build the ExprState here as we don't yet know the join type we're going + * to be hashing values for and we need to know that before calling + * ExecBuildHash32Expr as the keep_nulls parameter depends on the join + * type. */ - Assert(node->plan.qual == NIL); - hashstate->hashkeys = - ExecInitExprList(node->hashkeys, (PlanState *) hashstate); + hashstate->hash_expr = NULL; return hashstate; } @@ -429,7 +444,7 @@ ExecEndHash(HashState *node) * ---------------------------------------------------------------- */ HashJoinTable -ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, bool keepNulls) +ExecHashTableCreate(HashState *state) { Hash *node; HashJoinTable hashtable; @@ -440,10 +455,6 @@ ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, double rows; int num_skew_mcvs; int log2_nbuckets; - int nkeys; - int i; - ListCell *ho; - ListCell *hc; MemoryContext oldcxt; /* @@ -487,7 +498,6 @@ ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, hashtable->log2_nbuckets = log2_nbuckets; hashtable->log2_nbuckets_optimal = log2_nbuckets; hashtable->buckets.unshared = NULL; - hashtable->keepNulls = keepNulls; hashtable->skewEnabled = false; hashtable->skewBucket = NULL; hashtable->skewBucketLen = 0; @@ -540,32 +550,6 @@ ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, oldcxt = MemoryContextSwitchTo(hashtable->hashCxt); - /* - * Get info about the hash functions to be used for each hash key. Also - * remember whether the join operators are strict. - */ - nkeys = list_length(hashOperators); - hashtable->outer_hashfunctions = palloc_array(FmgrInfo, nkeys); - hashtable->inner_hashfunctions = palloc_array(FmgrInfo, nkeys); - hashtable->hashStrict = palloc_array(bool, nkeys); - hashtable->collations = palloc_array(Oid, nkeys); - i = 0; - forboth(ho, hashOperators, hc, hashCollations) - { - Oid hashop = lfirst_oid(ho); - Oid left_hashfn; - Oid right_hashfn; - - if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn)) - elog(ERROR, "could not find hash function for hash operator %u", - hashop); - fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]); - fmgr_info(right_hashfn, &hashtable->inner_hashfunctions[i]); - hashtable->hashStrict[i] = op_strict(hashop); - hashtable->collations[i] = lfirst_oid(hc); - i++; - } - if (nbatch > 1 && hashtable->parallel_state == NULL) { MemoryContext oldctx; @@ -652,7 +636,7 @@ ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, * it.) */ if (nbatch > 1) - ExecHashBuildSkewHash(hashtable, node, num_skew_mcvs); + ExecHashBuildSkewHash(state, hashtable, node, num_skew_mcvs); MemoryContextSwitchTo(oldcxt); } @@ -1803,103 +1787,6 @@ ExecParallelHashTableInsertCurrentBatch(HashJoinTable hashtable, heap_free_minimal_tuple(tuple); } -/* - * ExecHashGetHashValue - * Compute the hash value for a tuple - * - * The tuple to be tested must be in econtext->ecxt_outertuple (thus Vars in - * the hashkeys expressions need to have OUTER_VAR as varno). If outer_tuple - * is false (meaning it's the HashJoin's inner node, Hash), econtext, - * hashkeys, and slot need to be from Hash, with hashkeys/slot referencing and - * being suitable for tuples from the node below the Hash. Conversely, if - * outer_tuple is true, econtext is from HashJoin, and hashkeys/slot need to - * be appropriate for tuples from HashJoin's outer node. - * - * A true result means the tuple's hash value has been successfully computed - * and stored at *hashvalue. A false result means the tuple cannot match - * because it contains a null attribute, and hence it should be discarded - * immediately. (If keep_nulls is true then false is never returned.) - */ -bool -ExecHashGetHashValue(HashJoinTable hashtable, - ExprContext *econtext, - List *hashkeys, - bool outer_tuple, - bool keep_nulls, - uint32 *hashvalue) -{ - uint32 hashkey = 0; - FmgrInfo *hashfunctions; - ListCell *hk; - int i = 0; - MemoryContext oldContext; - - /* - * We reset the eval context each time to reclaim any memory leaked in the - * hashkey expressions. - */ - ResetExprContext(econtext); - - oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); - - if (outer_tuple) - hashfunctions = hashtable->outer_hashfunctions; - else - hashfunctions = hashtable->inner_hashfunctions; - - foreach(hk, hashkeys) - { - ExprState *keyexpr = (ExprState *) lfirst(hk); - Datum keyval; - bool isNull; - - /* combine successive hashkeys by rotating */ - hashkey = pg_rotate_left32(hashkey, 1); - - /* - * Get the join attribute value of the tuple - */ - keyval = ExecEvalExpr(keyexpr, econtext, &isNull); - - /* - * If the attribute is NULL, and the join operator is strict, then - * this tuple cannot pass the join qual so we can reject it - * immediately (unless we're scanning the outside of an outer join, in - * which case we must not reject it). Otherwise we act like the - * hashcode of NULL is zero (this will support operators that act like - * IS NOT DISTINCT, though not any more-random behavior). We treat - * the hash support function as strict even if the operator is not. - * - * Note: currently, all hashjoinable operators must be strict since - * the hash index AM assumes that. However, it takes so little extra - * code here to allow non-strict that we may as well do it. - */ - if (isNull) - { - if (hashtable->hashStrict[i] && !keep_nulls) - { - MemoryContextSwitchTo(oldContext); - return false; /* cannot match */ - } - /* else, leave hashkey unmodified, equivalent to hashcode 0 */ - } - else - { - /* Compute the hash function */ - uint32 hkey; - - hkey = DatumGetUInt32(FunctionCall1Coll(&hashfunctions[i], hashtable->collations[i], keyval)); - hashkey ^= hkey; - } - - i++; - } - - MemoryContextSwitchTo(oldContext); - - *hashvalue = hashkey; - return true; -} /* * ExecHashGetBucketAndBatch @@ -2372,7 +2259,8 @@ ExecReScanHash(HashState *node) * based on available memory. */ static void -ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse) +ExecHashBuildSkewHash(HashState *hashstate, HashJoinTable hashtable, + Hash *node, int mcvsToUse) { HeapTupleData *statsTuple; AttStatsSlot sslot; @@ -2400,7 +2288,6 @@ ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse) { double frac; int nbuckets; - FmgrInfo *hashfunctions; int i; if (mcvsToUse > sslot.nvalues) @@ -2468,15 +2355,14 @@ ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse) * ExecHashRemoveNextSkewBucket) and we want the least common MCVs to * be removed first. */ - hashfunctions = hashtable->outer_hashfunctions; for (i = 0; i < mcvsToUse; i++) { uint32 hashvalue; int bucket; - hashvalue = DatumGetUInt32(FunctionCall1Coll(&hashfunctions[0], - hashtable->collations[0], + hashvalue = DatumGetUInt32(FunctionCall1Coll(hashstate->skew_hashfunction, + hashstate->skew_collation, sslot.values[i])); /* |