diff options
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r-- | src/backend/executor/execExpr.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 91aa386fa61..8c5ead93d68 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -79,7 +79,8 @@ static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, - int transno, int setno, int setoff, bool ishash); + int transno, int setno, int setoff, bool ishash, + bool nullcheck); /* @@ -2924,10 +2925,13 @@ ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, * check for filters, evaluate aggregate input, check that that input is not * NULL for a strict transition function, and then finally invoke the * transition for each of the concurrently computed grouping sets. + * + * If nullcheck is true, the generated code will check for a NULL pointer to + * the array of AggStatePerGroup, and skip evaluation if so. */ ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, - bool doSort, bool doHash) + bool doSort, bool doHash, bool nullcheck) { ExprState *state = makeNode(ExprState); PlanState *parent = &aggstate->ss.ps; @@ -3158,7 +3162,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, for (int setno = 0; setno < processGroupingSets; setno++) { ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, - pertrans, transno, setno, setoff, false); + pertrans, transno, setno, setoff, false, + nullcheck); setoff++; } } @@ -3177,7 +3182,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, for (int setno = 0; setno < numHashes; setno++) { ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, - pertrans, transno, setno, setoff, true); + pertrans, transno, setno, setoff, true, + nullcheck); setoff++; } } @@ -3227,15 +3233,28 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, - int transno, int setno, int setoff, bool ishash) + int transno, int setno, int setoff, bool ishash, + bool nullcheck) { ExprContext *aggcontext; + int adjust_jumpnull = -1; if (ishash) aggcontext = aggstate->hashcontext; else aggcontext = aggstate->aggcontexts[setno]; + /* add check for NULL pointer? */ + if (nullcheck) + { + scratch->opcode = EEOP_AGG_PLAIN_PERGROUP_NULLCHECK; + scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff; + /* adjust later */ + scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1; + ExprEvalPushStep(state, scratch); + adjust_jumpnull = state->steps_len - 1; + } + /* * Determine appropriate transition implementation. * @@ -3303,6 +3322,16 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate, scratch->d.agg_trans.transno = transno; scratch->d.agg_trans.aggcontext = aggcontext; ExprEvalPushStep(state, scratch); + + /* fix up jumpnull */ + if (adjust_jumpnull != -1) + { + ExprEvalStep *as = &state->steps[adjust_jumpnull]; + + Assert(as->opcode == EEOP_AGG_PLAIN_PERGROUP_NULLCHECK); + Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1); + as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len; + } } /* |