aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-01-30 13:21:42 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2025-01-30 13:21:42 -0500
commit115a365519bfd53a65bf17d253b26902eff0c337 (patch)
tree809dcf8dcfd0ec0b82fce588557af80073005b02 /src/backend/executor
parent6252b1eaf82bb8db361341d1c8651e43b29be816 (diff)
downloadpostgresql-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.c34
-rw-r--r--src/backend/executor/execExprInterp.c59
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 */