aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execGrouping.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2018-02-15 21:55:31 -0800
committerAndres Freund <andres@anarazel.de>2018-02-15 21:55:31 -0800
commit773aec7aa98abd38d6d9435913bb8e14e392c274 (patch)
tree149ffe4c29433a85e84e128eb47aa22f3b388853 /src/backend/executor/execGrouping.c
parent51db0d18fbf58b0c2e5ebc2b5b2c48daf45c8d93 (diff)
downloadpostgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.tar.gz
postgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.zip
Do execGrouping.c via expression eval machinery.
This has a performance benefit on own, although not hugely so. The primary benefit is that it will allow for to JIT tuple deforming and comparator invocations. Author: Andres Freund Discussion: https://postgr.es/m/20171129080934.amqqkke2zjtekd4t@alap3.anarazel.de
Diffstat (limited to 'src/backend/executor/execGrouping.c')
-rw-r--r--src/backend/executor/execGrouping.c236
1 files changed, 49 insertions, 187 deletions
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 8e8dbb1f205..4f604fb2861 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -52,172 +52,33 @@ static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tup
*****************************************************************************/
/*
- * execTuplesMatch
- * Return true if two tuples match in all the indicated fields.
- *
- * This actually implements SQL's notion of "not distinct". Two nulls
- * match, a null and a not-null don't match.
- *
- * slot1, slot2: the tuples to compare (must have same columns!)
- * numCols: the number of attributes to be examined
- * matchColIdx: array of attribute column numbers
- * eqFunctions: array of fmgr lookup info for the equality functions to use
- * evalContext: short-term memory context for executing the functions
- *
- * NB: evalContext is reset each time!
- */
-bool
-execTuplesMatch(TupleTableSlot *slot1,
- TupleTableSlot *slot2,
- int numCols,
- AttrNumber *matchColIdx,
- FmgrInfo *eqfunctions,
- MemoryContext evalContext)
-{
- MemoryContext oldContext;
- bool result;
- int i;
-
- /* Reset and switch into the temp context. */
- MemoryContextReset(evalContext);
- oldContext = MemoryContextSwitchTo(evalContext);
-
- /*
- * We cannot report a match without checking all the fields, but we can
- * report a non-match as soon as we find unequal fields. So, start
- * comparing at the last field (least significant sort key). That's the
- * most likely to be different if we are dealing with sorted input.
- */
- result = true;
-
- for (i = numCols; --i >= 0;)
- {
- AttrNumber att = matchColIdx[i];
- Datum attr1,
- attr2;
- bool isNull1,
- isNull2;
-
- attr1 = slot_getattr(slot1, att, &isNull1);
-
- attr2 = slot_getattr(slot2, att, &isNull2);
-
- if (isNull1 != isNull2)
- {
- result = false; /* one null and one not; they aren't equal */
- break;
- }
-
- if (isNull1)
- continue; /* both are null, treat as equal */
-
- /* Apply the type-specific equality function */
-
- if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
- attr1, attr2)))
- {
- result = false; /* they aren't equal */
- break;
- }
- }
-
- MemoryContextSwitchTo(oldContext);
-
- return result;
-}
-
-/*
- * execTuplesUnequal
- * Return true if two tuples are definitely unequal in the indicated
- * fields.
- *
- * Nulls are neither equal nor unequal to anything else. A true result
- * is obtained only if there are non-null fields that compare not-equal.
- *
- * Parameters are identical to execTuplesMatch.
- */
-bool
-execTuplesUnequal(TupleTableSlot *slot1,
- TupleTableSlot *slot2,
- int numCols,
- AttrNumber *matchColIdx,
- FmgrInfo *eqfunctions,
- MemoryContext evalContext)
-{
- MemoryContext oldContext;
- bool result;
- int i;
-
- /* Reset and switch into the temp context. */
- MemoryContextReset(evalContext);
- oldContext = MemoryContextSwitchTo(evalContext);
-
- /*
- * We cannot report a match without checking all the fields, but we can
- * report a non-match as soon as we find unequal fields. So, start
- * comparing at the last field (least significant sort key). That's the
- * most likely to be different if we are dealing with sorted input.
- */
- result = false;
-
- for (i = numCols; --i >= 0;)
- {
- AttrNumber att = matchColIdx[i];
- Datum attr1,
- attr2;
- bool isNull1,
- isNull2;
-
- attr1 = slot_getattr(slot1, att, &isNull1);
-
- if (isNull1)
- continue; /* can't prove anything here */
-
- attr2 = slot_getattr(slot2, att, &isNull2);
-
- if (isNull2)
- continue; /* can't prove anything here */
-
- /* Apply the type-specific equality function */
-
- if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
- attr1, attr2)))
- {
- result = true; /* they are unequal */
- break;
- }
- }
-
- MemoryContextSwitchTo(oldContext);
-
- return result;
-}
-
-
-/*
* execTuplesMatchPrepare
- * Look up the equality functions needed for execTuplesMatch or
- * execTuplesUnequal, given an array of equality operator OIDs.
- *
- * The result is a palloc'd array.
+ * Build expression that can be evaluated using ExecQual(), returning
+ * whether an ExprContext's inner/outer tuples are NOT DISTINCT
*/
-FmgrInfo *
-execTuplesMatchPrepare(int numCols,
- Oid *eqOperators)
+ExprState *
+execTuplesMatchPrepare(TupleDesc desc,
+ int numCols,
+ AttrNumber *keyColIdx,
+ Oid *eqOperators,
+ PlanState *parent)
{
- FmgrInfo *eqFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
+ Oid *eqFunctions = (Oid *) palloc(numCols * sizeof(Oid));
int i;
+ ExprState *expr;
+
+ if (numCols == 0)
+ return NULL;
+ /* lookup equality functions */
for (i = 0; i < numCols; i++)
- {
- Oid eq_opr = eqOperators[i];
- Oid eq_function;
+ eqFunctions[i] = get_opcode(eqOperators[i]);
- eq_function = get_opcode(eq_opr);
- fmgr_info(eq_function, &eqFunctions[i]);
- }
+ /* build actual expression */
+ expr = ExecBuildGroupingEqual(desc, numCols, keyColIdx, eqFunctions,
+ parent);
- return eqFunctions;
+ return expr;
}
/*
@@ -288,7 +149,9 @@ execTuplesHashPrepare(int numCols,
* storage that will live as long as the hashtable does.
*/
TupleHashTable
-BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
+BuildTupleHashTable(PlanState *parent,
+ TupleDesc inputDesc,
+ int numCols, AttrNumber *keyColIdx,
FmgrInfo *eqfunctions,
FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize,
@@ -297,6 +160,9 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
{
TupleHashTable hashtable;
Size entrysize = sizeof(TupleHashEntryData) + additionalsize;
+ MemoryContext oldcontext;
+ Oid *eqoids = (Oid *) palloc(numCols * sizeof(Oid));
+ int i;
Assert(nbuckets > 0);
@@ -333,6 +199,26 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
hashtable->hashtab = tuplehash_create(tablecxt, nbuckets, hashtable);
+ oldcontext = MemoryContextSwitchTo(hashtable->tablecxt);
+
+ /*
+ * We copy the input tuple descriptor just for safety --- we assume all
+ * input tuples will have equivalent descriptors.
+ */
+ hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc));
+
+ /* build comparator for all columns */
+ for (i = 0; i < numCols; i++)
+ eqoids[i] = eqfunctions[i].fn_oid;
+ hashtable->eq_func = ExecBuildGroupingEqual(inputDesc,
+ numCols,
+ keyColIdx, eqoids,
+ parent);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ hashtable->exprcontext = CreateExprContext(parent->state);
+
return hashtable;
}
@@ -357,22 +243,6 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
bool found;
MinimalTuple key;
- /* If first time through, clone the input slot to make table slot */
- if (hashtable->tableslot == NULL)
- {
- TupleDesc tupdesc;
-
- oldContext = MemoryContextSwitchTo(hashtable->tablecxt);
-
- /*
- * We copy the input tuple descriptor just for safety --- we assume
- * all input tuples will have equivalent descriptors.
- */
- tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
- hashtable->tableslot = MakeSingleTupleTableSlot(tupdesc);
- MemoryContextSwitchTo(oldContext);
- }
-
/* Need to run the hash functions in short-lived context */
oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
@@ -524,9 +394,6 @@ TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple)
* See whether two tuples (presumably of the same hash value) match
*
* As above, the passed pointers are pointers to TupleHashEntryData.
- *
- * Also, the caller must select an appropriate memory context for running
- * the compare functions. (dynahash.c doesn't change CurrentMemoryContext.)
*/
static int
TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2)
@@ -534,6 +401,7 @@ TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const
TupleTableSlot *slot1;
TupleTableSlot *slot2;
TupleHashTable hashtable = (TupleHashTable) tb->private_data;
+ ExprContext *econtext = hashtable->exprcontext;
/*
* We assume that simplehash.h will only ever call us with the first
@@ -548,13 +416,7 @@ TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const
slot2 = hashtable->inputslot;
/* For crosstype comparisons, the inputslot must be first */
- if (execTuplesMatch(slot2,
- slot1,
- hashtable->numCols,
- hashtable->keyColIdx,
- hashtable->cur_eq_funcs,
- hashtable->tempcxt))
- return 0;
- else
- return 1;
+ econtext->ecxt_innertuple = slot1;
+ econtext->ecxt_outertuple = slot2;
+ return !ExecQualAndReset(hashtable->eq_func, econtext);
}