v1-0002-Factor-out-common-ScalarArrayOp-array-reduction-l.patch
application/octet-stream
Filename: v1-0002-Factor-out-common-ScalarArrayOp-array-reduction-l.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0002
Subject: Factor out common ScalarArrayOp array reduction logic
| File | + | − |
|---|---|---|
| src/backend/executor/execExprInterp.c | 65 | 83 |
From a617677bbd71acf3413d59220b1180f175cafdaa Mon Sep 17 00:00:00 2001
From: Chengpeng Yan <chengpeng_yan@outlook.com>
Date: Mon, 13 Apr 2026 12:31:05 +0800
Subject: [PATCH v1 2/2] Factor out common ScalarArrayOp array reduction logic
ExecEvalScalarArrayOp() and the NULL-lhs fallback in
ExecEvalHashedScalarArrayOp() both need the same array-element scan and
boolean reduction logic. Move that logic into a shared helper so the
semantics live in one place.
No functional change intended.
---
src/backend/executor/execExprInterp.c | 148 +++++++++++---------------
1 file changed, 65 insertions(+), 83 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 5437a8cd4b7..8f3d72d19e4 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -154,6 +154,12 @@ static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
bool *changed);
static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
ExprContext *econtext, bool checkisnull);
+static void ExecEvalArrayCompareReduce(FunctionCallInfo fcinfo,
+ ArrayType *arr, int16 typlen,
+ bool typbyval, char typalign,
+ bool useOr,
+ bool invert_nonnull_result,
+ Datum *result, bool *resultnull);
/* fast-path evaluation functions */
static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
@@ -4031,13 +4037,6 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
int nitems;
Datum result;
bool resultnull;
- int16 typlen;
- bool typbyval;
- char typalign;
- uint8 typalignby;
- char *s;
- uint8 *bitmap;
- int bitmask;
/*
* If the array is NULL then we return NULL --- it's not very meaningful
@@ -4086,14 +4085,49 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
}
- typlen = op->d.scalararrayop.typlen;
- typbyval = op->d.scalararrayop.typbyval;
- typalign = op->d.scalararrayop.typalign;
- typalignby = typalign_to_alignby(typalign);
+ ExecEvalArrayCompareReduce(fcinfo,
+ arr,
+ op->d.scalararrayop.typlen,
+ op->d.scalararrayop.typbyval,
+ op->d.scalararrayop.typalign,
+ useOr,
+ false,
+ &result,
+ &resultnull);
+
+ *op->resvalue = result;
+ *op->resnull = resultnull;
+}
+
+/*
+ * Shared helper for ExecEvalScalarArrayOp() and the hashed NULL-lhs fallback.
+ * Callers must handle the scalar-NULL strict fast path before invoking this.
+ *
+ * The linear path passes the expression's comparison function and uses useOr
+ * to select OR or AND reduction. The hashed NULL-lhs fallback instead passes
+ * the equality function used by hash probes, so NOT IN inverts non-NULL
+ * results after reduction.
+ */
+static void
+ExecEvalArrayCompareReduce(FunctionCallInfo fcinfo,
+ ArrayType *arr, int16 typlen,
+ bool typbyval, char typalign,
+ bool useOr,
+ bool invert_nonnull_result,
+ Datum *result, bool *resultnull)
+{
+ uint8 typalignby = typalign_to_alignby(typalign);
+ int nitems;
+ char *s;
+ uint8 *bitmap;
+ int bitmask;
+ bool strictfunc = fcinfo->flinfo->fn_strict;
+
+ nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
/* Initialize result appropriately depending on useOr */
- result = BoolGetDatum(!useOr);
- resultnull = false;
+ *result = BoolGetDatum(!useOr);
+ *resultnull = false;
/* Loop over the array elements */
s = (char *) ARR_DATA_PTR(arr);
@@ -4129,18 +4163,18 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
else
{
fcinfo->isnull = false;
- thisresult = op->d.scalararrayop.fn_addr(fcinfo);
+ thisresult = fcinfo->flinfo->fn_addr(fcinfo);
}
/* Combine results per OR or AND semantics */
if (fcinfo->isnull)
- resultnull = true;
+ *resultnull = true;
else if (useOr)
{
if (DatumGetBool(thisresult))
{
- result = BoolGetDatum(true);
- resultnull = false;
+ *result = BoolGetDatum(true);
+ *resultnull = false;
break; /* needn't look at any more elements */
}
}
@@ -4148,8 +4182,8 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
{
if (!DatumGetBool(thisresult))
{
- result = BoolGetDatum(false);
- resultnull = false;
+ *result = BoolGetDatum(false);
+ *resultnull = false;
break; /* needn't look at any more elements */
}
}
@@ -4166,8 +4200,9 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
}
}
- *op->resvalue = result;
- *op->resnull = resultnull;
+ /* Apply the caller-requested NOT IN inversion, preserving NULL. */
+ if (invert_nonnull_result && !*resultnull)
+ *result = BoolGetDatum(!DatumGetBool(*result));
}
/*
@@ -4254,11 +4289,6 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
int16 typlen;
bool typbyval;
char typalign;
- uint8 typalignby;
- int nitems;
- char *s;
- uint8 *bitmap;
- int bitmask;
if (strictfunc)
{
@@ -4272,67 +4302,19 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
&typlen,
&typbyval,
&typalign);
- typalignby = typalign_to_alignby(typalign);
-
- nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
-
- /* Compute IN as an OR reduction of equality results. */
- result = BoolGetDatum(false);
- resultnull = false;
fcinfo->args[0].value = (Datum) 0;
fcinfo->args[0].isnull = true;
- s = (char *) ARR_DATA_PTR(arr);
- bitmap = ARR_NULLBITMAP(arr);
- bitmask = 1;
- for (int i = 0; i < nitems; i++)
- {
- Datum elt;
- Datum thisresult;
-
- /* Get array element, checking for NULL. */
- if (bitmap && (*bitmap & bitmask) == 0)
- {
- fcinfo->args[1].value = (Datum) 0;
- fcinfo->args[1].isnull = true;
- }
- else
- {
- elt = fetch_att(s, typbyval, typlen);
- s = att_addlength_pointer(s, typlen, s);
- s = (char *) att_nominal_alignby(s, typalignby);
- fcinfo->args[1].value = elt;
- fcinfo->args[1].isnull = false;
- }
-
- fcinfo->isnull = false;
- thisresult = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
-
- if (fcinfo->isnull)
- resultnull = true;
- else if (DatumGetBool(thisresult))
- {
- result = BoolGetDatum(true);
- resultnull = false;
- break;
- }
-
- /* Advance bitmap pointer if any. */
- if (bitmap)
- {
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- bitmap++;
- bitmask = 1;
- }
- }
- }
-
- /* Reverse for NOT IN; NULL stays NULL. */
- if (!inclause && !resultnull)
- result = BoolGetDatum(!DatumGetBool(result));
+ ExecEvalArrayCompareReduce(fcinfo,
+ arr,
+ typlen,
+ typbyval,
+ typalign,
+ true,
+ !inclause,
+ &result,
+ &resultnull);
*op->resvalue = result;
*op->resnull = resultnull;
--
2.50.1 (Apple Git-155)