From: Nathan Bossart <nathandbossart@gmail.com>
To: Alexander Lakhin <exclusion@gmail.com>
Cc: Joseph Koshakow <koshy44@gmail.com>
Cc: jian he <jian.universality@gmail.com>
Cc: Heikki Linnakangas <hlinnaka@iki.fi>
Cc: Matthew Kim <matthewkmkim@gmail.com>
Cc: Tom Lane <tgl@sss.pgh.pa.us>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Cc: Andres Freund <andres@anarazel.de>
Subject: Re: Remove dependence on integer wrapping
Date: Tue, 20 Aug 2024 16:21:33 -0500
Message-ID: <ZsUI3QJdUOIpPkZ5@nathan> (raw)
In-Reply-To: <e5d3f013-e206-835c-0c08-53c786b098f2@gmail.com>
References: <Zr5M3KxOZlEZRZIN@nathan>
<Zr50ZpSyrBx0EHfR@nathan>
<CAAvxfHfkHS1n0+wMbtKwj6_GE6+aSJ9JjnsCOOdZPhTKRs-Yhw@mail.gmail.com>
<Zr-DwBxep-IaayQF@nathan>
<bfff906f-300d-81ea-83b7-f2c93845e7f2@gmail.com>
<Zr-b1c6x-Yf31TCZ@nathan>
<Zr-yiLatqDlen3oH@nathan>
<CAAvxfHd43nT6Va20wgftJ9XQuNPpmYSjR4WRc1jxTv=U4qOZgg@mail.gmail.com>
<CAAvxfHeWeETpiwxn11NvWkWd4o0curubg4cTXuk6yOGtixzAdg@mail.gmail.com>
<e5d3f013-e206-835c-0c08-53c786b098f2@gmail.com>
I've combined all the current proposed changes into one patch. I've also
introduced signed versions of the negation functions into int.h to avoid
relying on multiplication.
--
nathan
From 2364ba4028f879a22b9f69f999aee3ea9c013ec0 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Tue, 20 Aug 2024 16:12:39 -0500
Subject: [PATCH v26 1/1] Remove dependence on -fwrapv semantics in more
places.
---
src/backend/nodes/bitmapset.c | 2 +-
src/backend/utils/adt/date.c | 6 +++-
src/backend/utils/adt/formatting.c | 28 +++++++++++++--
src/backend/utils/hash/dynahash.c | 6 ++--
src/include/common/int.h | 48 ++++++++++++++++++++++++++
src/test/regress/expected/date.out | 2 ++
src/test/regress/expected/horology.out | 4 +++
src/test/regress/expected/union.out | 43 +++++++++++++++++++++++
src/test/regress/sql/date.sql | 1 +
src/test/regress/sql/horology.sql | 2 ++
src/test/regress/sql/union.sql | 9 +++++
11 files changed, 143 insertions(+), 8 deletions(-)
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.cindex cd05c642b0..d37a997c0e 100644--- a/src/backend/nodes/bitmapset.c+++ b/src/backend/nodes/bitmapset.c@@ -67,7 +67,7 @@
* we get zero.
*----------
*/
-#define RIGHTMOST_ONE(x) ((signedbitmapword) (x) & -((signedbitmapword) (x)))+#define RIGHTMOST_ONE(x) ((bitmapword) (x) & (~((bitmapword) (x)) + 1))
#define HAS_MULTIPLE_ONES(x) ((bitmapword) RIGHTMOST_ONE(x) != (x))
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.cindex 9c854e0e5c..0782e84776 100644--- a/src/backend/utils/adt/date.c+++ b/src/backend/utils/adt/date.c@@ -257,7 +257,11 @@ make_date(PG_FUNCTION_ARGS)
if (tm.tm_year < 0)
{
bc = true;
- tm.tm_year = -tm.tm_year;+ if (pg_neg_s32_overflow(tm.tm_year, &tm.tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),+ errmsg("date field value out of range: %d-%02d-%02d",+ tm.tm_year, tm.tm_mon, tm.tm_mday)));
}
dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.cindex 68069fcfd3..76bb3a79b5 100644--- a/src/backend/utils/adt/formatting.c+++ b/src/backend/utils/adt/formatting.c@@ -77,6 +77,7 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
+#include "common/int.h"
#include "common/unicode_case.h"
#include "common/unicode_category.h"
#include "mb/pg_wchar.h"
@@ -3809,7 +3810,12 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out,
ereturn(escontext,,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input string for \"Y,YYY\"")));
- years += (millennia * 1000);+ if (pg_mul_s32_overflow(millennia, 1000, &millennia) ||+ pg_add_s32_overflow(years, millennia, &years))+ ereturn(escontext,,+ (errcode(ERRCODE_INVALID_DATETIME_FORMAT),+ errmsg("invalid input string for \"Y,YYY\"")));+
if (!from_char_set_int(&out->year, years, n, escontext))
return;
out->yysz = 4;
@@ -4797,11 +4803,27 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
if (tmfc.bc)
tmfc.cc = -tmfc.cc;
if (tmfc.cc >= 0)
+ {
/* +1 because 21st century started in 2001 */
- tm->tm_year = (tmfc.cc - 1) * 100 + 1;+ /* tm->tm_year = (tmfc.cc - 1) * 100 + 1 */+ if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||+ pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),+ errmsg("date out of range: \"%s\"",+ text_to_cstring(date_txt))));+ }
else
+ {
/* +1 because year == 599 is 600 BC */
- tm->tm_year = tmfc.cc * 100 + 1;+ /* tm->tm_year = tmfc.cc * 100 + 1 */+ if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||+ pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),+ errmsg("date out of range: \"%s\"",+ text_to_cstring(date_txt))));+ }
fmask |= DTK_M(YEAR);
}
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.cindex 5d9c62b652..ee2bbe5dc8 100644--- a/src/backend/utils/hash/dynahash.c+++ b/src/backend/utils/hash/dynahash.c@@ -717,7 +717,7 @@ init_htab(HTAB *hashp, long nelem)
nbuckets <<= 1;
hctl->max_bucket = hctl->low_mask = nbuckets - 1;
- hctl->high_mask = (nbuckets << 1) - 1;+ hctl->high_mask = ((uint32) nbuckets << 1) - 1;
/*
* Figure number of directory segments needed, round up to a power of 2
@@ -1819,8 +1819,8 @@ next_pow2_long(long num)
static int
next_pow2_int(long num)
{
- if (num > INT_MAX / 2)- num = INT_MAX / 2;+ if (num > INT_MAX / 2 + 1)+ num = INT_MAX / 2 + 1;
return 1 << my_log2(num);
}
diff --git a/src/include/common/int.h b/src/include/common/int.hindex 3b1590d676..6b50aa67b9 100644--- a/src/include/common/int.h+++ b/src/include/common/int.h@@ -117,6 +117,22 @@ pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
#endif
}
+static inline bool+pg_neg_s16_overflow(int16 a, int16 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT16_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint16
pg_abs_s16(int16 a)
{
@@ -185,6 +201,22 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
#endif
}
+static inline bool+pg_neg_s32_overflow(int32 a, int32 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT32_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint32
pg_abs_s32(int32 a)
{
@@ -300,6 +332,22 @@ pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
#endif
}
+static inline bool+pg_neg_s64_overflow(int64 a, int64 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT64_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint64
pg_abs_s64(int64 a)
{
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.outindex f5949f3d17..c8f76c205d 100644--- a/src/test/regress/expected/date.out+++ b/src/test/regress/expected/date.out@@ -1532,3 +1532,5 @@ select make_time(10, 55, 100.1);
ERROR: time field value out of range: 10:55:100.1
select make_time(24, 0, 2.1);
ERROR: time field value out of range: 24:00:2.1
+SELECT make_date(-2147483648, 1, 1);+ERROR: date field value out of range: -2147483648-01-01diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.outindex 241713cc51..df02d268c0 100644--- a/src/test/regress/expected/horology.out+++ b/src/test/regress/expected/horology.out@@ -3448,6 +3448,8 @@ SELECT i, to_timestamp('2018-11-02 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'
SELECT i, to_timestamp('2018-11-02 12:34:56.123456789', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
ERROR: date/time field value out of range: "2018-11-02 12:34:56.123456789"
+SELECT to_timestamp('1000000000,999', 'Y,YYY');+ERROR: invalid input string for "Y,YYY"
SELECT to_date('1 4 1902', 'Q MM YYYY'); -- Q is ignored
to_date
------------
@@ -3778,6 +3780,8 @@ SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
02-01-0001 BC
(1 row)
+SELECT to_date('100000000', 'CC');+ERROR: date out of range: "100000000"
-- to_char's TZ format code produces zone abbrev if known
SELECT to_char('2012-12-12 12:00'::timestamptz, 'YYYY-MM-DD HH:MI:SS TZ');
to_char
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.outindex 0fd0e1c38b..444744848e 100644--- a/src/test/regress/expected/union.out+++ b/src/test/regress/expected/union.out@@ -59,6 +59,49 @@ SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1;
2.2
(2 rows)
+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;+ ?column? +----------+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+(31 rows)+
-- Mixed types
SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1;
two
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sqlindex 1c58ff6966..9a4e5832b9 100644--- a/src/test/regress/sql/date.sql+++ b/src/test/regress/sql/date.sql@@ -373,3 +373,4 @@ select make_date(2013, 13, 1);
select make_date(2013, 11, -1);
select make_time(10, 55, 100.1);
select make_time(24, 0, 2.1);
+SELECT make_date(-2147483648, 1, 1);diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sqlindex e5cf12ff63..db532ee3c0 100644--- a/src/test/regress/sql/horology.sql+++ b/src/test/regress/sql/horology.sql@@ -558,6 +558,7 @@ SELECT i, to_timestamp('2018-11-02 12:34:56.1234', 'YYYY-MM-DD HH24:MI:SS.FF' ||
SELECT i, to_timestamp('2018-11-02 12:34:56.12345', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
SELECT i, to_timestamp('2018-11-02 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
SELECT i, to_timestamp('2018-11-02 12:34:56.123456789', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
+SELECT to_timestamp('1000000000,999', 'Y,YYY');
SELECT to_date('1 4 1902', 'Q MM YYYY'); -- Q is ignored
SELECT to_date('3 4 21 01', 'W MM CC YY');
@@ -660,6 +661,7 @@ SELECT to_date('2016 365', 'YYYY DDD'); -- ok
SELECT to_date('2016 366', 'YYYY DDD'); -- ok
SELECT to_date('2016 367', 'YYYY DDD');
SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
+SELECT to_date('100000000', 'CC');
-- to_char's TZ format code produces zone abbrev if known
SELECT to_char('2012-12-12 12:00'::timestamptz, 'YYYY-MM-DD HH:MI:SS TZ');
diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sqlindex f8826514e4..e1954a92d2 100644--- a/src/test/regress/sql/union.sql+++ b/src/test/regress/sql/union.sql@@ -20,6 +20,15 @@ SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1;
SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1;
+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;+
-- Mixed types
SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1;
--
2.39.3 (Apple Git-146)
Attachments:
[text/plain] v26-0001-Remove-dependence-on-fwrapv-semantics-in-more-pl.patch (11.4K, ../ZsUI3QJdUOIpPkZ5@nathan/2-v26-0001-Remove-dependence-on-fwrapv-semantics-in-more-pl.patch)
download | inline diff:
From 2364ba4028f879a22b9f69f999aee3ea9c013ec0 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Tue, 20 Aug 2024 16:12:39 -0500
Subject: [PATCH v26 1/1] Remove dependence on -fwrapv semantics in more
places.
---
src/backend/nodes/bitmapset.c | 2 +-
src/backend/utils/adt/date.c | 6 +++-
src/backend/utils/adt/formatting.c | 28 +++++++++++++--
src/backend/utils/hash/dynahash.c | 6 ++--
src/include/common/int.h | 48 ++++++++++++++++++++++++++
src/test/regress/expected/date.out | 2 ++
src/test/regress/expected/horology.out | 4 +++
src/test/regress/expected/union.out | 43 +++++++++++++++++++++++
src/test/regress/sql/date.sql | 1 +
src/test/regress/sql/horology.sql | 2 ++
src/test/regress/sql/union.sql | 9 +++++
11 files changed, 143 insertions(+), 8 deletions(-)
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.cindex cd05c642b0..d37a997c0e 100644--- a/src/backend/nodes/bitmapset.c+++ b/src/backend/nodes/bitmapset.c@@ -67,7 +67,7 @@
* we get zero.
*----------
*/
-#define RIGHTMOST_ONE(x) ((signedbitmapword) (x) & -((signedbitmapword) (x)))+#define RIGHTMOST_ONE(x) ((bitmapword) (x) & (~((bitmapword) (x)) + 1))
#define HAS_MULTIPLE_ONES(x) ((bitmapword) RIGHTMOST_ONE(x) != (x))
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.cindex 9c854e0e5c..0782e84776 100644--- a/src/backend/utils/adt/date.c+++ b/src/backend/utils/adt/date.c@@ -257,7 +257,11 @@ make_date(PG_FUNCTION_ARGS)
if (tm.tm_year < 0)
{
bc = true;
- tm.tm_year = -tm.tm_year;+ if (pg_neg_s32_overflow(tm.tm_year, &tm.tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),+ errmsg("date field value out of range: %d-%02d-%02d",+ tm.tm_year, tm.tm_mon, tm.tm_mday)));
}
dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.cindex 68069fcfd3..76bb3a79b5 100644--- a/src/backend/utils/adt/formatting.c+++ b/src/backend/utils/adt/formatting.c@@ -77,6 +77,7 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
+#include "common/int.h"
#include "common/unicode_case.h"
#include "common/unicode_category.h"
#include "mb/pg_wchar.h"
@@ -3809,7 +3810,12 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out,
ereturn(escontext,,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input string for \"Y,YYY\"")));
- years += (millennia * 1000);+ if (pg_mul_s32_overflow(millennia, 1000, &millennia) ||+ pg_add_s32_overflow(years, millennia, &years))+ ereturn(escontext,,+ (errcode(ERRCODE_INVALID_DATETIME_FORMAT),+ errmsg("invalid input string for \"Y,YYY\"")));+
if (!from_char_set_int(&out->year, years, n, escontext))
return;
out->yysz = 4;
@@ -4797,11 +4803,27 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
if (tmfc.bc)
tmfc.cc = -tmfc.cc;
if (tmfc.cc >= 0)
+ {
/* +1 because 21st century started in 2001 */
- tm->tm_year = (tmfc.cc - 1) * 100 + 1;+ /* tm->tm_year = (tmfc.cc - 1) * 100 + 1 */+ if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||+ pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),+ errmsg("date out of range: \"%s\"",+ text_to_cstring(date_txt))));+ }
else
+ {
/* +1 because year == 599 is 600 BC */
- tm->tm_year = tmfc.cc * 100 + 1;+ /* tm->tm_year = tmfc.cc * 100 + 1 */+ if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||+ pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))+ ereport(ERROR,+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),+ errmsg("date out of range: \"%s\"",+ text_to_cstring(date_txt))));+ }
fmask |= DTK_M(YEAR);
}
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.cindex 5d9c62b652..ee2bbe5dc8 100644--- a/src/backend/utils/hash/dynahash.c+++ b/src/backend/utils/hash/dynahash.c@@ -717,7 +717,7 @@ init_htab(HTAB *hashp, long nelem)
nbuckets <<= 1;
hctl->max_bucket = hctl->low_mask = nbuckets - 1;
- hctl->high_mask = (nbuckets << 1) - 1;+ hctl->high_mask = ((uint32) nbuckets << 1) - 1;
/*
* Figure number of directory segments needed, round up to a power of 2
@@ -1819,8 +1819,8 @@ next_pow2_long(long num)
static int
next_pow2_int(long num)
{
- if (num > INT_MAX / 2)- num = INT_MAX / 2;+ if (num > INT_MAX / 2 + 1)+ num = INT_MAX / 2 + 1;
return 1 << my_log2(num);
}
diff --git a/src/include/common/int.h b/src/include/common/int.hindex 3b1590d676..6b50aa67b9 100644--- a/src/include/common/int.h+++ b/src/include/common/int.h@@ -117,6 +117,22 @@ pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
#endif
}
+static inline bool+pg_neg_s16_overflow(int16 a, int16 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT16_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint16
pg_abs_s16(int16 a)
{
@@ -185,6 +201,22 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
#endif
}
+static inline bool+pg_neg_s32_overflow(int32 a, int32 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT32_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint32
pg_abs_s32(int32 a)
{
@@ -300,6 +332,22 @@ pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
#endif
}
+static inline bool+pg_neg_s64_overflow(int64 a, int64 *result)+{+#if defined(HAVE__BUILTIN_OP_OVERFLOW)+ return __builtin_sub_overflow(0, a, result);+#else+ if (unlikely(a == PG_INT64_MIN))+ {+ *result = 0x5EED; /* to avoid spurious warnings */+ return true;+ }+ *result = -a;+ return false;+#endif+}+
static inline uint64
pg_abs_s64(int64 a)
{
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.outindex f5949f3d17..c8f76c205d 100644--- a/src/test/regress/expected/date.out+++ b/src/test/regress/expected/date.out@@ -1532,3 +1532,5 @@ select make_time(10, 55, 100.1);
ERROR: time field value out of range: 10:55:100.1
select make_time(24, 0, 2.1);
ERROR: time field value out of range: 24:00:2.1
+SELECT make_date(-2147483648, 1, 1);+ERROR: date field value out of range: -2147483648-01-01diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.outindex 241713cc51..df02d268c0 100644--- a/src/test/regress/expected/horology.out+++ b/src/test/regress/expected/horology.out@@ -3448,6 +3448,8 @@ SELECT i, to_timestamp('2018-11-02 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'
SELECT i, to_timestamp('2018-11-02 12:34:56.123456789', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
ERROR: date/time field value out of range: "2018-11-02 12:34:56.123456789"
+SELECT to_timestamp('1000000000,999', 'Y,YYY');+ERROR: invalid input string for "Y,YYY"
SELECT to_date('1 4 1902', 'Q MM YYYY'); -- Q is ignored
to_date
------------
@@ -3778,6 +3780,8 @@ SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
02-01-0001 BC
(1 row)
+SELECT to_date('100000000', 'CC');+ERROR: date out of range: "100000000"
-- to_char's TZ format code produces zone abbrev if known
SELECT to_char('2012-12-12 12:00'::timestamptz, 'YYYY-MM-DD HH:MI:SS TZ');
to_char
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.outindex 0fd0e1c38b..444744848e 100644--- a/src/test/regress/expected/union.out+++ b/src/test/regress/expected/union.out@@ -59,6 +59,49 @@ SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1;
2.2
(2 rows)
+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;+ ?column? +----------+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+(31 rows)+
-- Mixed types
SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1;
two
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sqlindex 1c58ff6966..9a4e5832b9 100644--- a/src/test/regress/sql/date.sql+++ b/src/test/regress/sql/date.sql@@ -373,3 +373,4 @@ select make_date(2013, 13, 1);
select make_date(2013, 11, -1);
select make_time(10, 55, 100.1);
select make_time(24, 0, 2.1);
+SELECT make_date(-2147483648, 1, 1);diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sqlindex e5cf12ff63..db532ee3c0 100644--- a/src/test/regress/sql/horology.sql+++ b/src/test/regress/sql/horology.sql@@ -558,6 +558,7 @@ SELECT i, to_timestamp('2018-11-02 12:34:56.1234', 'YYYY-MM-DD HH24:MI:SS.FF' ||
SELECT i, to_timestamp('2018-11-02 12:34:56.12345', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
SELECT i, to_timestamp('2018-11-02 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
SELECT i, to_timestamp('2018-11-02 12:34:56.123456789', 'YYYY-MM-DD HH24:MI:SS.FF' || i) FROM generate_series(1, 6) i;
+SELECT to_timestamp('1000000000,999', 'Y,YYY');
SELECT to_date('1 4 1902', 'Q MM YYYY'); -- Q is ignored
SELECT to_date('3 4 21 01', 'W MM CC YY');
@@ -660,6 +661,7 @@ SELECT to_date('2016 365', 'YYYY DDD'); -- ok
SELECT to_date('2016 366', 'YYYY DDD'); -- ok
SELECT to_date('2016 367', 'YYYY DDD');
SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
+SELECT to_date('100000000', 'CC');
-- to_char's TZ format code produces zone abbrev if known
SELECT to_char('2012-12-12 12:00'::timestamptz, 'YYYY-MM-DD HH:MI:SS TZ');
diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sqlindex f8826514e4..e1954a92d2 100644--- a/src/test/regress/sql/union.sql+++ b/src/test/regress/sql/union.sql@@ -20,6 +20,15 @@ SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1;
SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1;
+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL+SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;+
-- Mixed types
SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1;
--
2.39.3 (Apple Git-146)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: nathandbossart@gmail.com, exclusion@gmail.com, koshy44@gmail.com, jian.universality@gmail.com, hlinnaka@iki.fi, matthewkmkim@gmail.com, tgl@sss.pgh.pa.us, pgsql-hackers@lists.postgresql.org, andres@anarazel.de
Subject: Re: Remove dependence on integer wrapping
In-Reply-To: <ZsUI3QJdUOIpPkZ5@nathan>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox