v8-0003-SLOPE-prosupport-definitions.patch
application/octet-stream
Filename: v8-0003-SLOPE-prosupport-definitions.patch
Type: application/octet-stream
Part: 2
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 v8-0003
Subject: SLOPE: prosupport definitions
| File | + | − |
|---|---|---|
| src/backend/utils/adt/misc.c | 294 | 0 |
| src/include/nodes/supportnodes.h | 25 | 0 |
From 116168bcf6e2ca6b31dd26925a3d2cb0dfea5ce2 Mon Sep 17 00:00:00 2001
From: Alexandre Felipe <o.alexandre.felipe@gmail.com>
Date: Fri, 3 Apr 2026 20:01:39 +0100
Subject: [PATCH 3/6] SLOPE: prosupport definitions
Add support functions to describe monotonicy of buildint functions
These functions will be referenced by pg_proc entries in a subsequent
commit.
New prosupport functions:
- arg0_asc_slope_support: f(x, ...) is increasing in x
- arg0_desc_slope_support: f(x, ...) is decreasing in x
- arg1_asc_slope_support: f(a, x, ...) is increasing in x
- diff_slope_support: x - y is increasing in x, decreasing in y
- addition_slope_support: x + y is increasing in both args
- multiply_slope_support: x * c or c * x depends on sign of constant c
- divide_slope_support: x / c depends on sign of constant c
Also adds SupportRequestMonotonic to supportnodes.h for the planner
to query monotonicity information from prosupport functions.
---
src/backend/utils/adt/misc.c | 294 +++++++++++++++++++++++++++++++
src/include/nodes/supportnodes.h | 25 +++
2 files changed, 319 insertions(+)
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index c033e68ba15..19b7b48e80a 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -32,6 +32,7 @@
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
+#include "nodes/supportnodes.h"
#include "parser/parse_type.h"
#include "parser/scansup.h"
#include "pgstat.h"
@@ -43,6 +44,7 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
+#include "utils/numeric.h"
#include "utils/ruleutils.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
@@ -1095,3 +1097,295 @@ any_value_transfn(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
+
+/*
+ * monotonic_slope_support
+ * Generic helper for prosupport functions that declare monotonic slopes.
+ *
+ * If the request is a SupportRequestMonotonic, fills in nslopes and slopes
+ * and returns the request pointer. Otherwise returns NULL.
+ */
+static Datum
+monotonic_slope_support(Node *rawreq, int nslopes,
+ const MonotonicFunction *slopes)
+{
+ if (IsA(rawreq, SupportRequestMonotonic))
+ {
+ SupportRequestMonotonic *req = (SupportRequestMonotonic *) rawreq;
+
+ req->nslopes = nslopes;
+ req->slopes = slopes;
+ return PointerGetDatum(req);
+ }
+
+ return PointerGetDatum(NULL);
+}
+
+/*
+ * arg0_asc_slope_support
+ * Prosupport: f(x, ...) is monotonically increasing in x.
+ */
+Datum
+arg0_asc_slope_support(PG_FUNCTION_ARGS)
+{
+ static const MonotonicFunction pattern[1] = {MONOTONICFUNC_INCREASING};
+
+ return monotonic_slope_support((Node *) PG_GETARG_POINTER(0),
+ lengthof(pattern), pattern);
+}
+
+/*
+ * arg0_desc_slope_support
+ * Prosupport: f(x, ...) is monotonically decreasing in x.
+ */
+Datum
+arg0_desc_slope_support(PG_FUNCTION_ARGS)
+{
+ static const MonotonicFunction pattern[1] = {MONOTONICFUNC_DECREASING};
+
+ return monotonic_slope_support((Node *) PG_GETARG_POINTER(0),
+ lengthof(pattern), pattern);
+}
+
+/*
+ * arg1_asc_slope_support
+ * Prosupport: f(a, x, ...) is monotonically increasing in x.
+ */
+Datum
+arg1_asc_slope_support(PG_FUNCTION_ARGS)
+{
+ static const MonotonicFunction pattern[2] = {MONOTONICFUNC_NONE,
+ MONOTONICFUNC_INCREASING};
+
+ return monotonic_slope_support((Node *) PG_GETARG_POINTER(0),
+ lengthof(pattern), pattern);
+}
+
+/*
+ * diff_slope_support
+ * Prosupport: f(x, y) = x - y is increasing in x, decreasing in y.
+ */
+Datum
+diff_slope_support(PG_FUNCTION_ARGS)
+{
+ static const MonotonicFunction pattern[2] = {MONOTONICFUNC_INCREASING,
+ MONOTONICFUNC_DECREASING};
+
+ return monotonic_slope_support((Node *) PG_GETARG_POINTER(0),
+ lengthof(pattern), pattern);
+}
+
+/*
+ * addition_slope_support
+ * Prosupport: f(x, y) = x + y is increasing in both x and y.
+ */
+Datum
+addition_slope_support(PG_FUNCTION_ARGS)
+{
+ static const MonotonicFunction pattern[2] = {MONOTONICFUNC_INCREASING,
+ MONOTONICFUNC_INCREASING};
+
+ return monotonic_slope_support((Node *) PG_GETARG_POINTER(0),
+ lengthof(pattern), pattern);
+}
+
+/*
+ * get_const_sign
+ * Helper to determine the sign of a numeric constant.
+ * Returns 1 for positive, -1 for negative, 0 for zero or unknown.
+ */
+static int
+get_const_sign(Const *constval)
+{
+ if (constval->constisnull)
+ return 0;
+
+ switch (constval->consttype)
+ {
+ case INT2OID:
+ {
+ int16 val = DatumGetInt16(constval->constvalue);
+
+ return (val > 0) ? 1 : (val < 0) ? -1 : 0;
+ }
+ case INT4OID:
+ {
+ int32 val = DatumGetInt32(constval->constvalue);
+
+ return (val > 0) ? 1 : (val < 0) ? -1 : 0;
+ }
+ case INT8OID:
+ {
+ int64 val = DatumGetInt64(constval->constvalue);
+
+ return (val > 0) ? 1 : (val < 0) ? -1 : 0;
+ }
+ case FLOAT4OID:
+ {
+ float4 val = DatumGetFloat4(constval->constvalue);
+
+ if (isnan(val) || val == 0.0f)
+ return 0;
+ return (val > 0.0f) ? 1 : -1;
+ }
+ case FLOAT8OID:
+ {
+ float8 val = DatumGetFloat8(constval->constvalue);
+
+ if (isnan(val) || val == 0.0)
+ return 0;
+ return (val > 0.0) ? 1 : -1;
+ }
+ case NUMERICOID:
+ {
+ Numeric num = DatumGetNumeric(constval->constvalue);
+ Datum result;
+ Numeric sign_num;
+ int sign;
+
+ if (numeric_is_nan(num) || numeric_is_inf(num))
+ return 0;
+
+ result = DirectFunctionCall1(numeric_sign, NumericGetDatum(num));
+ sign_num = DatumGetNumeric(result);
+ sign = numeric_int4_safe(sign_num, NULL);
+ return sign;
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * multiply_slope_support
+ * Prosupport: x * c is increasing if c > 0, decreasing if c < 0.
+ * Similarly for c * x.
+ *
+ * For multiplication, the monotonicity depends on the sign of the constant:
+ * - x * positive_const: increasing in x
+ * - x * negative_const: decreasing in x
+ * - x * 0: not monotonic (constant result)
+ */
+Datum
+multiply_slope_support(PG_FUNCTION_ARGS)
+{
+ Node *rawreq = (Node *) PG_GETARG_POINTER(0);
+
+ if (IsA(rawreq, SupportRequestMonotonic))
+ {
+ SupportRequestMonotonic *req = (SupportRequestMonotonic *) rawreq;
+ List *args;
+ Node *arg0;
+ Node *arg1;
+ Const *constval = NULL;
+ int var_argno = -1;
+ int sign;
+
+ if (IsA(req->expr, FuncExpr))
+ args = ((FuncExpr *) req->expr)->args;
+ else if (IsA(req->expr, OpExpr))
+ args = ((OpExpr *) req->expr)->args;
+ else
+ PG_RETURN_POINTER(NULL);
+
+ if (list_length(args) != 2)
+ PG_RETURN_POINTER(NULL);
+
+ arg0 = (Node *) linitial(args);
+ arg1 = (Node *) lsecond(args);
+
+ if (IsA(arg0, Const))
+ {
+ constval = (Const *) arg0;
+ var_argno = 1;
+ }
+ else if (IsA(arg1, Const))
+ {
+ constval = (Const *) arg1;
+ var_argno = 0;
+ }
+ else
+ PG_RETURN_POINTER(NULL);
+
+ sign = get_const_sign(constval);
+ if (sign == 0)
+ PG_RETURN_POINTER(NULL);
+
+ {
+ static const MonotonicFunction asc_first[2] = {MONOTONICFUNC_INCREASING,
+ MONOTONICFUNC_NONE};
+ static const MonotonicFunction asc_second[2] = {MONOTONICFUNC_NONE,
+ MONOTONICFUNC_INCREASING};
+ static const MonotonicFunction desc_first[2] = {MONOTONICFUNC_DECREASING,
+ MONOTONICFUNC_NONE};
+ static const MonotonicFunction desc_second[2] = {MONOTONICFUNC_NONE,
+ MONOTONICFUNC_DECREASING};
+
+ if (var_argno == 0)
+ req->slopes = (sign > 0) ? asc_first : desc_first;
+ else
+ req->slopes = (sign > 0) ? asc_second : desc_second;
+ req->nslopes = 2;
+ PG_RETURN_POINTER(req);
+ }
+ }
+
+ PG_RETURN_POINTER(NULL);
+}
+
+/*
+ * divide_slope_support
+ * Prosupport: x / c is increasing if c > 0, decreasing if c < 0.
+ *
+ * Division by a constant has the same monotonicity as multiplication:
+ * - x / positive_const: increasing in x
+ * - x / negative_const: decreasing in x
+ * - x / 0: undefined (not monotonic)
+ */
+Datum
+divide_slope_support(PG_FUNCTION_ARGS)
+{
+ Node *rawreq = (Node *) PG_GETARG_POINTER(0);
+
+ if (IsA(rawreq, SupportRequestMonotonic))
+ {
+ SupportRequestMonotonic *req = (SupportRequestMonotonic *) rawreq;
+ List *args;
+ Node *arg1;
+ Const *constval;
+ int sign;
+
+ if (IsA(req->expr, FuncExpr))
+ args = ((FuncExpr *) req->expr)->args;
+ else if (IsA(req->expr, OpExpr))
+ args = ((OpExpr *) req->expr)->args;
+ else
+ PG_RETURN_POINTER(NULL);
+
+ if (list_length(args) != 2)
+ PG_RETURN_POINTER(NULL);
+
+ arg1 = (Node *) lsecond(args);
+
+ if (!IsA(arg1, Const))
+ PG_RETURN_POINTER(NULL);
+
+ constval = (Const *) arg1;
+ sign = get_const_sign(constval);
+ if (sign == 0)
+ PG_RETURN_POINTER(NULL);
+
+ {
+ static const MonotonicFunction asc_pattern[2] = {MONOTONICFUNC_INCREASING,
+ MONOTONICFUNC_NONE};
+ static const MonotonicFunction desc_pattern[2] = {MONOTONICFUNC_DECREASING,
+ MONOTONICFUNC_NONE};
+
+ req->slopes = (sign > 0) ? asc_pattern : desc_pattern;
+ req->nslopes = 2;
+ PG_RETURN_POINTER(req);
+ }
+ }
+
+ PG_RETURN_POINTER(NULL);
+}
diff --git a/src/include/nodes/supportnodes.h b/src/include/nodes/supportnodes.h
index 132a2bcd8af..106a369e1cc 100644
--- a/src/include/nodes/supportnodes.h
+++ b/src/include/nodes/supportnodes.h
@@ -445,4 +445,29 @@ typedef struct SupportRequestModifyInPlace
int paramid; /* ID of Param(s) representing variable */
} SupportRequestModifyInPlace;
+/* ----------
+ * SupportRequestMonotonic: request monotonicity information for SLOPE
+ *
+ * This allows the planner to use an index on 'x' to satisfy ORDER BY f(x)
+ * when f is monotonic. The support function fills in the slopes array
+ * to indicate the monotonicity of each argument.
+ *
+ * 'expr' is the FuncExpr or OpExpr being analyzed.
+ * 'nslopes' points to a MonotonicFunction array (one per argument up to
+ * nslopes). Arguments beyond nslopes are treated as MONOTONICFUNC_NONE.
+ * Return the request pointer on success, or NULL if not monotonic.
+ * ----------
+ */
+typedef struct SupportRequestMonotonic
+{
+ NodeTag type;
+
+ /* Input fields: */
+ Node *expr; /* FuncExpr or OpExpr */
+
+ /* Output fields (set by prosupport function): */
+ int nslopes; /* number of slopes in array */
+ const MonotonicFunction *slopes; /* array of slopes, one per arg */
+} SupportRequestMonotonic;
+
#endif /* SUPPORTNODES_H */
--
2.53.0