diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2025-01-30 13:21:42 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2025-01-30 13:21:42 -0500 |
commit | 115a365519bfd53a65bf17d253b26902eff0c337 (patch) | |
tree | 809dcf8dcfd0ec0b82fce588557af80073005b02 /src/backend/executor | |
parent | 6252b1eaf82bb8db361341d1c8651e43b29be816 (diff) | |
download | postgresql-115a365519bfd53a65bf17d253b26902eff0c337.tar.gz postgresql-115a365519bfd53a65bf17d253b26902eff0c337.zip |
Simplify executor's handling of CaseTestExpr & CoerceToDomainValue.
Instead of deciding at runtime whether to read from casetest.value
or caseValue_datum, split EEOP_CASE_TESTVAL into two opcodes and
make the decision during expression compilation. Similarly for
EEOP_DOMAIN_TESTVAL. This actually results in net less code,
mainly because llvmjit_expr.c's code for handling these opcodes
gets shorter. The performance gain is doubtless negligible, but
this seems worth changing anyway on grounds of simplicity and
understandability.
Author: Andreas Karlsson <andreas@proxel.se>
Co-authored-by: Xing Guo <higuoxing@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CACpMh+AiBYAWn+D1aU7Rsy-V1tox06Cbc0H3qA7rwL5zdJ=anQ@mail.gmail.com
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execExpr.c | 34 | ||||
-rw-r--r-- | src/backend/executor/execExprInterp.c | 59 |
2 files changed, 45 insertions, 48 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 8f28da4bf94..03566c4d181 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -1901,13 +1901,17 @@ ExecInitExprRec(Expr *node, ExprState *state, * actually within a CaseExpr, ArrayCoerceExpr, etc structure. * That can happen because some parts of the system abuse * CaseTestExpr to cause a read of a value externally supplied - * in econtext->caseValue_datum. We'll take care of that - * scenario at runtime. + * in econtext->caseValue_datum. We'll take care of that by + * generating a specialized operation. */ - scratch.opcode = EEOP_CASE_TESTVAL; - scratch.d.casetest.value = state->innermost_caseval; - scratch.d.casetest.isnull = state->innermost_casenull; - + if (state->innermost_caseval == NULL) + scratch.opcode = EEOP_CASE_TESTVAL_EXT; + else + { + scratch.opcode = EEOP_CASE_TESTVAL; + scratch.d.casetest.value = state->innermost_caseval; + scratch.d.casetest.isnull = state->innermost_casenull; + } ExprEvalPushStep(state, &scratch); break; } @@ -2594,14 +2598,18 @@ ExecInitExprRec(Expr *node, ExprState *state, * that innermost_domainval could be NULL, if we're compiling * a standalone domain check rather than one embedded in a * larger expression. In that case we must read from - * econtext->domainValue_datum. We'll take care of that - * scenario at runtime. + * econtext->domainValue_datum. We'll take care of that by + * generating a specialized operation. */ - scratch.opcode = EEOP_DOMAIN_TESTVAL; - /* we share instruction union variant with case testval */ - scratch.d.casetest.value = state->innermost_domainval; - scratch.d.casetest.isnull = state->innermost_domainnull; - + if (state->innermost_domainval == NULL) + scratch.opcode = EEOP_DOMAIN_TESTVAL_EXT; + else + { + scratch.opcode = EEOP_DOMAIN_TESTVAL; + /* we share instruction union variant with case testval */ + scratch.d.casetest.value = state->innermost_domainval; + scratch.d.casetest.isnull = state->innermost_domainnull; + } ExprEvalPushStep(state, &scratch); break; } diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 1127e6f11eb..09f6a5f14c1 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -365,8 +365,7 @@ ExecReadyInterpretedExpr(ExprState *state) return; } else if (step0 == EEOP_CASE_TESTVAL && - step1 == EEOP_FUNCEXPR_STRICT && - state->steps[0].d.casetest.value) + step1 == EEOP_FUNCEXPR_STRICT) { state->evalfunc_private = ExecJustApplyFuncToCase; return; @@ -524,6 +523,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_PARAM_CALLBACK, &&CASE_EEOP_PARAM_SET, &&CASE_EEOP_CASE_TESTVAL, + &&CASE_EEOP_CASE_TESTVAL_EXT, &&CASE_EEOP_MAKE_READONLY, &&CASE_EEOP_IOCOERCE, &&CASE_EEOP_IOCOERCE_SAFE, @@ -548,6 +548,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_SBSREF_ASSIGN, &&CASE_EEOP_SBSREF_FETCH, &&CASE_EEOP_DOMAIN_TESTVAL, + &&CASE_EEOP_DOMAIN_TESTVAL_EXT, &&CASE_EEOP_DOMAIN_NOTNULL, &&CASE_EEOP_DOMAIN_CHECK, &&CASE_EEOP_HASHDATUM_SET_INITVAL, @@ -1273,44 +1274,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_CASE_TESTVAL) { - /* - * Normally upper parts of the expression tree have setup the - * values to be returned here, but some parts of the system - * currently misuse {caseValue,domainValue}_{datum,isNull} to set - * run-time data. So if no values have been set-up, use - * ExprContext's. This isn't pretty, but also not *that* ugly, - * and this is unlikely to be performance sensitive enough to - * worry about an extra branch. - */ - if (op->d.casetest.value) - { - *op->resvalue = *op->d.casetest.value; - *op->resnull = *op->d.casetest.isnull; - } - else - { - *op->resvalue = econtext->caseValue_datum; - *op->resnull = econtext->caseValue_isNull; - } + *op->resvalue = *op->d.casetest.value; + *op->resnull = *op->d.casetest.isnull; EEO_NEXT(); } - EEO_CASE(EEOP_DOMAIN_TESTVAL) + EEO_CASE(EEOP_CASE_TESTVAL_EXT) { - /* - * See EEOP_CASE_TESTVAL comment. - */ - if (op->d.casetest.value) - { - *op->resvalue = *op->d.casetest.value; - *op->resnull = *op->d.casetest.isnull; - } - else - { - *op->resvalue = econtext->domainValue_datum; - *op->resnull = econtext->domainValue_isNull; - } + *op->resvalue = econtext->caseValue_datum; + *op->resnull = econtext->caseValue_isNull; EEO_NEXT(); } @@ -1726,6 +1699,22 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_DOMAIN_TESTVAL) + { + *op->resvalue = *op->d.casetest.value; + *op->resnull = *op->d.casetest.isnull; + + EEO_NEXT(); + } + + EEO_CASE(EEOP_DOMAIN_TESTVAL_EXT) + { + *op->resvalue = econtext->domainValue_datum; + *op->resnull = econtext->domainValue_isNull; + + EEO_NEXT(); + } + EEO_CASE(EEOP_DOMAIN_NOTNULL) { /* too complex for an inline implementation */ |