1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

Add window RANGE support for float4, float8, numeric.

Commit 0a459cec9 left this for later, but since time's running out,
I went ahead and took care of it.  There are more data types that
somebody might someday want RANGE support for, but this is enough
to satisfy all expectations of the SQL standard, which just says that
"numeric, datetime, and interval" types should have RANGE support.
This commit is contained in:
Tom Lane
2018-02-24 13:23:38 -05:00
parent 081bfc19b3
commit 8b29e88cdc
7 changed files with 429 additions and 1 deletions

View File

@ -2165,6 +2165,81 @@ cmp_numerics(Numeric num1, Numeric num2)
return result;
}
/*
* in_range support function for numeric.
*/
Datum
in_range_numeric_numeric(PG_FUNCTION_ARGS)
{
Numeric val = PG_GETARG_NUMERIC(0);
Numeric base = PG_GETARG_NUMERIC(1);
Numeric offset = PG_GETARG_NUMERIC(2);
bool sub = PG_GETARG_BOOL(3);
bool less = PG_GETARG_BOOL(4);
bool result;
/*
* Reject negative or NaN offset. Negative is per spec, and NaN is
* because appropriate semantics for that seem non-obvious.
*/
if (NUMERIC_IS_NAN(offset) || NUMERIC_SIGN(offset) == NUMERIC_NEG)
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 cmp_numerics). The offset cannot affect
* the conclusion.
*/
if (NUMERIC_IS_NAN(val))
{
if (NUMERIC_IS_NAN(base))
result = true; /* NAN = NAN */
else
result = !less; /* NAN > non-NAN */
}
else if (NUMERIC_IS_NAN(base))
{
result = less; /* non-NAN < NAN */
}
else
{
/*
* Otherwise go ahead and compute base +/- offset. While it's
* possible for this to overflow the numeric format, it's unlikely
* enough that we don't take measures to prevent it.
*/
NumericVar valv;
NumericVar basev;
NumericVar offsetv;
NumericVar sum;
init_var_from_num(val, &valv);
init_var_from_num(base, &basev);
init_var_from_num(offset, &offsetv);
init_var(&sum);
if (sub)
sub_var(&basev, &offsetv, &sum);
else
add_var(&basev, &offsetv, &sum);
if (less)
result = (cmp_var(&valv, &sum) <= 0);
else
result = (cmp_var(&valv, &sum) >= 0);
free_var(&sum);
}
PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(base, 1);
PG_FREE_IF_COPY(offset, 2);
PG_RETURN_BOOL(result);
}
Datum
hash_numeric(PG_FUNCTION_ARGS)
{