summaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execGrouping.c123
-rw-r--r--src/backend/executor/nodeAgg.c23
-rw-r--r--src/backend/executor/nodeHash.c35
-rw-r--r--src/backend/executor/nodeHashjoin.c19
-rw-r--r--src/backend/executor/nodeSubplan.c16
5 files changed, 116 insertions, 100 deletions
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 0d4d5ed20f..b41c75e926 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.2 2003/01/12 04:03:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.3 2003/06/22 22:04:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,6 +19,8 @@
#include "executor/executor.h"
#include "parser/parse_oper.h"
#include "utils/memutils.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
/*****************************************************************************
@@ -213,76 +215,46 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
return eqfunctions;
}
-
-/*****************************************************************************
- * Utility routines for hashing
- *****************************************************************************/
-
/*
- * ComputeHashFunc
+ * execTuplesHashPrepare
+ * Look up the equality and hashing functions needed for a TupleHashTable.
*
- * the hash function for hash joins (also used for hash aggregation)
- *
- * XXX this probably ought to be replaced with datatype-specific
- * hash functions, such as those already implemented for hash indexes.
+ * This is similar to execTuplesMatchPrepare, but we also need to find the
+ * hash functions associated with the equality operators. *eqfunctions and
+ * *hashfunctions receive the palloc'd result arrays.
*/
-uint32
-ComputeHashFunc(Datum key, int typLen, bool byVal)
+void
+execTuplesHashPrepare(TupleDesc tupdesc,
+ int numCols,
+ AttrNumber *matchColIdx,
+ FmgrInfo **eqfunctions,
+ FmgrInfo **hashfunctions)
{
- unsigned char *k;
+ int i;
- if (byVal)
- {
- /*
- * If it's a by-value data type, just hash the whole Datum value.
- * This assumes that datatypes narrower than Datum are
- * consistently padded (either zero-extended or sign-extended, but
- * not random bits) to fill Datum; see the XXXGetDatum macros in
- * postgres.h. NOTE: it would not work to do hash_any(&key, len)
- * since this would get the wrong bytes on a big-endian machine.
- */
- k = (unsigned char *) &key;
- typLen = sizeof(Datum);
- }
- else
+ *eqfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
+ *hashfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
+
+ for (i = 0; i < numCols; i++)
{
- if (typLen > 0)
- {
- /* fixed-width pass-by-reference type */
- k = (unsigned char *) DatumGetPointer(key);
- }
- else if (typLen == -1)
- {
- /*
- * It's a varlena type, so 'key' points to a "struct varlena".
- * NOTE: VARSIZE returns the "real" data length plus the
- * sizeof the "vl_len" attribute of varlena (the length
- * information). 'key' points to the beginning of the varlena
- * struct, so we have to use "VARDATA" to find the beginning
- * of the "real" data. Also, we have to be careful to detoast
- * the datum if it's toasted. (We don't worry about freeing
- * the detoasted copy; that happens for free when the
- * per-tuple memory context is reset in ExecHashGetBucket.)
- */
- struct varlena *vkey = PG_DETOAST_DATUM(key);
-
- typLen = VARSIZE(vkey) - VARHDRSZ;
- k = (unsigned char *) VARDATA(vkey);
- }
- else if (typLen == -2)
- {
- /* It's a null-terminated C string */
- typLen = strlen(DatumGetCString(key)) + 1;
- k = (unsigned char *) DatumGetPointer(key);
- }
- else
- {
- elog(ERROR, "ComputeHashFunc: Invalid typLen %d", typLen);
- k = NULL; /* keep compiler quiet */
- }
+ AttrNumber att = matchColIdx[i];
+ Oid typid = tupdesc->attrs[att - 1]->atttypid;
+ Operator optup;
+ Oid eq_opr;
+ Oid eq_function;
+ Oid hash_function;
+
+ optup = equality_oper(typid, false);
+ eq_opr = oprid(optup);
+ eq_function = oprfuncid(optup);
+ ReleaseSysCache(optup);
+ hash_function = get_op_hash_function(eq_opr);
+ if (!OidIsValid(hash_function))
+ elog(ERROR, "Could not find hash function for hash operator %u",
+ eq_opr);
+ fmgr_info(eq_function, &(*eqfunctions)[i]);
+ fmgr_info(hash_function, &(*hashfunctions)[i]);
}
-
- return DatumGetUInt32(hash_any(k, typLen));
}
@@ -299,19 +271,21 @@ ComputeHashFunc(Datum key, int typLen, bool byVal)
*
* numCols, keyColIdx: identify the tuple fields to use as lookup key
* eqfunctions: equality comparison functions to use
+ * hashfunctions: datatype-specific hashing functions to use
* nbuckets: number of buckets to make
* entrysize: size of each entry (at least sizeof(TupleHashEntryData))
* tablecxt: memory context in which to store table and table entries
* tempcxt: short-lived context for evaluation hash and comparison functions
*
- * The eqfunctions array may be made with execTuplesMatchPrepare().
+ * The function arrays may be made with execTuplesHashPrepare().
*
- * Note that keyColIdx and eqfunctions must be allocated in storage that
- * will live as long as the hashtable does.
+ * Note that keyColIdx, eqfunctions, and hashfunctions must be allocated in
+ * storage that will live as long as the hashtable does.
*/
TupleHashTable
BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
FmgrInfo *eqfunctions,
+ FmgrInfo *hashfunctions,
int nbuckets, Size entrysize,
MemoryContext tablecxt, MemoryContext tempcxt)
{
@@ -328,6 +302,7 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
hashtable->numCols = numCols;
hashtable->keyColIdx = keyColIdx;
hashtable->eqfunctions = eqfunctions;
+ hashtable->hashfunctions = hashfunctions;
hashtable->tablecxt = tablecxt;
hashtable->tempcxt = tempcxt;
hashtable->entrysize = entrysize;
@@ -375,11 +350,15 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
attr = heap_getattr(tuple, att, tupdesc, &isNull);
- if (isNull)
- continue; /* treat nulls as having hash key 0 */
- hashkey ^= ComputeHashFunc(attr,
- (int) tupdesc->attrs[att - 1]->attlen,
- tupdesc->attrs[att - 1]->attbyval);
+
+ if (!isNull) /* treat nulls as having hash key 0 */
+ {
+ uint32 hkey;
+
+ hkey = DatumGetUInt32(FunctionCall1(&hashtable->hashfunctions[i],
+ attr));
+ hashkey ^= hkey;
+ }
}
bucketno = hashkey % (uint32) hashtable->nbuckets;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index f2499cb4e5..d0dd6b31c9 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.106 2003/06/06 15:04:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.107 2003/06/22 22:04:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -582,6 +582,7 @@ build_hash_table(AggState *aggstate)
aggstate->hashtable = BuildTupleHashTable(node->numCols,
node->grpColIdx,
aggstate->eqfunctions,
+ aggstate->hashfunctions,
node->numGroups,
entrysize,
aggstate->aggcontext,
@@ -1035,6 +1036,7 @@ ExecInitAgg(Agg *node, EState *estate)
aggstate->aggs = NIL;
aggstate->numaggs = 0;
aggstate->eqfunctions = NULL;
+ aggstate->hashfunctions = NULL;
aggstate->peragg = NULL;
aggstate->agg_done = false;
aggstate->pergroup = NULL;
@@ -1123,14 +1125,23 @@ ExecInitAgg(Agg *node, EState *estate)
}
/*
- * If we are grouping, precompute fmgr lookup data for inner loop
+ * If we are grouping, precompute fmgr lookup data for inner loop.
+ * We need both equality and hashing functions to do it by hashing,
+ * but only equality if not hashing.
*/
if (node->numCols > 0)
{
- aggstate->eqfunctions =
- execTuplesMatchPrepare(ExecGetScanType(&aggstate->ss),
- node->numCols,
- node->grpColIdx);
+ if (node->aggstrategy == AGG_HASHED)
+ execTuplesHashPrepare(ExecGetScanType(&aggstate->ss),
+ node->numCols,
+ node->grpColIdx,
+ &aggstate->eqfunctions,
+ &aggstate->hashfunctions);
+ else
+ aggstate->eqfunctions =
+ execTuplesMatchPrepare(ExecGetScanType(&aggstate->ss),
+ node->numCols,
+ node->grpColIdx);
}
/*
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index b338c8961e..f00cc28684 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.75 2003/03/27 16:51:27 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.76 2003/06/22 22:04:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -192,7 +192,7 @@ ExecEndHash(HashState *node)
* ----------------------------------------------------------------
*/
HashJoinTable
-ExecHashTableCreate(Hash *node)
+ExecHashTableCreate(Hash *node, List *hashOperators)
{
HashJoinTable hashtable;
Plan *outerNode;
@@ -201,7 +201,7 @@ ExecHashTableCreate(Hash *node)
int nbatch;
int nkeys;
int i;
- List *hk;
+ List *ho;
MemoryContext oldcxt;
/*
@@ -237,17 +237,20 @@ ExecHashTableCreate(Hash *node)
hashtable->outerBatchSize = NULL;
/*
- * Get info about the datatypes of the hash keys.
+ * Get info about the hash functions to be used for each hash key.
*/
- nkeys = length(node->hashkeys);
- hashtable->typLens = (int16 *) palloc(nkeys * sizeof(int16));
- hashtable->typByVals = (bool *) palloc(nkeys * sizeof(bool));
+ nkeys = length(hashOperators);
+ hashtable->hashfunctions = (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
i = 0;
- foreach(hk, node->hashkeys)
+ foreach(ho, hashOperators)
{
- get_typlenbyval(exprType(lfirst(hk)),
- &hashtable->typLens[i],
- &hashtable->typByVals[i]);
+ Oid hashfn;
+
+ hashfn = get_op_hash_function(lfirsto(ho));
+ if (!OidIsValid(hashfn))
+ elog(ERROR, "Could not find hash function for hash operator %u",
+ lfirsto(ho));
+ fmgr_info(hashfn, &hashtable->hashfunctions[i]);
i++;
}
@@ -520,7 +523,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
/*
* We reset the eval context each time to reclaim any memory leaked in
- * the hashkey expressions or ComputeHashFunc itself.
+ * the hashkey expressions.
*/
ResetExprContext(econtext);
@@ -545,9 +548,11 @@ ExecHashGetBucket(HashJoinTable hashtable,
*/
if (!isNull) /* treat nulls as having hash key 0 */
{
- hashkey ^= ComputeHashFunc(keyval,
- (int) hashtable->typLens[i],
- hashtable->typByVals[i]);
+ uint32 hkey;
+
+ hkey = DatumGetUInt32(FunctionCall1(&hashtable->hashfunctions[i],
+ keyval));
+ hashkey ^= hkey;
}
i++;
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 17585b2f0f..9a0071f018 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.51 2003/05/30 20:23:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.52 2003/06/22 22:04:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -117,7 +117,8 @@ ExecHashJoin(HashJoinState *node)
* create the hash table
*/
Assert(hashtable == NULL);
- hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan);
+ hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan,
+ node->hj_HashOperators);
node->hj_HashTable = hashtable;
/*
@@ -305,6 +306,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate)
Plan *outerNode;
Hash *hashNode;
List *hclauses;
+ List *hoperators;
List *hcl;
/*
@@ -406,8 +408,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate)
/*
* The planner already made a list of the inner hashkeys for us,
- * but we also need a list of the outer hashkeys. Each list of
- * exprs must then be prepared for execution.
+ * but we also need a list of the outer hashkeys, as well as a list
+ * of the hash operator OIDs. Both lists of exprs must then be prepared
+ * for execution.
*/
hjstate->hj_InnerHashKeys = (List *)
ExecInitExpr((Expr *) hashNode->hashkeys,
@@ -416,13 +419,19 @@ ExecInitHashJoin(HashJoin *node, EState *estate)
hjstate->hj_InnerHashKeys;
hclauses = NIL;
+ hoperators = NIL;
foreach(hcl, node->hashclauses)
{
- hclauses = lappend(hclauses, get_leftop(lfirst(hcl)));
+ OpExpr *hclause = (OpExpr *) lfirst(hcl);
+
+ Assert(IsA(hclause, OpExpr));
+ hclauses = lappend(hclauses, get_leftop((Expr *) hclause));
+ hoperators = lappendo(hoperators, hclause->opno);
}
hjstate->hj_OuterHashKeys = (List *)
ExecInitExpr((Expr *) hclauses,
(PlanState *) hjstate);
+ hjstate->hj_HashOperators = hoperators;
hjstate->js.ps.ps_OuterTupleSlot = NULL;
hjstate->js.ps.ps_TupFromTlist = false;
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index ff5d03faf8..82502c985e 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.46 2003/06/06 15:04:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.47 2003/06/22 22:04:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -519,6 +519,7 @@ buildSubPlanHash(SubPlanState *node)
node->hashtable = BuildTupleHashTable(ncols,
node->keyColIdx,
node->eqfunctions,
+ node->hashfunctions,
nbuckets,
sizeof(TupleHashEntryData),
node->tablecxt,
@@ -537,6 +538,7 @@ buildSubPlanHash(SubPlanState *node)
node->hashnulls = BuildTupleHashTable(ncols,
node->keyColIdx,
node->eqfunctions,
+ node->hashfunctions,
nbuckets,
sizeof(TupleHashEntryData),
node->tablecxt,
@@ -700,6 +702,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
node->innerecontext = NULL;
node->keyColIdx = NULL;
node->eqfunctions = NULL;
+ node->hashfunctions = NULL;
/*
* create an EState for the subplan
@@ -797,11 +800,12 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
* ExecTypeFromTL).
*
* We also extract the combining operators themselves to initialize
- * the equality functions for the hash tables.
+ * the equality and hashing functions for the hash tables.
*/
lefttlist = righttlist = NIL;
leftptlist = rightptlist = NIL;
node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
+ node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
i = 1;
foreach(lexpr, node->exprs)
{
@@ -811,6 +815,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
Expr *expr;
TargetEntry *tle;
GenericExprState *tlestate;
+ Oid hashfn;
Assert(IsA(fstate, FuncExprState));
Assert(IsA(opexpr, OpExpr));
@@ -850,6 +855,13 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
fmgr_info(opexpr->opfuncid, &node->eqfunctions[i-1]);
node->eqfunctions[i-1].fn_expr = (Node *) opexpr;
+ /* Lookup the associated hash function */
+ hashfn = get_op_hash_function(opexpr->opno);
+ if (!OidIsValid(hashfn))
+ elog(ERROR, "Could not find hash function for hash operator %u",
+ opexpr->opno);
+ fmgr_info(hashfn, &node->hashfunctions[i-1]);
+
i++;
}