Обсуждение: BUG #4684: lastval in function

Поиск
Список
Период
Сортировка

BUG #4684: lastval in function

От
"andreas"
Дата:
The following bug has been logged online:

Bug reference:      4684
Logged by:          andreas
Email address:      postgresql@elbrief.de
PostgreSQL version: 8.3.6
Operating system:   linux
Description:        lastval in function
Details:

create table bla ( id serial primary key , name text not null unique ) ;
create table bla2 ( id serial primary key , blaid int references bla , name
text not null unique ) ;
create or replace function blaa( text ) returns int as $$
  my $name = shift ;
  my $q = spi_exec_query( "select id from bla where name = '$name'" ) ;
  if ( not $q->{ rows }->[ 0 ]->{ id } ) {
    spi_exec_query( "insert into bla ( name ) values ( '$name' )" ) ;
    $q = spi_exec_query( "select lastval() as id" ) ;
  }
  return $q->{ rows }->[ 0 ]->{ id } ;
$$ language plperl security definer ;
select blaa( 'test' ) ;
insert into bla2 ( blaid , name ) values ( blaa( 'muster' ) , 'muster' ) ;

select lastval() ;
 lastval
---------
       2

i expected lastval() should be 1, because this is the id from the
insertstatement.

insert into bla2 ( blaid , name ) values ( blaa( 'muster2' ) , blaa(
'muster3' ) ) ;

select lastval() ;
 lastval
---------
       4

if nextval is used inside a function in a insertstatement, you get always
the value from inside the last function. but i expected, that lastval()
deliver the value from the insertstatement. i think, this should clearify in
the documentation, or better fixed that the nextval from an insertstatement
is called after the functioncalls.

Andreas

Re: BUG #4684: lastval in function

От
Tom Lane
Дата:
"andreas" <postgresql@elbrief.de> writes:
> select lastval() ;
>  lastval
> ---------
>        2

> i expected lastval() should be 1, because this is the id from the
> insertstatement.

Well, you can't really rely on that when the statement you're executing
contains two different nextval() calls, as this does.  The order of
evaluation of those calls is unspecified.

Personally I'm of the opinion that anyone who uses lastval() deserves to
lose, precisely because of the risk of this type of interaction.  Use
currval() on one or the other of those sequences, and you'll be at least
a little bit safer.  Even better is to use INSERT RETURNING or some
other alternative so that you can avoid currval() too.

            regards, tom lane

Re: BUG #4684: lastval in function

От
Heikki Linnakangas
Дата:
andreas wrote:
> if nextval is used inside a function in a insertstatement, you get always
> the value from inside the last function. but i expected, that lastval()
> deliver the value from the insertstatement. i think, this should clearify in
> the documentation, or better fixed that the nextval from an insertstatement
> is called after the functioncalls.

Well, others might expect the opposite, like existing applications. Want
to suggest wording for the documentation?

To get the id of the row inserted, use INSERT RETURNING. Or currval('bla2').

--
   Heikki Linnakangas
   EnterpriseDB   http://www.enterprisedb.com

Re: BUG #4684: lastval in function

От
Andreas
Дата:
Heikki Linnakangas schrieb:
> andreas wrote:
>> if nextval is used inside a function in a insertstatement, you get always
>> the value from inside the last function. but i expected, that lastval()
>> deliver the value from the insertstatement. i think, this should
>> clearify in
>> the documentation, or better fixed that the nextval from an
>> insertstatement
>> is called after the functioncalls.
>
> Well, others might expect the opposite, like existing applications. Want
> to suggest wording for the documentation?

Yes, existing applications might be involved. But i think, this is a
very rare situation. But if someone use an insertstatement with a
functioncall, but the function do NOT use nextval, and he use lastval to
estimate the last inserted value he has no problems. But if then someone
change the function so the function use nextval then the application
crashes. So i think it is much more better to change the behavior,
because this is what i expect. And i think, this is what others
expect too.

Andreas

Re: BUG #4684: lastval in function

От
Chris Browne
Дата:
Andreas <postgresql@elbrief.de> writes:
> Heikki Linnakangas schrieb:
>> andreas wrote:
>>> if nextval is used inside a function in a insertstatement, you get always
>>> the value from inside the last function. but i expected, that lastval()
>>> deliver the value from the insertstatement. i think, this should
>>> clearify in
>>> the documentation, or better fixed that the nextval from an
>>> insertstatement
>>> is called after the functioncalls.
>>
>> Well, others might expect the opposite, like existing
>> applications. Want to suggest wording for the documentation?
>
> Yes, existing applications might be involved. But i think, this is a
> very rare situation. But if someone use an insertstatement with a
> functioncall, but the function do NOT use nextval, and he use lastval to
> estimate the last inserted value he has no problems. But if then someone
> change the function so the function use nextval then the application
> crashes. So i think it is much more better to change the behavior,
> because this is what i expect. And i think, this is what others
> expect too.

Someone recently reported this issue as a possible bug in Slony-I;
they had written their application to use lastval() to capture
sequence values, and then, when they introduced replication, they
started capturing values of a sequence Slony-I uses to control *its*
operations.

You'd experience the same problem with any similar sort of "after"
trigger that was added to do logging; any kind of logging system that
uses sequences is liable to break usage of lastval().

This actually feels like it's a global versus dynamic/lexical scope
problem <http://en.wikipedia.org/wiki/Scope_(programming)>.

PostgreSQL is capturing *all* the sequence updates for the connection,
where the application would apparently prefer to only see those that
it *wants* to see.  I'm not sure whether lexical or dynamic scope
better reflect what might be desired.

However, the notion of there being some kind of more-local scope is
the big deal, something which PostgreSQL does not support.

I'm not sure I'd *want* to have a more-sophisticated scoping mechanism
for this.
--
output = reverse("moc.enworbbc" "@" "enworbbc")
http://cbbrowne.com/info/nonrdbms.html
Rules of the Evil Overlord #177.  "If a scientist with a beautiful and
unmarried  daughter  refuses to  work  for me,  I  will  not hold  her
hostage. Instead, I  will offer to pay for her  future wedding and her
children's college tuition." <http://www.eviloverlord.com/>

Re: BUG #4684: lastval in function

От
Tom Lane
Дата:
Chris Browne <cbbrowne@acm.org> writes:
> I'm not sure I'd *want* to have a more-sophisticated scoping mechanism
> for this.

We already have an appropriate language-level solution for this: it's
called INSERT RETURNING.

The fact is that lastval was invented to aid in porting brain-dead
mysql applications that weren't going to do anything as complicated
as execute commands that might involve more than one nextval call.
If there is any remote possibility that your app might have to deal
with such a thing, you shouldn't be using lastval.

Before considering complicating the definition of lastval, I'd vote
for removing it entirely.  It's a foot-gun and will never be anything
but.

            regards, tom lane

Re: BUG #4684: lastval in function

От
Jaime Casanova
Дата:
On Mon, Mar 2, 2009 at 12:21 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Before considering complicating the definition of lastval, I'd vote
> for removing it entirely. =A0It's a foot-gun and will never be anything
> but.
>

+1


--=20
Atentamente,
Jaime Casanova
Soporte y capacitaci=F3n de PostgreSQL
Asesor=EDa y desarrollo de sistemas
Guayaquil - Ecuador
Cel. +59387171157