Thread

Commits

  1. Fix integer-overflow problems in interval comparison.

  1. Unexpected interval comparison

    Frazer McLean <frazer@frazermclean.co.uk> — 2017-03-21T13:57:09Z

    I came across an unexpected comparison (tested on PostgreSQL 9.4 and
    9.6) for intervals with a large difference in magnitude.
    
    
    I narrowed it down to this example, where comparisons with this range
    give the wrong value:
    
    
    postgres=# SELECT 
    
      '1 year'::interval > '3854933 years'::interval,
    
      '1 year'::interval > '3854934 years'::interval,
    
      '1 year'::interval > '32618664 years'::interval,
    
      '1 year'::interval > '32618665 years'::interval;
    
    
    
    ?column? | ?column? | ?column? | ?column?
    
    ----------+----------+----------+----------
    
    f        | t        | t        | f
    
    (1 row)
    
    
    
    Is this a bug? Should I not be comparing intervals? It would seem the
    interval type has enough information to give the correct answer here.
    
    
    Regards,
    
    
    
    Frazer McLean
    
  2. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-03-21T14:42:16Z

    Frazer McLean <frazer@frazermclean.co.uk> writes:
    > I came across an unexpected comparison (tested on PostgreSQL 9.4 and
    > 9.6) for intervals with a large difference in magnitude.
    
    >   '1 year'::interval > '32618665 years'::interval;
    
    > Is this a bug?
    
    It looks like the problem is overflow of the result of interval_cmp_value,
    because it's trying to compute
    
    =# select '32618665'::int8 * 30 * 86400 * 1000000;
    ERROR:  bigint out of range
    
    It's not immediately obvious how to avoid that while preserving the same
    comparison semantics :-(
    
    			regards, tom lane
    
    
    
  3. Re: Unexpected interval comparison

    Adrian Klaver <adrian.klaver@aklaver.com> — 2017-03-21T14:52:25Z

    On 03/21/2017 07:42 AM, Tom Lane wrote:
    > Frazer McLean <frazer@frazermclean.co.uk> writes:
    >> I came across an unexpected comparison (tested on PostgreSQL 9.4 and
    >> 9.6) for intervals with a large difference in magnitude.
    >
    >>   '1 year'::interval > '32618665 years'::interval;
    >
    >> Is this a bug?
    >
    > It looks like the problem is overflow of the result of interval_cmp_value,
    > because it's trying to compute
    >
    > =# select '32618665'::int8 * 30 * 86400 * 1000000;
    > ERROR:  bigint out of range
    >
    > It's not immediately obvious how to avoid that while preserving the same
    > comparison semantics :-(
    
    Not sure if it helps but this works:
    
    test=# select extract(epoch from '1 year'::interval) > extract(epoch 
    from '32618665 years'::interval);
      ?column?
    ----------
      f
    
    >
    > 			regards, tom lane
    >
    >
    
    
    -- 
    Adrian Klaver
    adrian.klaver@aklaver.com
    
    
    
  4. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-03-30T07:46:51Z

    Hello,
    
    At Tue, 21 Mar 2017 07:52:25 -0700, Adrian Klaver <adrian.klaver@aklaver.com> wrote in <375c9e5a-960f-942c-913f-55632a1f0a90@aklaver.com>
    > On 03/21/2017 07:42 AM, Tom Lane wrote:
    > > Frazer McLean <frazer@frazermclean.co.uk> writes:
    > >> I came across an unexpected comparison (tested on PostgreSQL 9.4 and
    > >> 9.6) for intervals with a large difference in magnitude.
    > >
    > >>   '1 year'::interval > '32618665 years'::interval;
    > >
    > >> Is this a bug?
    > >
    > > It looks like the problem is overflow of the result of
    > > interval_cmp_value,
    > > because it's trying to compute
    > >
    > > =# select '32618665'::int8 * 30 * 86400 * 1000000;
    > > ERROR:  bigint out of range
    > >
    > > It's not immediately obvious how to avoid that while preserving the
    > > same
    > > comparison semantics :-(
    
    This is an apparent bug of interval comparison. During comparison
    interval is converted into int64 in milliseconds but it overflows
    in the case.
    
    Detecting the overflow during the conversion can fix it and
    preserving the semantics (except value range). The current code
    tells a lie anyway for the cases but I'm not sure limting the
    range of value is acceptable or not.
    
    | =# select '106751990 days 24:59:59'::interval;
    |         interval         
    | -------------------------
    |  106751990 days 24:59:59
    | =# select '106751990 days 24:59:59'::interval > '1 year'::interval;
    | ERROR:  interval out of range during comparison
    
    If this is not acceptable, some refactoring would be required.
    
    
    > Not sure if it helps but this works:
    > 
    > test=# select extract(epoch from '1 year'::interval) > extract(epoch
    > from '32618665 years'::interval);
    >  ?column?
    > ----------
    >  f
    
    It calculates in seconds. So it is useful if subseconds are not
    significant. But extract also silently overflows during
    converting the same interval to usecs. This seems to need the
    same amendment.
    
    > =# select extract(usec from '32618665 years'::interval);
    >  date_part 
    > -----------
    >          0
    
    regards,
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  5. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-03-30T14:57:19Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > At Tue, 21 Mar 2017 07:52:25 -0700, Adrian Klaver <adrian.klaver@aklaver.com> wrote in <375c9e5a-960f-942c-913f-55632a1f0a90@aklaver.com>
    >> On 03/21/2017 07:42 AM, Tom Lane wrote:
    >>> It looks like the problem is overflow of the result of interval_cmp_value,
    >>> because it's trying to compute
    >>> =# select '32618665'::int8 * 30 * 86400 * 1000000;
    >>> ERROR:  bigint out of range
    >>> It's not immediately obvious how to avoid that while preserving the
    >>> same comparison semantics :-(
    
    > Detecting the overflow during the conversion can fix it and
    > preserving the semantics (except value range). The current code
    > tells a lie anyway for the cases but I'm not sure limting the
    > range of value is acceptable or not.
    
    I don't think it is.  It'd cause failures in attempting to enter
    very large interval values into btree indexes, for instance.
    
    A possible solution is to manually work in wider-than-64-bit
    arithmetic, that is compute the comparison values div and mod
    some pretty-large number and then compare the two halves.
    I seem to recall that we did something similar in a few cases
    years ago, before we were willing to assume that every machine
    had 64-bit integer support.
    
    Of course, for machines having int128, you could just use that
    type directly.  I'm not sure how widespread that support is
    nowadays.  Maybe a 95%-good-enough solution is to use int128
    if available and otherwise throw errors for intervals exceeding
    64 bits.
    
    			regards, tom lane
    
    
    
  6. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-03-31T05:21:57Z

    At Thu, 30 Mar 2017 10:57:19 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <2087.1490885839@sss.pgh.pa.us>
    > Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > > At Tue, 21 Mar 2017 07:52:25 -0700, Adrian Klaver <adrian.klaver@aklaver.com> wrote in <375c9e5a-960f-942c-913f-55632a1f0a90@aklaver.com>
    > >> On 03/21/2017 07:42 AM, Tom Lane wrote:
    > >>> It looks like the problem is overflow of the result of interval_cmp_value,
    > >>> because it's trying to compute
    > >>> =# select '32618665'::int8 * 30 * 86400 * 1000000;
    > >>> ERROR:  bigint out of range
    > >>> It's not immediately obvious how to avoid that while preserving the
    > >>> same comparison semantics :-(
    > 
    > > Detecting the overflow during the conversion can fix it and
    > > preserving the semantics (except value range). The current code
    > > tells a lie anyway for the cases but I'm not sure limting the
    > > range of value is acceptable or not.
    > 
    > I don't think it is.  It'd cause failures in attempting to enter
    > very large interval values into btree indexes, for instance.
    
    As for btree on intervals, it uses the same conversion function
    with bare comparisons so it works for btree, too.  The following
    correctly fails with the patch.
    
    | =# insert into ti values ('32618665 years'::interval);
    | ERROR:  interval out of range during comparison
    
    But, strange behavior is seen on creating an index.
    
    | =# insert into ti values ('32618665 years'::interval);
    | INSERT 0 1
    | postgres=# create index on ti using btree (i);
    | ERROR:  interval out of range during comparison
    
    So, restricting the domain on reading (interval_in or such) might
    be better. Since we don't have big-bigint, extract(usec) will
    overflow for certain range of interval values anyway. Or allow
    returning them in numeric?
    
    If we don't mind such inconsistency, just using wider integer
    will useful.
    
    > A possible solution is to manually work in wider-than-64-bit
    > arithmetic, that is compute the comparison values div and mod
    > some pretty-large number and then compare the two halves.
    > I seem to recall that we did something similar in a few cases
    > years ago, before we were willing to assume that every machine
    > had 64-bit integer support.
    > 
    > Of course, for machines having int128, you could just use that
    > type directly.  I'm not sure how widespread that support is
    > nowadays.  Maybe a 95%-good-enough solution is to use int128
    > if available and otherwise throw errors for intervals exceeding
    > 64 bits.
    
    int128 is seen in numeric.c. It is doable in the same manner. In
    that case it will be a bit slower on the platforms without
    int128.
    
    By the way is it right that we don't assume this as a bug-fix
    which should be done in the Pg10 dev cycle, but an improvement
    for 11?
    
    regards,
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
    
    
    
  7. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-03-31T17:29:24Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > At Thu, 30 Mar 2017 10:57:19 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <2087.1490885839@sss.pgh.pa.us>
    >> A possible solution is to manually work in wider-than-64-bit
    >> arithmetic, that is compute the comparison values div and mod
    >> some pretty-large number and then compare the two halves.
    >> I seem to recall that we did something similar in a few cases
    >> years ago, before we were willing to assume that every machine
    >> had 64-bit integer support.
    >> 
    >> Of course, for machines having int128, you could just use that
    >> type directly.  I'm not sure how widespread that support is
    >> nowadays.  Maybe a 95%-good-enough solution is to use int128
    >> if available and otherwise throw errors for intervals exceeding
    >> 64 bits.
    
    > int128 is seen in numeric.c. It is doable in the same manner. In
    > that case it will be a bit slower on the platforms without
    > int128.
    
    > By the way is it right that we don't assume this as a bug-fix
    > which should be done in the Pg10 dev cycle, but an improvement
    > for 11?
    
    Well, it seems like a bug to me.  We might conclude that the fix
    is too risky to back-patch, but it's hard to make that decision
    before having a patch in hand to evaluate.
    
    			regards, tom lane
    
    
    
  8. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-04-03T11:51:18Z

    Hmm. It took a bit longer time than expected.
    
    At Fri, 31 Mar 2017 13:29:24 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <10353.1490981364@sss.pgh.pa.us>
    > Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > > int128 is seen in numeric.c. It is doable in the same manner. In
    > > that case it will be a bit slower on the platforms without
    > > int128.
    > 
    > > By the way is it right that we don't assume this as a bug-fix
    > > which should be done in the Pg10 dev cycle, but an improvement
    > > for 11?
    > 
    > Well, it seems like a bug to me.  We might conclude that the fix
    > is too risky to back-patch, but it's hard to make that decision
    > before having a patch in hand to evaluate.
    
    Ok, the attached patch changes the result type of
    interval_cmp_value from TimeOffset(=int64) to new 128 bit
    LinearInterval. The value is hidden under the functions
    interval_eq/ge.../cmp and all other stuff seems to use the
    functions.
    
    For platforms without 128 bit support, int64 * 2 version of
    interval_cmp_value is used.
    
    I added separate test for the near-overflow values since just
    adding such values into INTERVAL_TABLE resuted in a mess. (I ran
    64-bit version by commenting-out the definition of PG_INT128_TYPE
    in pg_config.h).
    
    The attached patch is that.
    
    regards,
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  9. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-04-03T15:35:25Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > Ok, the attached patch changes the result type of
    > interval_cmp_value from TimeOffset(=int64) to new 128 bit
    > LinearInterval. The value is hidden under the functions
    > interval_eq/ge.../cmp and all other stuff seems to use the
    > functions.
    
    Looking at this now ... why isn't the INT64_AU32 macro just
    
    #define INT64_AU32(i64) ((i64) >> 32)
    
    ?  The business with subtracting and re-adding 1 seems unnecessary, and it
    also creates a risk of overflow with the minimum possible int64 value.
    
    			regards, tom lane
    
    
    
  10. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-04-04T08:15:03Z

    Thank you for the comment.
    
    At Mon, 03 Apr 2017 11:35:25 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <23053.1491233725@sss.pgh.pa.us>
    > Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > > Ok, the attached patch changes the result type of
    > > interval_cmp_value from TimeOffset(=int64) to new 128 bit
    > > LinearInterval. The value is hidden under the functions
    > > interval_eq/ge.../cmp and all other stuff seems to use the
    > > functions.
    > 
    > Looking at this now ... why isn't the INT64_AU32 macro just
    > 
    > #define INT64_AU32(i64) ((i64) >> 32)
    > 
    > ?  The business with subtracting and re-adding 1 seems unnecessary, and it
    > also creates a risk of overflow with the minimum possible int64 value.
    
    It is equivalent to "i64 / (1<<32)" except for -INT64_MAX.
    
    INT64_AU32 gives the value for the first term in the following
    polynomial.
    
    (int64)INT64_AU32(i64) * (2^32) + (int64)INT64_AL32(i64) = i64
    
    The previous expression intended to avoid decimal arithmetic, but
    gcc optimizes the simple division better (using cmovns-add-sar)
    than the current INT64_AU32 (jmp-sar) so I changed it. This
    doesn't suffer overflow.
    
    -#define INT64_AU32(i64) (((i64) < 0 ? (((i64) - 1) >> 32) + 1: ((i64) >> 32)))
    +#define INT64_AU32(i64) ((i64) / (1LL<<32))
    
    In summation of terms in 128bit multiplication expression, I
    noticed that the value of the second term's lower 32bit loses MSB
    for certain cases. I changed LINEARINTERVAL_ADD_INT64 to accept
    the MSB (as the 65th bit) separately.
    
    The first attached is the revised patch and the second is
    temporary sanity check code for non-128bit environment code. (but
    works only on 128 bit environment)
    
    regards,
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  11. Re: Unexpected interval comparison

    Vick Khera <vivek@khera.org> — 2017-04-04T12:39:59Z

    On Tue, Apr 4, 2017 at 4:15 AM, Kyotaro HORIGUCHI <
    horiguchi.kyotaro@lab.ntt.co.jp> wrote:
    
    > The previous expression intended to avoid decimal arithmetic, but
    > gcc optimizes the simple division better (using cmovns-add-sar)
    > than the current INT64_AU32 (jmp-sar) so I changed it. This
    > doesn't suffer overflow.
    >
    >
    How does this affect non-gcc compilers? Specifically I am interested in the
    llvm based compilers in FreeBSD. Or is this within a gcc-specific section
    of the header?
    
  12. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-04-04T22:06:38Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > The first attached is the revised patch and the second is
    > temporary sanity check code for non-128bit environment code. (but
    > works only on 128 bit environment)
    
    This seemed to me to be probably even less correct, so I extracted
    the addition and multiplication logic into a standalone test program
    (attached), which compares the result of a multiplication to that
    of native int128 arithmetic.  I changed the order of the LinearInterval
    fields to be LS-first so that I could overlay them onto an int128
    result (on a little-endian machine); this is just for testing purposes
    not something we must do in the finished code.  I soon found cases
    where it indeed fails, eg
    
    $ ./a.out 0x7ffffffff 0x7ffffffff
    7FFFFFFFF * 7FFFFFFFF
    result = 62 18446744004990074881
    result = 3E FFFFFFF000000001
    MISMATCH!
    result = 63 18446744004990074881
    result = 3F FFFFFFF000000001
    
    After fooling with it for awhile, I decided that the cause of the
    problems was basically not thinking carefully about the lower half
    of the value being unsigned: that affects when to do carries in
    the addition macro, and we also have to be careful about whether
    or not to sign-extend the partial product terms.  The second
    attached file is a version that I can't break anymore, though I'm
    not quite sure it's bug-free.
    
    			regards, tom lane
    
    
  13. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-04-05T11:07:23Z

    Mmm. It's shameful.
    
    At Tue, 04 Apr 2017 18:06:38 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <5084.1491343598@sss.pgh.pa.us>
    > Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > > The first attached is the revised patch and the second is
    > > temporary sanity check code for non-128bit environment code. (but
    > > works only on 128 bit environment)
    > 
    > This seemed to me to be probably even less correct, so I extracted
    > the addition and multiplication logic into a standalone test program
    > (attached), which compares the result of a multiplication to that
    > of native int128 arithmetic.  I changed the order of the LinearInterval
    > fields to be LS-first so that I could overlay them onto an int128
    > result (on a little-endian machine); this is just for testing purposes
    > not something we must do in the finished code.  I soon found cases
    > where it indeed fails, eg
    > 
    > $ ./a.out 0x7ffffffff 0x7ffffffff
    > 7FFFFFFFF * 7FFFFFFFF
    > result = 62 18446744004990074881
    > result = 3E FFFFFFF000000001
    > MISMATCH!
    > result = 63 18446744004990074881
    > result = 3F FFFFFFF000000001
    
    I admit that I was careless about that.
    
    > After fooling with it for awhile, I decided that the cause of the
    > problems was basically not thinking carefully about the lower half
    > of the value being unsigned: that affects when to do carries in
    > the addition macro, and we also have to be careful about whether
    > or not to sign-extend the partial product terms.  The second
    > attached file is a version that I can't break anymore, though I'm
    > not quite sure it's bug-free.
    
    In the first version, I converted all operands to positive
    numbers and finally correct the sign of the result. This was
    straightforward but doesn't looked clean so I tried direct
    handling of singed values. It was the beginning of this mess.
    
    There was a time when the lower bits is in uint64 but I was
    confused by arithmetics mixing signed and unsigned. I realized
    that I misunderstood composing 64 bit value from decomposition of
    a negative int64.
    
    
    I reconsidered this based on Tom's test program and try to give
    reasoning for the algorithm of the attached new version.
    
    1. Now INT64_AL32 returns explicitly casted into uint64 (for
      safety).  the upper and lower 32 bit values surely makes the
      original value just by INT64_AU32 << 32 + INT64_AL32 because
    
      1.1. The arithmetic is done assuming that both operands of the
         addition are in signed int64 but the MSB of the right
         operand is always 0 so no difference by reading it as
         singed.
    
    - As mentioned in added comment, all terms (stored in the
      variable tmp) are the products of two signed/unsigned 32-bit
      values expanded to singed int64 variables. This is safe.
    
    - The second and third terms should be left-shifted by 32 bit in
      virtually-128-bit storage then added to exiting 128 bit
      value. This can be said as adding INT128_AU64(tmp<<32) into hi
      part. If INT128_AU64(tmp<<32) is equivalent to
      INT64_AU32(tmp)>>32, "span.hi += INT64_AU32(tmp)" is safe.
    
       INT128_AU64(tmp << 32)  ; tmp is assumed signed int128 here
        = ((tmp << 32) >> 64)
        = tmp >>32
        = INT64_AU32(tmp)      ; here, tmp is safe even if singed int64
    
      Similary,
    
       INT128_AL64(tmp << 32)	
        = (uint128)(tmp << 32) & 0xFFFFFFFF_FFFFFFFF  (lower 32 bits are always 0)
        = ((uint64)(tmp) & 0xFFFFFFFF) << 32
        = INT64_AL32(tmp) << 32
    
    - The last thing I should confirm is that
      LINEARINTERVAL_ADD_UINT64 is correct. This is analogous to 1
      above.
    
        (int128)x + (uint64)y
      = (int128)x + (int128)y   ; safely extended without change
      =  (INT128AU64(x) << 64 + INT128AL64(x))
       + (INT128AU64(y) << 64 + INT128AL64(y))
      =  (INT128AU64(x) + INT128AU64(y)) << 64  ; performed as signed
       + (INT128AL64(x) + INT128AL64(y))        ; performed as unsigned
    
      Where (INT128AL64(x) + INT128AL64(y)) is performed as unsigned
      and can be overflow, and the carry can be just pushed to the
      upper 64bit.
    
      2. Adding two values with MSB of 0 doesn't overflow.
    
      3. If at least one of the two has MSB of 1, it can be overflow.
    
      3.1. Both have MSB of 1, it must overflow.
    
      3.2. If one of the two has MSB of 1, the maximum overflowed
         value is made by 0xFFF...FF + 0x7FF...FF and result is
         0x(1)7FF..FE so "MSB of the result is 0" and "overflowed" is
         equivalent for the case.
    
    Addition to all of the above, dayfraction should be positive so
    that LINEARINTERVAL_ADD_UINT64 can be used.
    
    The attached patch is the revised version.
    
    regards,
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  14. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-04-05T19:51:10Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > The attached patch is the revised version.
    
    Hmm, this still isn't right --- testing shows that you had the comparison
    rule right the first time.
    
    Looking at what we've got here, it's already a substantial fraction of
    what would be needed to provide a compiler-independent implementation
    of the int128-based aggregate logic in numeric.c.  With that in mind,
    I propose that we extract the relevant stuff into a new header file
    that is designed as general-purpose int128 support.  Something like the
    attached.  I also attach the test program I put together to verify it.
    
    On my Fedora 25 laptop, it appears that the hand-rolled implementation
    is actually respectably fast compared to gcc's "native" functionality;
    the test program runs in ~2m for 1B iterations with the native logic,
    and ~2.5m with the hand-rolled logic.  Allowing for overhead and the
    fact that we're doing the arithmetic twice, we're probably within 2X
    of the native code.  Not bad at all.
    
    I'm not entirely sure what to do with the test program:
    1. discard it
    2. commit it as utils/adt/int128.c, as suggested in its comment
    3. commit it somewhere else, maybe src/tools/.
    
    Thoughts?
    
    			regards, tom lane
    
    
  15. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-04-05T21:06:53Z

    I wrote:
    > Looking at what we've got here, it's already a substantial fraction of
    > what would be needed to provide a compiler-independent implementation
    > of the int128-based aggregate logic in numeric.c.  With that in mind,
    > I propose that we extract the relevant stuff into a new header file
    > that is designed as general-purpose int128 support.  Something like the
    > attached.  I also attach the test program I put together to verify it.
    
    Here's a fleshed-out patch for the original problem based on that.
    I found that direct int64-to-int128 coercions were also needed to
    handle some of the steps in timestamp.c, so I added those to int128.h.
    
    I think it would be reasonable to back-patch this, although it would
    need some adjustments for the back branches since we only recently
    got rid of the float-timestamp option.  Also I'd not be inclined to
    depend on native int128 any further back than it was already in use.
    
    			regards, tom lane
    
    
  16. Re: Unexpected interval comparison

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> — 2017-04-06T03:07:45Z

    At Wed, 05 Apr 2017 15:51:10 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <27982.1491421870@sss.pgh.pa.us>
    > Hmm, this still isn't right --- testing shows that you had the comparison
    > rule right the first time.
    
    Perhaps Laplaces's deamon is continuously nudging on my head
    toward wrong conclusion, sigh. Sorry for bothering you.
    
    At Wed, 05 Apr 2017 17:06:53 -0400, Tom Lane <tgl@sss.pgh.pa.us> wrote in <385.1491426413@sss.pgh.pa.us>
    > I wrote:
    > > Looking at what we've got here, it's already a substantial fraction of
    > > what would be needed to provide a compiler-independent implementation
    > > of the int128-based aggregate logic in numeric.c.  With that in mind,
    > > I propose that we extract the relevant stuff into a new header file
    > > that is designed as general-purpose int128 support.
    
    +1
    
    > >                                                     Something like the
    > > attached.  I also attach the test program I put together to verify it.
    
    The new patch seems cleaner and fine to me with maybe-fresh eyes.
    
    Since we have some instances of failure cases on non-native
    int128 arithmetic, I'd like to provide regression test for them
    but that seems not so simple.
    
    By the way the adt directory is, as suggested by the name,
    storing files with names of SQL data types so "int128.c" among
    then seems incongruous. Is "int128_test.c" acceptable? int16.c
    will be placed there in case we support int16 or hugeint on SQL.
    
    > Here's a fleshed-out patch for the original problem based on that.
    > I found that direct int64-to-int128 coercions were also needed to
    > handle some of the steps in timestamp.c, so I added those to int128.h.
    > 
    > I think it would be reasonable to back-patch this, although it would
    > need some adjustments for the back branches since we only recently
    > got rid of the float-timestamp option.  Also I'd not be inclined to
    > depend on native int128 any further back than it was already in use.
    
    Back to 9.5 seems reasonable to me.
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
    
    
    
  17. Re: Unexpected interval comparison

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-04-06T03:31:40Z

    Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> writes:
    > By the way the adt directory is, as suggested by the name,
    > storing files with names of SQL data types so "int128.c" among
    > then seems incongruous. Is "int128_test.c" acceptable? int16.c
    > will be placed there in case we support int16 or hugeint on SQL.
    
    After further reflection I've decided to put int128.h in
    src/include/common/, thinking that maybe someday it will be useful
    on client side too.  Also I've changed the test harness file to
    be src/tools/testint128.c, so that it won't be confused with code
    meant to be part of the backend.
    
    > Back to 9.5 seems reasonable to me.
    
    I poked around and noticed that before 9.4, we did not attempt
    to guard against overflows in interval calculations at all.
    So backpatch to 9.4 seems pretty defensible.  The non-HAVE_INT128
    code works fine in 9.4.
    
    I've just about finished adjusting the patch for the back
    branches, and will push in a little bit.
    
    			regards, tom lane