Thread
Commits
-
Fix some corner cases for window ranges with infinite offsets.
- a4faef8f8fe1 14.0 landed
-
Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-16T18:58:13Z
Dean Rasheed pointed out that in_range for float4/float8 seems to be doing the wrong thing for infinite offsets, and after some testing I concur that it is. For example, a sort key of '-infinity' should be considered to be in-range for a range specified as RANGE BETWEEN 'inf' PRECEDING AND 'inf' PRECEDING; but with the code as it stands, it isn't. I propose the attached patch, which probably should be back-patched. When the current row's value is +infinity, actual computation of base - offset would yield NaN, making it a bit unclear whether we should consider -infinity to be in-range. It seems to me that we should, as that gives more natural-looking results in the test cases, so that's how the patch does it. regards, tom lane
-
Re: Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-16T21:50:16Z
I wrote: > When the current row's value is +infinity, actual computation of > base - offset would yield NaN, making it a bit unclear whether > we should consider -infinity to be in-range. It seems to me that > we should, as that gives more natural-looking results in the test > cases, so that's how the patch does it. Actually, after staring at those results awhile longer, I decided they were wrong. The results shown here seem actually sane --- for instance, -Infinity shouldn't "infinitely precede" itself, I think. (Maybe if you got solipsistic enough you could argue that that is valid, but it seems pretty bogus.) regards, tom lane
-
Re: Wrong results from in_range() tests with infinite offset
Dean Rasheed <dean.a.rasheed@gmail.com> — 2020-07-16T23:47:14Z
On Thu, 16 Jul 2020, 22:50 Tom Lane, <tgl@sss.pgh.pa.us> wrote: > I wrote: > > When the current row's value is +infinity, actual computation of > > base - offset would yield NaN, making it a bit unclear whether > > we should consider -infinity to be in-range. It seems to me that > > we should, as that gives more natural-looking results in the test > > cases, so that's how the patch does it. > > Actually, after staring at those results awhile longer, I decided > they were wrong. The results shown here seem actually sane --- > for instance, -Infinity shouldn't "infinitely precede" itself, > I think. (Maybe if you got solipsistic enough you could argue > that that is valid, but it seems pretty bogus.) > Hmm, that code looks a bit fishy to me, but I really need to think about it some more. I'll take another look tomorrow, and maybe it'll become clearer. Regards, Dean
-
Re: Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-17T00:59:57Z
Dean Rasheed <dean.a.rasheed@gmail.com> writes: > On Thu, 16 Jul 2020, 22:50 Tom Lane, <tgl@sss.pgh.pa.us> wrote: >> Actually, after staring at those results awhile longer, I decided >> they were wrong. The results shown here seem actually sane --- >> for instance, -Infinity shouldn't "infinitely precede" itself, >> I think. (Maybe if you got solipsistic enough you could argue >> that that is valid, but it seems pretty bogus.) > Hmm, that code looks a bit fishy to me, but I really need to think about it > some more. I'll take another look tomorrow, and maybe it'll become clearer. It's certainly verbose, so I'd like to find a more concise way to write the logic. But the v2 results seem right. regards, tom lane
-
Re: Wrong results from in_range() tests with infinite offset
Dean Rasheed <dean.a.rasheed@gmail.com> — 2020-07-18T08:16:39Z
On Fri, 17 Jul 2020 at 01:59, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Dean Rasheed <dean.a.rasheed@gmail.com> writes: > > On Thu, 16 Jul 2020, 22:50 Tom Lane, <tgl@sss.pgh.pa.us> wrote: > >> Actually, after staring at those results awhile longer, I decided > >> they were wrong. The results shown here seem actually sane --- > >> for instance, -Infinity shouldn't "infinitely precede" itself, > >> I think. (Maybe if you got solipsistic enough you could argue > >> that that is valid, but it seems pretty bogus.) > > > Hmm, that code looks a bit fishy to me, but I really need to think about it > > some more. I'll take another look tomorrow, and maybe it'll become clearer. > > It's certainly verbose, so I'd like to find a more concise way to > write the logic. But the v2 results seem right. > I'm finding it hard to come up with a principled argument to say exactly what the right results should be. As things stand (pre-patch), a window frame defined as "BETWEEN 'inf' PRECEDING AND 'inf' PRECEDING", produces the following: id | f_float4 | first_value | last_value ----+-----------+-------------+------------ 0 | -Infinity | | 1 | -3 | | 2 | -1 | | 3 | 0 | | 4 | 1.1 | | 5 | 1.12 | | 6 | 2 | | 7 | 100 | | 8 | Infinity | | 9 | NaN | 9 | 9 (10 rows) which is clearly wrong, because -Inf obviously infinitely precedes all the other (non-NaN) values. With the first version of the patch, that result became id | f_float4 | first_value | last_value ----+-----------+-------------+------------ 0 | -Infinity | 0 | 0 1 | -3 | 0 | 0 2 | -1 | 0 | 0 3 | 0 | 0 | 0 4 | 1.1 | 0 | 0 5 | 1.12 | 0 | 0 6 | 2 | 0 | 0 7 | 100 | 0 | 0 8 | Infinity | 0 | 0 9 | NaN | 9 | 9 (10 rows) which is definitely better, but the one obvious problem is last_value for id=8, because all the values in earlier rows infinitely precede +Inf, so they should be included in the window frame for that row. With the second version of the patch, the result is id | f_float4 | first_value | last_value ----+-----------+-------------+------------ 0 | -Infinity | | 1 | -3 | 0 | 0 2 | -1 | 0 | 0 3 | 0 | 0 | 0 4 | 1.1 | 0 | 0 5 | 1.12 | 0 | 0 6 | 2 | 0 | 0 7 | 100 | 0 | 0 8 | Infinity | 0 | 7 9 | NaN | 9 | 9 (10 rows) That fixes last_value for id=8, using the fact that all values less than +Inf infinitely precede it, and also assuming that +Inf does not infinitely precede itself, which seems reasonable. The other change is in the first row, because it now assumes that -Inf doesn't infinitely precede itself, which seems reasonable from a consistency point of view. However, that is also a bit odd because it goes against the documented contract of in_range(), which is supposed to do the tests val <= base +/- offset1 val >= base +/- offset2 which for "BETWEEN 'inf' PRECEDING AND 'inf' PRECEDING" become val = base - Inf which is -Inf, even if base = -Inf. So I'd say that the window infinitely preceding -Inf contains -Inf, since -Inf - Inf = -Inf. But if -Inf infinitely precedes -Inf, it probably also makes sense to say that +Inf infinitely precedes +Inf for consistency, even though that really isn't well-defined, since Inf - Inf = NaN. Doing that is certainly a lot easier to code, because it just needs to return true if base +/- offset would be NaN, i.e., /* * Deal with cases where both base and offset are infinite, and computing * base +/- offset would produce NaN. This corresponds to a window frame * whose boundary infinitely precedes +inf or infinitely follows -inf, * which is not well-defined. For consistency with other cases involving * infinities, such as the fact that +inf infinitely follows +inf, we * choose to assume that +inf infinitely precedes +inf and -inf infinitely * follows -inf, and therefore that all finite and infinite values are in * such a window frame. */ if (isinf(base) && isinf(offset)) { if ((base > 0 && sub) || (base < 0 && !sub)) PG_RETURN_BOOL(true); } and the result is id | f_float8 | first_value | last_value ----+-----------+-------------+------------ 0 | -Infinity | 0 | 0 1 | -3 | 0 | 0 2 | -1 | 0 | 0 3 | 0 | 0 | 0 4 | 1.1 | 0 | 0 5 | 1.12 | 0 | 0 6 | 2 | 0 | 0 7 | 100 | 0 | 0 8 | Infinity | 0 | 8 9 | NaN | 9 | 9 (10 rows) which looks about equally sensible. To me, the fact that the window infinitely preceding -Inf includes -Inf makes more sense, but the meaning of the window infinitely preceding +Inf is much less obvious, and not really well-defined. Regards, Dean -
Re: Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-18T14:06:13Z
Dean Rasheed <dean.a.rasheed@gmail.com> writes: > if (isinf(base) && isinf(offset)) > { > if ((base > 0 && sub) || (base < 0 && !sub)) > PG_RETURN_BOOL(true); > } Yeah, I'd experimented with more-or-less that logic before arriving at my v2 patch. I didn't like the outcome that "inf both infinitely precedes and infinitely follows itself". Still, it is nicely simple. To make sense of this behavior, you have to argue that +/-inf are not in any way concrete values, but represent some sort of infinite ranges; then there could be some members of the class "inf" that infinitely precede other members. I thought that was bending the mathematical concept a bit too far. However, this isn't an area of math that I've studied in any detail, so maybe it's a standard interpretation. Still, I think the results my v2 patch gets make more sense than these. regards, tom lane -
Re: Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-18T21:28:52Z
I wrote: > Dean Rasheed <dean.a.rasheed@gmail.com> writes: >> if (isinf(base) && isinf(offset)) >> { >> if ((base > 0 && sub) || (base < 0 && !sub)) >> PG_RETURN_BOOL(true); >> } > Yeah, I'd experimented with more-or-less that logic before arriving at > my v2 patch. I didn't like the outcome that "inf both infinitely precedes > and infinitely follows itself". Still, it is nicely simple. I spent some more time thinking about this, and came to a couple of conclusions. First, let's take it as given that we should only special-case situations where the sum would be computed as NaN. That destroys my position that, for instance, -inf shouldn't be included in the range that ends 'inf preceding' itself, because the normal calculation goes through as -inf <= (-inf - inf) which yields TRUE without forming any NaN. Although that conclusion seems weird at first glance, there seems no way to poke a hole in it without rejecting the principle that inf + inf = inf. Second, if -inf is included in the range that ends 'inf preceding' itself, symmetry dictates that it is also included in the range that begins 'inf following' itself. In that case we'd be trying to compute -inf >= (-inf + inf) which does involve a NaN, but this argument says we should return TRUE. The other three cases where we'd hit NaNs are likewise symmetric with non-NaN cases that'd return TRUE. Hence, I'm forced to the conclusion that you've got it right above. I might write the code a little differently, but const-TRUE-for-NaN-cases seems like the right behavior. So I withdraw my objection to defining it this way. Unless somebody else weighs in, I'll commit it like that in a day or two. regards, tom lane -
Re: Wrong results from in_range() tests with infinite offset
Tom Lane <tgl@sss.pgh.pa.us> — 2020-07-21T02:06:32Z
I wrote: > The other three cases where we'd hit NaNs are likewise symmetric with > non-NaN cases that'd return TRUE. Hence, I'm forced to the conclusion > that you've got it right above. I might write the code a little > differently, but const-TRUE-for-NaN-cases seems like the right behavior. > So I withdraw my objection to defining it this way. Unless somebody > else weighs in, I'll commit it like that in a day or two. Pushed, but I chickened out of back-patching. The improvement in what happens for finite comparison values seems somewhat counterbalanced by the possibility that someone might not like the definition we arrived at for infinities. So, it's not quite an open-and-shut bug fix, so I just put it in HEAD (for now anyway). regards, tom lane
-
Re: Wrong results from in_range() tests with infinite offset
Dean Rasheed <dean.a.rasheed@gmail.com> — 2020-07-21T08:06:09Z
On Tue, 21 Jul 2020 at 03:06, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Pushed, but I chickened out of back-patching. The improvement in what > happens for finite comparison values seems somewhat counterbalanced by > the possibility that someone might not like the definition we arrived > at for infinities. So, it's not quite an open-and-shut bug fix, so > I just put it in HEAD (for now anyway). > Yeah, that seems fair enough, and it's quite an obscure corner-case that has gone unnoticed for quite some time. Regards, Dean