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:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user