aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/float.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r--src/backend/utils/adt/float.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index bc6a3e09b5b..4f718c3eff1 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1180,6 +1180,93 @@ btfloat84cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
}
+/*
+ * in_range support function for float8.
+ *
+ * Note: we needn't supply a float8_float4 variant, as implicit coercion
+ * of the offset value takes care of that scenario just as well.
+ */
+Datum
+in_range_float8_float8(PG_FUNCTION_ARGS)
+{
+ float8 val = PG_GETARG_FLOAT8(0);
+ float8 base = PG_GETARG_FLOAT8(1);
+ float8 offset = PG_GETARG_FLOAT8(2);
+ bool sub = PG_GETARG_BOOL(3);
+ bool less = PG_GETARG_BOOL(4);
+ float8 sum;
+
+ /*
+ * Reject negative or NaN offset. Negative is per spec, and NaN is
+ * because appropriate semantics for that seem non-obvious.
+ */
+ if (isnan(offset) || offset < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PRECEDING_FOLLOWING_SIZE),
+ errmsg("invalid preceding or following size in window function")));
+
+ /*
+ * Deal with cases where val and/or base is NaN, following the rule that
+ * NaN sorts after non-NaN (cf float8_cmp_internal). The offset cannot
+ * affect the conclusion.
+ */
+ if (isnan(val))
+ {
+ if (isnan(base))
+ PG_RETURN_BOOL(true); /* NAN = NAN */
+ else
+ PG_RETURN_BOOL(!less); /* NAN > non-NAN */
+ }
+ else if (isnan(base))
+ {
+ PG_RETURN_BOOL(less); /* non-NAN < NAN */
+ }
+
+ /*
+ * Deal with infinite offset (necessarily +inf, at this point). We must
+ * special-case this because if base happens to be -inf, their sum would
+ * be NaN, which is an overflow-ish condition we should avoid.
+ */
+ if (isinf(offset))
+ {
+ PG_RETURN_BOOL(sub ? !less : less);
+ }
+
+ /*
+ * Otherwise it should be safe to compute base +/- offset. We trust the
+ * FPU to cope if base is +/-inf or the true sum would overflow, and
+ * produce a suitably signed infinity, which will compare properly against
+ * val whether or not that's infinity.
+ */
+ if (sub)
+ sum = base - offset;
+ else
+ sum = base + offset;
+
+ if (less)
+ PG_RETURN_BOOL(val <= sum);
+ else
+ PG_RETURN_BOOL(val >= sum);
+}
+
+/*
+ * in_range support function for float4.
+ *
+ * We would need a float4_float8 variant in any case, so we supply that and
+ * let implicit coercion take care of the float4_float4 case.
+ */
+Datum
+in_range_float4_float8(PG_FUNCTION_ARGS)
+{
+ /* Doesn't seem worth duplicating code for, so just invoke float8_float8 */
+ return DirectFunctionCall5(in_range_float8_float8,
+ Float8GetDatumFast((float8) PG_GETARG_FLOAT4(0)),
+ Float8GetDatumFast((float8) PG_GETARG_FLOAT4(1)),
+ PG_GETARG_DATUM(2),
+ PG_GETARG_DATUM(3),
+ PG_GETARG_DATUM(4));
+}
+
/*
* ===================