Обсуждение: Last inserted id
Hi, I have this simple code that uses ADO to insert a row in a test table
with a serial id and a varchar,
after insert I can obtain varchar's value but I *can't* obtain id's value
of
this record. What I'm doing wrong ??
Thanks!
*Table definition:
mydatabase-# \d societats;
idsocietat | integer | not null default
nextval('"societats_idsocietat_seq"'::text)
nomsocietat | character varying(50) |
capitalsocial | double precision | default 0
*Postgres 7.1.3 under FreeBSD 4.4
*VB code
Private Sub Command3_Click()
' Dims omited
Set Cnxn = New ADODB.Connection
strCnxn = "Provider=MSDASQL.1;Persist Security Info=False;Data
Source=mysource"
Cnxn.Open strCnxn
Set rstEmployees = New ADODB.Recordset
strSQL = "societats"
rstEmployees.Open strSQL, strCnxn, adOpenKeyset, adLockOptimistic,
adCmdTable
strFirstName = Trim(InputBox("Put name:"))
rstEmployees.AddNew
rstEmployees!nomsocietat = strFirstName
rstEmployees.Update
' Show the newly added data
MsgBox "New record: " & rstEmployees!idsocietat & " " &
rstEmployees!nomsocietat
'''''rstEmployees!idsocietat returns nothing !!!!!!!!!!!!!!
rstEmployees.Close
Cnxn.Close
Set rstEmployees = Nothing
Set Cnxn = Nothing
End Sub
> -----Original Message-----
> From: Simeo Reig [mailto:simreig@terra.es]
> Sent: 10 November 2001 20:56
> To: pgsql-odbc@postgresql.org
> Subject: [ODBC] Last inserted id
>
>
> Hi, I have this simple code that uses ADO to insert a row in
> a test table with a serial id and a varchar, after insert I
> can obtain varchar's value but I *can't* obtain id's value of
> this record. What I'm doing wrong ?? Thanks!
>
>
> *Table definition:
>
> mydatabase-# \d societats;
> idsocietat | integer | not null default
> nextval('"societats_idsocietat_seq"'::text)
> nomsocietat | character varying(50) |
> capitalsocial | double precision | default 0
>
> *Postgres 7.1.3 under FreeBSD 4.4
>
>
> *VB code
>
> Private Sub Command3_Click()
>
> ' Dims omited
> Set Cnxn = New ADODB.Connection
> strCnxn = "Provider=MSDASQL.1;Persist Security
> Info=False;Data Source=mysource"
> Cnxn.Open strCnxn
> Set rstEmployees = New ADODB.Recordset
> strSQL = "societats"
>
> rstEmployees.Open strSQL, strCnxn, adOpenKeyset,
> adLockOptimistic, adCmdTable
>
> strFirstName = Trim(InputBox("Put name:"))
> rstEmployees.AddNew
> rstEmployees!nomsocietat = strFirstName
> rstEmployees.Update
>
> ' Show the newly added data
> MsgBox "New record: " & rstEmployees!idsocietat & " " &
> rstEmployees!nomsocietat
>
> '''''rstEmployees!idsocietat returns nothing !!!!!!!!!!!!!!
>
> rstEmployees.Close
> Cnxn.Close
> Set rstEmployees = Nothing
> Set Cnxn = Nothing
>
> End Sub
>
ADO doesn't re-query the database to get the true representation of the new
row. The common way around this problem is to manually get the new ID first
in a seperate query, and then insert that value as well. The other
alternative is to refresh the recordset after the insert, however this often
isn't desirable.
Regards, Dave.
> -----Original Message----- > From: Simeo Reig [mailto:simreig@terra.es] > Sent: 11 November 2001 22:54 > To: Dave Page > Subject: Re: [ODBC] Last inserted id > > > I had think that the problem was this but I believed that > was possible to make a mistake because I'm newer with > ADO. What must I do ? I see two possibilities: > > A) Make a select NEXTVAL from sequence, and > insert this value in the id > > B) Insert row and after make a CURRVAL > > What option Do you use ? Use option A), it's multi-user safe whereas the other method isn't. > > Another question please : Are you pleased with Postgres ? > I have to make a project with almost 50 tables (five with > arround 100.000 rows), and 20 concurrent users. Can postgres > make a good job? I'm project lead for pgAdmin II (pgadmin.postgresql.org) so I'm probably a bit biased :-) but the main server I run at work hosts about 12 databases for interactive (VB) applications, PHP apps and also logs data from 3 PBXs. Most of the databases have at least 10 tables in them (a couple have about 40) and I have some tables over 1.7 million rows. In short, PostgreSQL does a great job for me and I use it wherever I can (incidently, I also have Informix, MS-SQL & Unidata servers here which I could have used instead of PostgreSQL). Regards, Dave. > Thanks Dave > > Simeó Reig > Barcelona (Spain) > > > ADO doesn't re-query the database to get the true > >representation of > > the > new > > row. The common way around this problem is to manually >get > the new ID > first > > in a seperate query, and then insert that value as well. The >other > > alternative is to refresh the recordset after the insert, >however > > this > often > > isn't desirable. > > > > Regards, Dave. > > >
On Mon, Nov 12, 2001 at 08:23:08AM -0000, Dave Page wrote: > > -----Original Message----- > > From: Simeo Reig [mailto:simreig@terra.es] > > Sent: 11 November 2001 22:54 > > To: Dave Page > > Subject: Re: [ODBC] Last inserted id > > > > > > I had think that the problem was this but I believed that > > was possible to make a mistake because I'm newer with > > ADO. What must I do ? I see two possibilities: > > > > A) Make a select NEXTVAL from sequence, and > > insert this value in the id > > > > B) Insert row and after make a CURRVAL > > > > What option Do you use ? > > Use option A), it's multi-user safe whereas the other method isn't. Unless I'm missing something, option B _is_ multi-user safe. currval() doesn't return the "current" value of the sequence (like "select * from my_seq" would) -- it returns the last value that nextval() gave that session (hence, it isn't defined until that session does a nextval()). I have no idea what ADO is :-), so there may be other issues here, but I don't think multi-user access is one of them. -- Geoffrey D. Bennett, RHCE, RHCX geoffrey@netcraft.com.au Senior Systems Engineer http://www.netcraft.com.au/geoffrey/ NetCraft Australia Pty Ltd http://www.netcraft.com.au/linux/
> -----Original Message-----
> From: Geoffrey D. Bennett [mailto:g@netcraft.com.au]
> Sent: 12 November 2001 08:55
> To: Dave Page
> Cc: 'Simeo Reig'; 'pgsql-odbc@postgresql.org'
> Subject: Re: [ODBC] Last inserted id
>
>
> On Mon, Nov 12, 2001 at 08:23:08AM -0000, Dave Page wrote:
> > > -----Original Message-----
> > > From: Simeo Reig [mailto:simreig@terra.es]
> > > Sent: 11 November 2001 22:54
> > > To: Dave Page
> > > Subject: Re: [ODBC] Last inserted id
> > >
> > >
> > > I had think that the problem was this but I believed that was
> > > possible to make a mistake because I'm newer with ADO.
> What must I
> > > do ? I see two possibilities:
> > >
> > > A) Make a select NEXTVAL from sequence, and
> > > insert this value in the id
> > >
> > > B) Insert row and after make a CURRVAL
> > >
> > > What option Do you use ?
> >
> > Use option A), it's multi-user safe whereas the other method isn't.
>
> Unless I'm missing something, option B _is_ multi-user safe.
> currval() doesn't return the "current" value of the sequence
> (like "select * from my_seq" would) -- it returns the last value that
> nextval() gave that session (hence, it isn't defined until
> that session does a nextval()).
The problem is that Microsoft's ActiveX Data Objects (ADO) will not query
the database for additional values in a newly inserted row (in this case,
the id which is inserted as a default by the backend).
I suggest (and use) option A).
As I understand option B), Simeo is proposing to get the current value from
the sequence, insert the complete row client side (so ADO knows the ID),
then set the current value of the sequence (SELECT setval('sequence', 123)).
This is not multiuser safe as a second user may increment the sequence value
in the middle of the first users' 3 queries.
Regards, Dave.
Him
> Unless I'm missing something, option B _is_ multi-user safe.
> currval() doesn't return the "current" value of the sequence (like
> "select * from my_seq" would) -- it returns the last value that
> nextval() gave that session (hence, it isn't defined until that
> session does a nextval()).
>
Actually the issue is b) is multi-user safe
*if* you have an exclusive lock on the table. If you don't it is quite
possible for a user to insert an other record between your insertion and the
currval() call
David
--
****************************************************
David Horwitz University of Cape Town
IT Officer Private Bag
Multimedia Education Group Rondebosch
7701
dhorwitz@ched.uct.ac.za SOUTH AFRICA
Tel:+27 21 650 3841 Fax:+27 21 650 5045
http://www.meg.uct.ac.za
PGP key: http://www.meg.uct.ac.za/dhorwitz/david_horwitz.acs
*************************************************
Hello, Why don't you add a timestamp field in the table? Insert a value with current time, then query to get the corresponding row. Best regards, Jean-Michel POURE
> -----Original Message----- > From: Jean-Michel POURE [mailto:jm.poure@freesurf.fr] > Sent: 12 November 2001 09:36 > To: pgsql-odbc@postgresql.org > Subject: Re: [ODBC] Last inserted id > > > Hello, > > Why don't you add a timestamp field in the table? > Insert a value with current time, then query to get the > corresponding row. 'Cos that's not safe either - you might get multiple rows inserted at the same time - unlikely, but certainly possible. /Dave.
At 09:55 12/11/01 +0000, you wrote: >'Cos that's not safe either - you might get multiple rows inserted at the >same time - unlikely, but certainly possible. In most cases a simple timestamp is enough because you add some other parameter to you query (ex:company name, or whatever field you inserted). For example, if you insert values with First_name=Dave, Second_name=Page, Timestamp=current time and query the resulting row, there is *very little* chance to get rows from other users. I guess this is the recommended way (see Access howto). Cheers, Jean-Michel
> -----Original Message-----
> From: Jean-Michel POURE [mailto:jm.poure@freesurf.fr]
> Sent: 12 November 2001 10:06
> To: pgsql-odbc@postgresql.org
> Subject: Re: [ODBC] Last inserted id
>
>
> At 09:55 12/11/01 +0000, you wrote:
> >'Cos that's not safe either - you might get multiple rows
> inserted at
> >the same time - unlikely, but certainly possible.
>
> In most cases a simple timestamp is enough because you add some other
> parameter to you query (ex:company name, or whatever field
> you inserted).
> For example, if you insert values with First_name=Dave,
> Second_name=Page,
> Timestamp=current time and query the resulting row, there is
> *very little*
> chance to get rows from other users.
>
> I guess this is the recommended way (see Access howto).
There is *very little* chance, but very little is not *no chance* (bear in
mind that at this point in time in the example we're discussing no primary
key value is yet known).
I would always suggest that people do a select nextval('seq') followed by a
suitable insert. It requires no locking, is definitely multi user safe and
will *always* correctly identify the row. The only downside is that it
requires a quick select before the insert, but if this minor speed sacrifice
was that much of an issue then VB+ADO+ODBC is possibly not the technology to
use in such a project anyway IMHO.
Regards, Dave.
David Horwitz <Dhorwitz@ched.uct.ac.za> writes:
> Actually the issue is b) is multi-user safe
> *if* you have an exclusive lock on the table. If you don't it is quite
> possible for a user to insert an other record between your insertion and the
> currval() call
False. Option B is multi-user safe, period. The reason is that currval
returns the value last obtained by nextval *in your own session*,
independently of what anyone else has done meanwhile.
I tend to prefer option A (select nextval and insert) myself, just
because it seems more intuitive. But if that's not convenient for
some reason, option B works fine too.
regards, tom lane
> -----Original Message-----
> From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
> Sent: 12 November 2001 15:30
> To: Dhorwitz@ched.uct.ac.za
> Cc: 'pgsql-odbc@postgresql.org'
> Subject: Re: [ODBC] Last inserted id
>
>
> David Horwitz <Dhorwitz@ched.uct.ac.za> writes:
> > Actually the issue is b) is multi-user safe
> > *if* you have an exclusive lock on the table. If you don't it is
> > quite possible for a user to insert an other record between your
> > insertion and the
> > currval() call
>
> False. Option B is multi-user safe, period. The reason is
> that currval returns the value last obtained by nextval *in
> your own session*, independently of what anyone else has done
> meanwhile.
>
> I tend to prefer option A (select nextval and insert) myself,
> just because it seems more intuitive. But if that's not
> convenient for some reason, option B works fine too.
Ahh, now I see where the (== my) confusion has occurred. Option B) being:
- do insert
- select current val.
Whereas I originally was arguing against my interpretation of the question
which was:
- Select current val
- Do insert
- Select setval('seq', current_val + 1)
Which isn't safe.
Oh well.
My bad.
Regards, Dave.
> False. Option B is multi-user safe, period. The reason is that currval > returns the value last obtained by nextval *in your own session*, > independently of what anyone else has done meanwhile. What do you understand for *session* ? Same postgres connection ? Same ADO connection ? (ADO sometimes make more than one connection for recordset) How Can I know how many connections are active ? (for ADO debugging) Thanks Simeó Reig
"Simeo Reig" <simreig@terra.es> writes:
>> False. Option B is multi-user safe, period. The reason is that currval
>> returns the value last obtained by nextval *in your own session*,
>> independently of what anyone else has done meanwhile.
> What do you understand for *session* ? Same postgres connection ?
Same postgres connection. If you are working in an application
environment that does connection pooling, or some such, then this
is unsafe and you'd better go back to option A.
regards, tom lane
> -----Original Message----- > From: Simeo Reig [mailto:simreig@terra.es] > Sent: 12 November 2001 20:43 > To: pgsql-odbc@postgresql.org > Subject: Re: [ODBC] Last inserted id > > > > False. Option B is multi-user safe, period. The reason is that > > currval returns the value last obtained by nextval *in your own > > session*, independently of what anyone else has done meanwhile. > > What do you understand for *session* ? Same postgres > connection ? Same ADO connection ? (ADO sometimes make more > than one connection for recordset) > > How Can I know how many connections are active ? > (for ADO debugging) I don't think you can easily find out what connections are open (at least from the ADO end). In pgAdmin II there is a long running bug that I can't resolve that prevents dropping a database because I can't persuade *all* connections to the specified database to close. It's for this reason that I'd still use option A - option B may be multi user safe (now that I understand it properly :-) ) but you never know how ADO is going to handle it. In theory it should only use one connection but the bug I mention above (knowing the time, effort and experimentation I've put into fixing it) makes me wonder. Regards, Dave.
At 08:35 13/11/01 +0000, you wrote: >In pgAdmin II there is a long running bug that I can't >resolve that prevents dropping a database because I can't persuade *all* >connections to the specified database to close. Dear all, The same problem arises when working in psql after the closing of Php socket connections. I have to do a 'service postgresql restart' server-side, and then psql template1 < drop database xxxx; Does anyone know a simpler solution? Cheers, Jean-Michel
On Mon, 12 Nov 2001, Jean-Michel POURE wrote: > At 09:55 12/11/01 +0000, you wrote: > >'Cos that's not safe either - you might get multiple rows inserted at the > >same time - unlikely, but certainly possible. > > In most cases a simple timestamp is enough because you add some other > parameter to you query (ex:company name, or whatever field you inserted). > For example, if you insert values with First_name=Dave, Second_name=Page, > Timestamp=current time and query the resulting row, there is *very little* > chance to get rows from other users. > > I guess this is the recommended way (see Access howto). Yes, but the query for search the row is more expensive than select from an id that is normally indexed. I have making tests and 'option A' seems be the best. Thanks Simeo Reig
I believe that in the release notes for the most recent version, it states that this problem is known and can't really be worked around. Chris > -----Original Message----- > From: pgsql-hackers-owner@postgresql.org > [mailto:pgsql-hackers-owner@postgresql.org]On Behalf Of Jean-Michel > POURE > Sent: Tuesday, 13 November 2001 5:33 PM > To: pgsql-odbc@postgresql.org > Cc: pgsql-hackers@postgresql.org > Subject: Re: [HACKERS] [ODBC] Last inserted id > > > At 08:35 13/11/01 +0000, you wrote: > >In pgAdmin II there is a long running bug that I can't > >resolve that prevents dropping a database because I can't persuade *all* > >connections to the specified database to close. > > Dear all, > > The same problem arises when working in psql after the closing of Php > socket connections. > I have to do a 'service postgresql restart' server-side, and then psql > template1 < drop database xxxx; > > Does anyone know a simpler solution? > > Cheers, > Jean-Michel > > ---------------------------(end of broadcast)--------------------------- > TIP 3: if posting/reading through Usenet, please send an appropriate > subscribe-nomail command to majordomo@postgresql.org so that your > message can get through to the mailing list cleanly >