pg.ddx.io  pgsql-interfaces@postgresql.org mailing list archive  
help / color / mirror / Atom feed
obtaining primary key/rowid following insert, redux...
5+ messages / 5 participants
[nested] [flat]

* obtaining primary key/rowid following insert, redux...
@ 2000-09-07 03:15 Mark Dzmura <mdz@digital-mission.com>
  2000-09-11 07:03 ` Re: obtaining primary key/rowid following insert, redux... Zeljko Trogrlic <zeljko@technologist.com>
  2000-09-11 14:37 ` Re: obtaining primary key/rowid following insert, redux... Tom Lane <tgl@sss.pgh.pa.us>
  0 siblings, 2 replies; 5+ messages in thread

From: Mark Dzmura @ 2000-09-07 03:15 UTC (permalink / raw)
  To: pgsql-interfaces

Peter:

Trying to solve my problem mentioned in the email of half an hour ago, I searched
through the archives of the interface list and found some of your replies suggesting
using "currval()" to get the last value assigned from a sequence...  However,
here's what happens in a good database with multiple in-use sequences:

db=# select currval('foo_foo_id_seq');
ERROR:  foo_foo_id_seq.currval is not yet defined in this session

As an alternative, I discovered that I can get the value this way:

db=# select last_value from foo_foo_id_seq;
last_value
---------
              27

My questions are, (1) why does the currval() approach give the error message, and
(2) is it OK to use my alternative??

Finally, as far as I can tell, there is a real race condition problem here in a multiple-connection
scenario (e.g. another task can cause the sequence to be incremented between the insert
and the select) - but wrapping a transaction around the insert and select should
take care of it... Thoughts??

Thanks,
Mark Dzmura

Attachments:

mdz.vcf (text/x-vcard, 279B) download begin:vcard n:Dzmura;Mark tel;fax:412-429-3361 tel;work:412-429-6001 x-mozilla-html:FALSE org:Digital Mission, LLC adr:;;230 E. Main St., Suite 210;Carnegie;PA;15106;USA version:2.1 email;internet:mdz@digital-mission.com title:President x-mozilla-cpt:;0 fn:Mark Dzmura end:vcard
^ permalink raw reply [nested|flat] 5+ messages in thread

* Re: obtaining primary key/rowid following insert, redux...
  2000-09-07 03:15 obtaining primary key/rowid following insert, redux... Mark Dzmura <mdz@digital-mission.com>
@ 2000-09-11 07:03 ` Zeljko Trogrlic <zeljko@technologist.com>
  2000-09-11 14:46   ` Re: obtaining primary key/rowid following insert, redux... Ross J. Reedstrom <reedstrm@rice.edu>
  1 sibling, 1 reply; 5+ messages in thread

From: Zeljko Trogrlic @ 2000-09-11 07:03 UTC (permalink / raw)
  To: Mark Dzmura <mdz@digital-mission.com>; pgsql-interfaces

nextval() is the solution  to your problems. currval() won't help, all
users will get same previous value.

At 05:15 7.9.2000 , Mark Dzmura wrote:
>Peter:
>
>Trying to solve my problem mentioned in the email of half an hour ago, I 
>searched
>through the archives of the interface list and found some of your replies 
>suggesting
>using "currval()" to get the last value assigned from a sequence...  However,
>here's what happens in a good database with multiple in-use sequences:
>
>db=# select currval('foo_foo_id_seq');
>ERROR:  foo_foo_id_seq.currval is not yet defined in this session
>
>As an alternative, I discovered that I can get the value this way:
>
>db=# select last_value from foo_foo_id_seq;
>last_value
>---------
>              27
>
>My questions are, (1) why does the currval() approach give the error 
>message, and
>(2) is it OK to use my alternative??
>
>Finally, as far as I can tell, there is a real race condition problem here 
>in a multiple-connection
>scenario (e.g. another task can cause the sequence to be incremented between 
>the insert
>and the select) - but wrapping a transaction around the insert and select 
>should
>take care of it... Thoughts??
>
>Thanks,
>Mark Dzmura
>
>





^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: obtaining primary key/rowid following insert, redux...
  2000-09-07 03:15 obtaining primary key/rowid following insert, redux... Mark Dzmura <mdz@digital-mission.com>
  2000-09-11 07:03 ` Re: obtaining primary key/rowid following insert, redux... Zeljko Trogrlic <zeljko@technologist.com>
@ 2000-09-11 14:46   ` Ross J. Reedstrom <reedstrm@rice.edu>
  0 siblings, 0 replies; 5+ messages in thread

From: Ross J. Reedstrom @ 2000-09-11 14:46 UTC (permalink / raw)
  To: pgsql-interfaces

On Mon, Sep 11, 2000 at 09:03:07AM +0200, Zeljko Trogrlic wrote:
> nextval() is the solution  to your problems. currval() won't help, all
> users will get same previous value.

I must say I am getting tired of seeing the same not only FAQ, but
misinformation being spread about sequences. The nextval()/currval()
functions are completely multiuser safe. The currval('foo') is defined
to return the last value of sequence 'foo' that was returned to the
current connection.  That is in fact why Mark got an error: He tried to
call it on a sequence that had not yet been incremented via nextval()
in the connection.

Currval('foo') (unlike SELECT last_value from foo) will _never_ return
a number that was not generated in the current connection: i.e. was
delivered to another backend. As a consequence, you may get gaps in the
sequence, if a transaction aborts, since sequence values are never rolled
back, but this is a small price to pay for not having lock the sequence,
and thereby serialize all your users.

Ross

> 
> At 05:15 7.9.2000 , Mark Dzmura wrote:
> >Peter:
> >
> >Trying to solve my problem mentioned in the email of half an hour ago, I 
> >searched
> >through the archives of the interface list and found some of your replies 
> >suggesting
> >using "currval()" to get the last value assigned from a sequence...  However,
> >here's what happens in a good database with multiple in-use sequences:
> >
> >db=# select currval('foo_foo_id_seq');
> >ERROR:  foo_foo_id_seq.currval is not yet defined in this session
> >
> >As an alternative, I discovered that I can get the value this way:
> >
> >db=# select last_value from foo_foo_id_seq;
> >last_value
> >---------
> >              27
> >
> >My questions are, (1) why does the currval() approach give the error 
> >message, and
> >(2) is it OK to use my alternative??
> >
> >Finally, as far as I can tell, there is a real race condition problem here 
> >in a multiple-connection
> >scenario (e.g. another task can cause the sequence to be incremented between 
> >the insert
> >and the select) - but wrapping a transaction around the insert and select 
> >should
> >take care of it... Thoughts??
> >
> >Thanks,
> >Mark Dzmura
> >
> >
> 
> 

-- 
Ross J. Reedstrom, Ph.D., <reedstrm@rice.edu> 
NSBRI Research Scientist/Programmer
Computer and Information Technology Institute
Rice University, 6100 S. Main St.,  Houston, TX 77005



^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: obtaining primary key/rowid following insert, redux...
  2000-09-07 03:15 obtaining primary key/rowid following insert, redux... Mark Dzmura <mdz@digital-mission.com>
@ 2000-09-11 14:37 ` Tom Lane <tgl@sss.pgh.pa.us>
  1 sibling, 0 replies; 5+ messages in thread

From: Tom Lane @ 2000-09-11 14:37 UTC (permalink / raw)
  To: Mark Dzmura <mdz@digital-mission.com>; +Cc: pgsql-interfaces

Mark Dzmura <mdz@digital-mission.com> writes:
> Trying to solve my problem mentioned in the email of half an hour ago,
> I searched through the archives of the interface list and found some
> of your replies suggesting using "currval()" to get the last value
> assigned from a sequence...  However, here's what happens in a good
> database with multiple in-use sequences:

> db=# select currval('foo_foo_id_seq');
> ERROR:  foo_foo_id_seq.currval is not yet defined in this session

That means you haven't actually done any nextval() yet in this backend,
therefore there is no "last value assigned" yet.

> As an alternative, I discovered that I can get the value this way:

> db=# select last_value from foo_foo_id_seq;
> last_value
> ---------
>               27

> My questions are, (1) why does the currval() approach give the error
> message, and (2) is it OK to use my alternative??

No, because you'd have a race condition across multiple backends.

> Finally, as far as I can tell, there is a real race condition problem
> here in a multiple-connection scenario (e.g. another task can cause
> the sequence to be incremented between the insert and the select)

Not with currval(), because that holds the last value assigned by the
current backend.  Looking directly at the sequence's last_value would
indeed have a race problem.

Another way to do it, which might be more convenient than currval()
depending on your application logic, is to do select nextval() to get
a new sequence number assigned, and then explicitly insert that value
into the serial column as you insert the row, rather than relying on
the column's DEFAULT clause to compute it for you.  I tend to see this
way as being logically cleaner than the insert-and-then-use-currval
way, but that's a matter of taste.

			regards, tom lane



^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* RE: obtaining primary key/rowid following insert, re dux...
@ 2000-09-11 07:07 Peter Mount <petermount@maidstone.gov.uk>
  0 siblings, 0 replies; 5+ messages in thread

From: Peter Mount @ 2000-09-11 07:07 UTC (permalink / raw)
  To: 'Mark Dzmura' <mdz@digital-mission.com>; pgsql-interfaces

currval is throwing the error because the sequence hasn't been used in that
session/connection. currval returns the most recent allocated value which is
cached, but not necessarily the next value -1.

Sequences don't have to increment by 1, so if you have multiple concurrent
connections (as I'll show in a moment) the select may not give the correct
result (the race condition you noticed).

The cases where you would (at creation time) set the increment to more than
1 is when you know that in a transaction you'll be allocating multiple
sequence values. Instead of updating the sequence table for each insert, you
allocate a block (say for example 10) of numbers. Another connection would
get the next block of 10, and your connection can safely allocate from the
remaining numbers in the cached block. Cuts down a lot of disk acceses.

Anyhow, here's a real life example of how I use currval. Ok, this is PHP but
you'll get the idea.

This little section of code is used on one of our new websites going live at
the end of the month (and in some ways is one of the other reasons why I'm
behind with JDBC ;-) ). This bit is called when someone is creating a new
user account. Each user is actually stored in three tables (performance
reasons).

There is a sequence 'users_uid_seq' which lives in the main 'users' table,
but is also the primary key in the userinfo and usercomments tables. Here we
have a transaction where the sequence is updated when the first insert is
done, but we need the allocated value to ensure that the next two inserts
are correct:

  if(!$error) {
    $res=pg_Exec("begin work");
    if($res) {pg_FreeResult($res);}
    
    $res=pg_Exec("insert into users
(nick,realname,email,fakemail,passwd,sig,enabled) values
('".$nick."','".$realname."','".$email."','".$email."','".$password."','','t
')");
    if($res) {pg_FreeResult($res);}
    
    $res=pg_Exec("insert into userinfo
(uid,url,bio,karma,dailynews,totalcomments) values
(currval('users_uid_seq'),'','',0,'f',0)");
    if($res) {pg_FreeResult($res);}
    
    $res=pg_Exec("insert into usercomments
(uid,posthtml,highthresh,clbig,clsmall,reparent,nosigs,cspill,noscores,mode,
threshold) values
(currval('users_uid_seq'),'f',3,300,50,'t','f',100,'f',2,0)");
    if($res) {pg_FreeResult($res);}
    
    $res=pg_Exec("commit work");
    if($res) {pg_FreeResult($res);}
    
    // redir here
    $res=pg_Exec("select currval('users_uid_seq') as a");
    if($res) {
      $uid=pg_Result($res,0,"a");
      pg_FreeResult($res);
      
      $time=time()+86400;
      $date=date("l, d-M-y H:i:s",($time));
      mySetCookie("digitalmsid",$uid,$time,"/",$GLOBALS["cookie domain"]);
    }
    header("Location: index.php?tm=".$time);
    exit;
  }

-- 
Peter Mount
Enterprise Support Officer, Maidstone Borough Council
Email: petermount@maidstone.gov.uk
WWW: http://www.maidstone.gov.uk
All views expressed within this email are not the views of Maidstone Borough
Council


-----Original Message-----
From: Mark Dzmura [mailto:mdz@digital-mission.com]
Sent: Thursday, September 07, 2000 4:15 AM
To: pgsql-interfaces@postgreSQL.org
Subject: [INTERFACES] obtaining primary key/rowid following insert,
redux...


Peter:

Trying to solve my problem mentioned in the email of half an hour ago, I
searched
through the archives of the interface list and found some of your replies
suggesting
using "currval()" to get the last value assigned from a sequence...
However,
here's what happens in a good database with multiple in-use sequences:

db=# select currval('foo_foo_id_seq');
ERROR:  foo_foo_id_seq.currval is not yet defined in this session

As an alternative, I discovered that I can get the value this way:

db=# select last_value from foo_foo_id_seq;
last_value
---------
              27

My questions are, (1) why does the currval() approach give the error
message, and
(2) is it OK to use my alternative??

Finally, as far as I can tell, there is a real race condition problem here
in a multiple-connection
scenario (e.g. another task can cause the sequence to be incremented between
the insert
and the select) - but wrapping a transaction around the insert and select
should
take care of it... Thoughts??

Thanks,
Mark Dzmura




^ permalink  raw  reply  [nested|flat] 5+ messages in thread


end of thread, other threads:[~2000-09-11 14:46 UTC | newest]

Thread overview: 5+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2000-09-07 03:15 obtaining primary key/rowid following insert, redux... Mark Dzmura <mdz@digital-mission.com>
2000-09-11 07:03 ` Zeljko Trogrlic <zeljko@technologist.com>
2000-09-11 14:46   ` Ross J. Reedstrom <reedstrm@rice.edu>
2000-09-11 14:37 ` Tom Lane <tgl@sss.pgh.pa.us>
2000-09-11 07:07 RE: obtaining primary key/rowid following insert, re dux... Peter Mount <petermount@maidstone.gov.uk>

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