Re: refactoring - share str2*int64 functions - Mailing list pgsql-hackers

From Andres Freund
Subject Re: refactoring - share str2*int64 functions
Date
Msg-id 20190717184820.iqz7schxdbucmdmu@alap3.anarazel.de
Whole thread Raw
In response to Re: refactoring - share str2*int64 functions  (Michael Paquier <michael@paquier.xyz>)
List pgsql-hackers
Hi,

On 2019-07-17 17:29:58 +0900, Michael Paquier wrote:
> Actually, one thing which may be a problem is that we lack currently
> the equivalents of pg_mul_s16_overflow and such for unsigned
> integers.

It's much simpler to implement them for unsigned than for signed,
because unsigned overflow is well-defined. So I'd not be particularly
worried about just adding them.  E.g. comparing the "slow" version of
pg_mul_s64_overflow() with an untested implementation of
pg_mul_u64_overflow():

pg_mul_s64_overflow:
    /*
     * Overflow can only happen if at least one value is outside the range
     * sqrt(min)..sqrt(max) so check that first as the division can be quite a
     * bit more expensive than the multiplication.
     *
     * Multiplying by 0 or 1 can't overflow of course and checking for 0
     * separately avoids any risk of dividing by 0.  Be careful about dividing
     * INT_MIN by -1 also, note reversing the a and b to ensure we're always
     * dividing it by a positive value.
     *
     */
    if ((a > PG_INT32_MAX || a < PG_INT32_MIN ||
         b > PG_INT32_MAX || b < PG_INT32_MIN) &&
        a != 0 && a != 1 && b != 0 && b != 1 &&
        ((a > 0 && b > 0 && a > PG_INT64_MAX / b) ||
         (a > 0 && b < 0 && b < PG_INT64_MIN / a) ||
         (a < 0 && b > 0 && a < PG_INT64_MIN / b) ||
         (a < 0 && b < 0 && a < PG_INT64_MAX / b)))
    {
        *result = 0x5EED;        /* to avoid spurious warnings */
        return true;
    }
    *result = a * b;
    return false;

pg_mul_s64_overflow:

        /*
         * Checking for unsigned overflow is simple, just check
         * if reversing the multiplication indicates that the
         * multiplication overflowed.
         */
        int64 res = a * b;
        if (a != 0 && b != res / a)
        {
        *result = 0x5EED;        /* to avoid spurious warnings */
        return true;
    }
    *result = res;
    return false;


The cases for addition/subtraction are even easier:
addition:
res = a + b;
if (res < a)
   /* overflow */

subtraction:
if (a < b)
   /* underflow */
res  = a - b;

Greetings,

Andres Freund



pgsql-hackers by date:

Previous
From: Sergei Kornilov
Date:
Subject: Re: Change ereport level for QueuePartitionConstraintValidation
Next
From: Darafei "Komяpa" Praliaskouski
Date:
Subject: Unwanted expression simplification in PG12b2