aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeHash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeHash.c')
-rw-r--r--src/backend/executor/nodeHash.c190
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]));
/*