diff options
author | Andres Freund <andres@anarazel.de> | 2018-02-15 21:55:31 -0800 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2018-02-15 21:55:31 -0800 |
commit | 773aec7aa98abd38d6d9435913bb8e14e392c274 (patch) | |
tree | 149ffe4c29433a85e84e128eb47aa22f3b388853 /src/backend/executor/execGrouping.c | |
parent | 51db0d18fbf58b0c2e5ebc2b5b2c48daf45c8d93 (diff) | |
download | postgresql-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.c | 236 |
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); } |