BUG #1608: integer negative limit in plpgsql function arguments

Started by Paulalmost 21 years ago4 messagesbugs
Jump to latest
#1Paul
paul@allinea.com

The following bug has been logged online:

Bug reference: 1608
Logged by: Paul
Email address: paul@allinea.com
PostgreSQL version: 8.0.2
Operating system: Gentoo and Fedora Core 3
Description: integer negative limit in plpgsql function arguments
Details:

The script below best sums up the problem (and the work around). The
question is: should I use that for all integers being put into a function?

8<--------------------------------------------

create table test (
test_id integer
);

insert into test (test_id) values (-2147483648);

create function print_test_id (integer) returns integer
AS '
DECLARE
tmp ALIAS FOR $1;
val integer;
BEGIN
select into val test_id from test where test_id = tmp;
return val;
END;
'
LANGUAGE plpgsql;

-- this doesn't work (and I think it should!)
SELECT print_test_id(-2147483648);

-- this is the workaround
SELECT print_test_id((-2147483648)::int);

-------------------------------------------->8

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Paul (#1)
Re: BUG #1608: integer negative limit in plpgsql function arguments

"Paul" <paul@allinea.com> writes:

-- this doesn't work (and I think it should!)
SELECT print_test_id(-2147483648);

"2147483648" isn't an integer constant; it's int8, and therefore so
is the result of the minus operator. Sorry, this isn't going to
change.

regards, tom lane

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Paul (#1)
Re: BUG #1608: integer negative limit in plpgsql function arguments

Paul Edwards <paul@allinea.com> writes:

Also, just as an experiment I tried the minimum limit for bigint (see
attached file). It seems that I do not need to cast for negative limit
which is inconsistent since 9223372036854775808 is not a bigint (when
-9223372036854775808 is). Therefore the type wasn't necessarily
determined before the unary operator.

Really? [ tries it ... then reads some code ... ]

You're right, we do cheat a little on negative numeric constants --- I
had forgotten about the doNegate() hack in gram.y.  We could conceivably
fix it to cheat some more.  Specifically it looks like make_const() in
parse_node.c could check for the possibility that a T_Float fits in INT4
--- which would happen only for the case of -2147483648, since any
smaller absolute value would have been T_Integer to start with.

This also brings up the thought that maybe the T_Integer case should
create an INT2 rather than INT4 Const if the value is small enough.
I'm fairly hesitant to do that though because it would be a significant
change in behavior, possibly breaking apps that don't have a problem
now. (IIRC we experimented with such a change some years back and saw
widespread failures in the regression tests, for example.)

However changing the behavior only for -2147483648 seems like a
relatively safe thing to do.

Thoughts, objections anyone?

regards, tom lane

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#3)
Re: BUG #1608: integer negative limit in plpgsql function arguments

I wrote:

You're right, we do cheat a little on negative numeric constants --- I
had forgotten about the doNegate() hack in gram.y.  We could conceivably
fix it to cheat some more.  Specifically it looks like make_const() in
parse_node.c could check for the possibility that a T_Float fits in INT4
--- which would happen only for the case of -2147483648, since any
smaller absolute value would have been T_Integer to start with.

I've applied the attached patch to CVS HEAD. I'm not going to risk
back-patching this, but feel free to use the patch locally if it's
important to you.

regards, tom lane

*** src/backend/parser/parse_node.c.orig	Fri Dec 31 17:45:55 2004
--- src/backend/parser/parse_node.c	Sat Apr 23 14:28:03 2005
***************
*** 304,314 ****
  			/* could be an oversize integer as well as a float ... */
  			if (scanint8(strVal(value), true, &val64))
  			{
! 				val = Int64GetDatum(val64);
! 				typeid = INT8OID;
! 				typelen = sizeof(int64);
! 				typebyval = false;		/* XXX might change someday */
  			}
  			else
  			{
--- 304,331 ----
  			/* could be an oversize integer as well as a float ... */
  			if (scanint8(strVal(value), true, &val64))
  			{
! 				/*
! 				 * It might actually fit in int32. Probably only INT_MIN can
! 				 * occur, but we'll code the test generally just to be sure.
! 				 */
! 				int32	val32 = (int32) val64;

! if (val64 == (int64) val32)
! {
! val = Int32GetDatum(val32);
!
! typeid = INT4OID;
! typelen = sizeof(int32);
! typebyval = true;
! }
! else
! {
! val = Int64GetDatum(val64);
!
! typeid = INT8OID;
! typelen = sizeof(int64);
! typebyval = false; /* XXX might change someday */
! }
}
else
{