BUG #13805: plpgsql execute using expression evaluate wrong

Started by Jovover 10 years ago6 messagesbugs
Jump to latest
#1Jov
amutu@amutu.com

The following bug has been logged on the website:

Bug reference: 13805
Logged by: Jov
Email address: amutu@amutu.com
PostgreSQL version: 9.4.5
Operating system: CentOS 6
Description:

test case:

CREATE OR REPLACE FUNCTION public.test()
RETURNS void
LANGUAGE plpgsql
AS $function$
declare
n int = 4;
rt timestamp[];
rt2 interval;
begin
execute $$select array_agg(g.i) from generate_series(now() - ('$1
month')::interval,now(),'1 month') g(i)$$ into r
t using n;
raise notice 'rt : %',rt;

execute $$select array_agg(g.i) from generate_series(now() - ($1::varchar ||
' month')::interval,now(),'1 month')
g(i)$$ into rt using n;
raise notice 'rt : %',rt;

execute $$select ('$1 month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;

execute $$select ($1::varchar || ' month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;
end;

$function$
~
~
No changes
db_001=# select * from test();
NOTICE: rt : {"2015-11-08 11:46:28.500811","2015-12-08
11:46:28.500811"}-----wrong answer,should 4 elements
NOTICE: rt : {"2015-08-08 11:46:28.500811","2015-09-08
11:46:28.500811","2015-10-08 11:46:28.500811","2015-11-08
11:46:28.500811","2015-12-08 11:46:28.500811"}
NOTICE: rt2 : 1 mon-----wrong,should 4 mons
NOTICE: rt2 : 4 mons
test
------

(1 row)

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#2daveg
daveg@sonic.net
In reply to: Jov (#1)
Re: BUG #13805: plpgsql execute using expression evaluate wrong

On Tue, 08 Dec 2015 03:54:44 +0000
amutu@amutu.com wrote:

execute $$select ('$1 month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;

execute $$select ($1::varchar || ' month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;
end;

NOTICE: rt2 : 1 mon-----wrong,should 4 mons
NOTICE: rt2 : 4 mons

You may have found a bug, but if so, it is not where you think it is. The
expression: '$1 month' is a text literal. PL/PGsql does not interpolate $n
like a shell, it only does the substitution where a variable could
ordinarily exist.

However, it does seem a little odd that the literal syntax for
intervals accepts the '$':

postgres=# select '$1 month'::interval, '$4 month'::interval;
interval | interval
----------+----------
1 mon | 4 mons
(1 row)

I would have expected it to raise an error. The documentation does not shed
any light on this. Anyone?

-dg

--
David Gould 510 282 0869 daveg@sonic.net
If simplicity worked, the world would be overrun with insects.

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#3Jov
amutu@amutu.com
In reply to: daveg (#2)
Re: BUG #13805: plpgsql execute using expression evaluate wrong

Yes,I think this trigger an error is reasonable.It take me 2 hours to find
the problem,not friendly.

Jov
blog: http:amutu.com/blog <http://amutu.com/blog&gt;

2015-12-08 14:08 GMT+08:00 David Gould <daveg@sonic.net>:

Show quoted text

On Tue, 08 Dec 2015 03:54:44 +0000
amutu@amutu.com wrote:

execute $$select ('$1 month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;

execute $$select ($1::varchar || ' month')::interval $$ into rt2 using n;
raise notice 'rt2 : %',rt2;
end;

NOTICE: rt2 : 1 mon-----wrong,should 4 mons
NOTICE: rt2 : 4 mons

You may have found a bug, but if so, it is not where you think it is. The
expression: '$1 month' is a text literal. PL/PGsql does not interpolate $n
like a shell, it only does the substitution where a variable could
ordinarily exist.

However, it does seem a little odd that the literal syntax for
intervals accepts the '$':

postgres=# select '$1 month'::interval, '$4 month'::interval;
interval | interval
----------+----------
1 mon | 4 mons
(1 row)

I would have expected it to raise an error. The documentation does not shed
any light on this. Anyone?

-dg

--
David Gould 510 282 0869 daveg@sonic.net
If simplicity worked, the world would be overrun with insects.

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: daveg (#2)
Re: BUG #13805: plpgsql execute using expression evaluate wrong

David Gould <daveg@sonic.net> writes:

However, it does seem a little odd that the literal syntax for
intervals accepts the '$':
...
I would have expected it to raise an error. The documentation does not shed
any light on this. Anyone?

The datetime input parser tends to consider most non-alphanumeric
characters as being insignificant except as field separators. We could
tighten that up, but I think we should tread pretty carefully for fear of
breaking cases that used to work. A trivial example:

regression=# select '1 mon 1 day'::interval;
interval
-------------
1 mon 1 day
(1 row)

regression=# select '1 mon, 1 day'::interval;
interval
-------------
1 mon 1 day
(1 row)

If we started to reject the second case, we'd likely get complaints.
But the parser doesn't see that as any different from

regression=# select '1 mon$ 1 day'::interval;
interval
-------------
1 mon 1 day
(1 row)

Trying to decide which characters are legitimate noise and which
aren't seems like a tarbaby best not to get stuck to :-(

regards, tom lane

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#5daveg
daveg@sonic.net
In reply to: Tom Lane (#4)
Re: BUG #13805: plpgsql execute using expression evaluate wrong

On Tue, 08 Dec 2015 01:36:39 -0500
Tom Lane <tgl@sss.pgh.pa.us> wrote:

The datetime input parser tends to consider most non-alphanumeric
characters as being insignificant except as field separators. We could
tighten that up, but I think we should tread pretty carefully for fear of
breaking cases that used to work. A trivial example:

...

regression=# select '1 mon$ 1 day'::interval;
interval
-------------
1 mon 1 day
(1 row)

Trying to decide which characters are legitimate noise and which
aren't seems like a tarbaby best not to get stuck to :-(

# select '#!1!#month,?=~&(12$[day*() '::interval;
interval
---------------
1 mon 12 days
(1 row)

I feel so ... dirty....

-dg

--
David Gould 510 282 0869 daveg@sonic.net
If simplicity worked, the world would be overrun with insects.

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#6Terje Elde
terje@elde.net
In reply to: Tom Lane (#4)
Re: BUG #13805: plpgsql execute using expression evaluate wrong

On 08 Dec 2015, at 07:36, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Trying to decide which characters are legitimate noise and which
aren't seems like a tarbaby best not to get stuck to :-(

I'd like to argue that if you need PostgreSQL-native time from a string, and want more control and verification, that's probably something that's best left to the application anyway.

I fail to see how PostgreSQL can reasonably be made to be "perfect" for all possible cases of dirty input being casted to interval.

The application is in a much better position to deal with this, presumably knowing more about the input, and being a cleaner place to put any parsing and handling.

From there, it can be passed to PostgreSQL either as a native interval object, or a cleaned up string.

In other words, I agree about not changing the behavior.

That said, I do wonder if it could be worthwhile to consider having an option to trigger a notice or error upon dirty bytes getting skipped, as a way of declaring "all input should be clean (now), please accept nothing less". The again, that certainly falls outside the scope of -bugs@.

Terje

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs