1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-08 11:42:09 +03:00

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
This commit is contained in:
Andres Freund
2018-02-15 21:55:31 -08:00
parent 51db0d18fb
commit 773aec7aa9
15 changed files with 498 additions and 366 deletions

View File

@ -3193,3 +3193,121 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
as->d.agg_strict_trans_check.jumpnull = state->steps_len;
}
}
/*
* Build equality expression that can be evaluated using ExecQual(), returning
* true if the expression context's inner/outer tuple are NOT DISTINCT. I.e
* two nulls match, a null and a not-null don't match.
*
* desc: tuple descriptor of the to-be-compared tuples
* numCols: the number of attributes to be examined
* keyColIdx: array of attribute column numbers
* eqFunctions: array of function oids of the equality functions to use
* parent: parent executor node
*/
ExprState *
ExecBuildGroupingEqual(TupleDesc desc,
int numCols,
AttrNumber *keyColIdx,
Oid *eqfunctions,
PlanState *parent)
{
ExprState *state = makeNode(ExprState);
ExprEvalStep scratch = {0};
int natt;
int maxatt = -1;
List *adjust_jumps = NIL;
ListCell *lc;
/*
* When no columns are actually compared, the result's always true. See
* special case in ExecQual().
*/
if (numCols == 0)
return NULL;
state->expr = NULL;
state->flags = EEO_FLAG_IS_QUAL;
state->parent = parent;
scratch.resvalue = &state->resvalue;
scratch.resnull = &state->resnull;
/* compute max needed attribute */
for (natt = 0; natt < numCols; natt++)
{
int attno = keyColIdx[natt];
if (attno > maxatt)
maxatt = attno;
}
Assert(maxatt >= 0);
/* push deform steps */
scratch.opcode = EEOP_INNER_FETCHSOME;
scratch.d.fetch.last_var = maxatt;
ExprEvalPushStep(state, &scratch);
scratch.opcode = EEOP_OUTER_FETCHSOME;
scratch.d.fetch.last_var = maxatt;
ExprEvalPushStep(state, &scratch);
/*
* 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.
*/
for (natt = numCols; --natt >= 0;)
{
int attno = keyColIdx[natt];
Form_pg_attribute att = TupleDescAttr(desc, attno - 1);
Var *larg,
*rarg;
List *args;
/*
* Reusing ExecInitFunc() requires creating Vars, but still seems
* worth it from a code reuse perspective.
*/
/* left arg */
larg = makeVar(INNER_VAR, attno, att->atttypid,
att->atttypmod, InvalidOid, 0);
/* right arg */
rarg = makeVar(OUTER_VAR, attno, att->atttypid,
att->atttypmod, InvalidOid, 0);
args = list_make2(larg, rarg);
/* evaluate distinctness */
ExecInitFunc(&scratch, NULL,
args, eqfunctions[natt], InvalidOid,
state);
scratch.opcode = EEOP_NOT_DISTINCT;
ExprEvalPushStep(state, &scratch);
/* then emit EEOP_QUAL to detect if result is false (or null) */
scratch.opcode = EEOP_QUAL;
scratch.d.qualexpr.jumpdone = -1;
ExprEvalPushStep(state, &scratch);
adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1);
}
/* adjust jump targets */
foreach(lc, adjust_jumps)
{
ExprEvalStep *as = &state->steps[lfirst_int(lc)];
Assert(as->opcode == EEOP_QUAL);
Assert(as->d.qualexpr.jumpdone == -1);
as->d.qualexpr.jumpdone = state->steps_len;
}
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
return state;
}