From 3745790f53bc5dd87b2df3d5a0c9c62d7ff0360d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 20 Oct 2026 15:13:34 -0400 Subject: [PATCH] contrib/intarray: always parse query_int integers as decimal. Previously we called strtol() with base 0, so that a leading zero digit caused the number to be read as octal. This is not documented because it was not the original intent: before commit 7ccb6dc2d, this code used atoi() which would have read the number as decimal always. Use base 10 instead to restore the original behavior. Also reject a bare minus sign consistently. Per POSIX, strtol() "may" set errno for that case but doesn't have to, and if it doesn't then we'd not have noticed the bad syntax but read the value as 0. Although this change restores old behavior, 7ccb6dc2d was a long time ago, so it's at least possible that someone out there is expecting the octal behavior. So it doesn't seem like a great idea to put this into stable branches. But I (tgl) judge it not too late for v19. Author: Marko Grujic Reviewed-by: Manu Reviewed-by: Tom Lane Discussion: https://postgr.es/m/CAOvwyF3=brZoxwcwHRQqvLjuqSqxiTN7RXpKMNHXJ1WAS5GQ2Q@mail.gmail.com Backpatch-through: 19 --- contrib/intarray/_int_bool.c | 5 +++-- contrib/intarray/expected/_int.out | 10 ++++++++++ contrib/intarray/sql/_int.sql | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c index 4382f882939..abac3ced433 100644 --- a/contrib/intarray/_int_bool.c +++ b/contrib/intarray/_int_bool.c @@ -90,12 +90,13 @@ gettoken(WORKSTATE *state, int32 *val) else { long lval; + char *endptr; nnn[innn] = '\0'; errno = 0; - lval = strtol(nnn, NULL, 0); + lval = strtol(nnn, &endptr, 10); *val = (int32) lval; - if (errno != 0 || (long) *val != lval) + if (errno != 0 || *endptr != '\0' || (long) *val != lval) return ERR; state->state = WAITOPERATOR; return (state->count && *(state->buf) == '\0') diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index fb4086a95ca..4a2ecba8081 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -398,6 +398,16 @@ SELECT '1&(2&(4&(5|!6)))'::query_int; 1 & 2 & 4 & ( 5 | !6 ) (1 row) +SELECT '010'::query_int; -- decimal, not octal + query_int +----------- + 10 +(1 row) + +SELECT '-'::query_int; -- syntax error +ERROR: syntax error +LINE 1: SELECT '-'::query_int; + ^ -- Test for overflow of the int16 "left" field in findoprnd(). -- This query uses a balanced binary tree to avoid using too much stack. DO $$ diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index 0d30914725e..7a1d07e15d1 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -74,6 +74,8 @@ SELECT '1&(2&(4&(5&6)))'::query_int; SELECT '1&2&4&5&6'::query_int; SELECT '1&(2&(4&(5|6)))'::query_int; SELECT '1&(2&(4&(5|!6)))'::query_int; +SELECT '010'::query_int; -- decimal, not octal +SELECT '-'::query_int; -- syntax error -- Test for overflow of the int16 "left" field in findoprnd(). -- This query uses a balanced binary tree to avoid using too much stack.