Skip to content

Commit 8b29e88

Browse files
committed
Add window RANGE support for float4, float8, numeric.
Commit 0a459ce 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.
1 parent 081bfc1 commit 8b29e88

File tree

7 files changed

+429
-1
lines changed

7 files changed

+429
-1
lines changed

src/backend/utils/adt/float.c

+87
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,93 @@ btfloat84cmp(PG_FUNCTION_ARGS)
11801180
PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
11811181
}
11821182

1183+
/*
1184+
* in_range support function for float8.
1185+
*
1186+
* Note: we needn't supply a float8_float4 variant, as implicit coercion
1187+
* of the offset value takes care of that scenario just as well.
1188+
*/
1189+
Datum
1190+
in_range_float8_float8(PG_FUNCTION_ARGS)
1191+
{
1192+
float8 val = PG_GETARG_FLOAT8(0);
1193+
float8 base = PG_GETARG_FLOAT8(1);
1194+
float8 offset = PG_GETARG_FLOAT8(2);
1195+
bool sub = PG_GETARG_BOOL(3);
1196+
bool less = PG_GETARG_BOOL(4);
1197+
float8 sum;
1198+
1199+
/*
1200+
* Reject negative or NaN offset. Negative is per spec, and NaN is
1201+
* because appropriate semantics for that seem non-obvious.
1202+
*/
1203+
if (isnan(offset) || offset < 0)
1204+
ereport(ERROR,
1205+
(errcode(ERRCODE_INVALID_PRECEDING_FOLLOWING_SIZE),
1206+
errmsg("invalid preceding or following size in window function")));
1207+
1208+
/*
1209+
* Deal with cases where val and/or base is NaN, following the rule that
1210+
* NaN sorts after non-NaN (cf float8_cmp_internal). The offset cannot
1211+
* affect the conclusion.
1212+
*/
1213+
if (isnan(val))
1214+
{
1215+
if (isnan(base))
1216+
PG_RETURN_BOOL(true); /* NAN = NAN */
1217+
else
1218+
PG_RETURN_BOOL(!less); /* NAN > non-NAN */
1219+
}
1220+
else if (isnan(base))
1221+
{
1222+
PG_RETURN_BOOL(less); /* non-NAN < NAN */
1223+
}
1224+
1225+
/*
1226+
* Deal with infinite offset (necessarily +inf, at this point). We must
1227+
* special-case this because if base happens to be -inf, their sum would
1228+
* be NaN, which is an overflow-ish condition we should avoid.
1229+
*/
1230+
if (isinf(offset))
1231+
{
1232+
PG_RETURN_BOOL(sub ? !less : less);
1233+
}
1234+
1235+
/*
1236+
* Otherwise it should be safe to compute base +/- offset. We trust the
1237+
* FPU to cope if base is +/-inf or the true sum would overflow, and
1238+
* produce a suitably signed infinity, which will compare properly against
1239+
* val whether or not that's infinity.
1240+
*/
1241+
if (sub)
1242+
sum = base - offset;
1243+
else
1244+
sum = base + offset;
1245+
1246+
if (less)
1247+
PG_RETURN_BOOL(val <= sum);
1248+
else
1249+
PG_RETURN_BOOL(val >= sum);
1250+
}
1251+
1252+
/*
1253+
* in_range support function for float4.
1254+
*
1255+
* We would need a float4_float8 variant in any case, so we supply that and
1256+
* let implicit coercion take care of the float4_float4 case.
1257+
*/
1258+
Datum
1259+
in_range_float4_float8(PG_FUNCTION_ARGS)
1260+
{
1261+
/* Doesn't seem worth duplicating code for, so just invoke float8_float8 */
1262+
return DirectFunctionCall5(in_range_float8_float8,
1263+
Float8GetDatumFast((float8) PG_GETARG_FLOAT4(0)),
1264+
Float8GetDatumFast((float8) PG_GETARG_FLOAT4(1)),
1265+
PG_GETARG_DATUM(2),
1266+
PG_GETARG_DATUM(3),
1267+
PG_GETARG_DATUM(4));
1268+
}
1269+
11831270

11841271
/*
11851272
* ===================

src/backend/utils/adt/numeric.c

+75
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,81 @@ cmp_numerics(Numeric num1, Numeric num2)
21652165
return result;
21662166
}
21672167

2168+
/*
2169+
* in_range support function for numeric.
2170+
*/
2171+
Datum
2172+
in_range_numeric_numeric(PG_FUNCTION_ARGS)
2173+
{
2174+
Numeric val = PG_GETARG_NUMERIC(0);
2175+
Numeric base = PG_GETARG_NUMERIC(1);
2176+
Numeric offset = PG_GETARG_NUMERIC(2);
2177+
bool sub = PG_GETARG_BOOL(3);
2178+
bool less = PG_GETARG_BOOL(4);
2179+
bool result;
2180+
2181+
/*
2182+
* Reject negative or NaN offset. Negative is per spec, and NaN is
2183+
* because appropriate semantics for that seem non-obvious.
2184+
*/
2185+
if (NUMERIC_IS_NAN(offset) || NUMERIC_SIGN(offset) == NUMERIC_NEG)
2186+
ereport(ERROR,
2187+
(errcode(ERRCODE_INVALID_PRECEDING_FOLLOWING_SIZE),
2188+
errmsg("invalid preceding or following size in window function")));
2189+
2190+
/*
2191+
* Deal with cases where val and/or base is NaN, following the rule that
2192+
* NaN sorts after non-NaN (cf cmp_numerics). The offset cannot affect
2193+
* the conclusion.
2194+
*/
2195+
if (NUMERIC_IS_NAN(val))
2196+
{
2197+
if (NUMERIC_IS_NAN(base))
2198+
result = true; /* NAN = NAN */
2199+
else
2200+
result = !less; /* NAN > non-NAN */
2201+
}
2202+
else if (NUMERIC_IS_NAN(base))
2203+
{
2204+
result = less; /* non-NAN < NAN */
2205+
}
2206+
else
2207+
{
2208+
/*
2209+
* Otherwise go ahead and compute base +/- offset. While it's
2210+
* possible for this to overflow the numeric format, it's unlikely
2211+
* enough that we don't take measures to prevent it.
2212+
*/
2213+
NumericVar valv;
2214+
NumericVar basev;
2215+
NumericVar offsetv;
2216+
NumericVar sum;
2217+
2218+
init_var_from_num(val, &valv);
2219+
init_var_from_num(base, &basev);
2220+
init_var_from_num(offset, &offsetv);
2221+
init_var(&sum);
2222+
2223+
if (sub)
2224+
sub_var(&basev, &offsetv, &sum);
2225+
else
2226+
add_var(&basev, &offsetv, &sum);
2227+
2228+
if (less)
2229+
result = (cmp_var(&valv, &sum) <= 0);
2230+
else
2231+
result = (cmp_var(&valv, &sum) >= 0);
2232+
2233+
free_var(&sum);
2234+
}
2235+
2236+
PG_FREE_IF_COPY(val, 0);
2237+
PG_FREE_IF_COPY(base, 1);
2238+
PG_FREE_IF_COPY(offset, 2);
2239+
2240+
PG_RETURN_BOOL(result);
2241+
}
2242+
21682243
Datum
21692244
hash_numeric(PG_FUNCTION_ARGS)
21702245
{

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201802061
56+
#define CATALOG_VERSION_NO 201802241
5757

5858
#endif

src/include/catalog/pg_amproc.h

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ DATA(insert ( 1970 700 701 1 2194 ));
105105
DATA(insert ( 1970 701 701 1 355 ));
106106
DATA(insert ( 1970 701 701 2 3133 ));
107107
DATA(insert ( 1970 701 700 1 2195 ));
108+
DATA(insert ( 1970 701 701 3 4139 ));
109+
DATA(insert ( 1970 700 701 3 4140 ));
108110
DATA(insert ( 1974 869 869 1 926 ));
109111
DATA(insert ( 1976 21 21 1 350 ));
110112
DATA(insert ( 1976 21 21 2 3129 ));
@@ -133,6 +135,7 @@ DATA(insert ( 1986 19 19 1 359 ));
133135
DATA(insert ( 1986 19 19 2 3135 ));
134136
DATA(insert ( 1988 1700 1700 1 1769 ));
135137
DATA(insert ( 1988 1700 1700 2 3283 ));
138+
DATA(insert ( 1988 1700 1700 3 4141 ));
136139
DATA(insert ( 1989 26 26 1 356 ));
137140
DATA(insert ( 1989 26 26 2 3134 ));
138141
DATA(insert ( 1991 30 30 1 404 ));

src/include/catalog/pg_proc.h

+6
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,12 @@ DATA(insert OID = 4131 ( in_range PGNSP PGUID 12 1 0 0 0 f f f f t f i s 5 0
661661
DESCR("window RANGE support");
662662
DATA(insert OID = 4132 ( in_range PGNSP PGUID 12 1 0 0 0 f f f f t f i s 5 0 16 "21 21 21 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int2_int2 _null_ _null_ _null_ ));
663663
DESCR("window RANGE support");
664+
DATA(insert OID = 4139 ( in_range PGNSP PGUID 12 1 0 0 0 f f f f t f i s 5 0 16 "701 701 701 16 16" _null_ _null_ _null_ _null_ _null_ in_range_float8_float8 _null_ _null_ _null_ ));
665+
DESCR("window RANGE support");
666+
DATA(insert OID = 4140 ( in_range PGNSP PGUID 12 1 0 0 0 f f f f t f i s 5 0 16 "700 700 701 16 16" _null_ _null_ _null_ _null_ _null_ in_range_float4_float8 _null_ _null_ _null_ ));
667+
DESCR("window RANGE support");
668+
DATA(insert OID = 4141 ( in_range PGNSP PGUID 12 1 0 0 0 f f f f t f i s 5 0 16 "1700 1700 1700 16 16" _null_ _null_ _null_ _null_ _null_ in_range_numeric_numeric _null_ _null_ _null_ ));
669+
DESCR("window RANGE support");
664670

665671
DATA(insert OID = 361 ( lseg_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 701 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_distance _null_ _null_ _null_ ));
666672
DATA(insert OID = 362 ( lseg_interpt PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 600 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_interpt _null_ _null_ _null_ ));

0 commit comments

Comments
 (0)