[Zope] Can I capture results from insert in Z SQL methods?

Tino Wildenhain tino@wildenhain.de
Sun, 03 Nov 2002 18:56:53 +0100


Hi Jim, hi Skip,

--On Sonntag, 3. November 2002 12:30 -0500 Jim Gallacher 
<jg.lists@sympatico.ca> wrote:

> Hi Skip,
>
>
> Skip Montanaro wrote:
>>     Andrew> This is really a general SQL problem rather than anything to
>>     do Andrew> with Zope/ZSQL.
>>
>> So ZSQL methods don't provide any special syntactic sugar other than
>> <dtml-sqlvar>?

Its nothing magic with this sqlvar. It only assembles the query which is 
then
send to the DB - as one block of text.
>>
>>     Andrew> Then do a select nextval('whatever'); to get the next id
>>     which Andrew> can then be used for the inserts.
>>
>> Thanks, I'll check it out.  This seems (naively) like it would be a race
>> to me though.  Let's say I do this:
>>
>>     insert into phone ( ... ) values ( ... );
>>
>> The new row in phone got a unique id (I do use the serial type for my
>> primary keys).  Now, I need the id that row got to use in another insert.
>> If I do something like:
>>
>>     insert into contact (
>>         ...
>>         phone,
>>         ...
>>     )
>>     values (
>>         ...
>>         (select currval(phone_id_seq)),
>>         ...
>>     );
>>
>> That will get the id of the record I just inserted assuming someone else
>> didn't sneak in and insert another row in the phone table before I
>> queried phone_id_seq.

You should consider consulting your database manual. This sequcence 
nextval/currval
is an FAQ. currval is only valid after nextval in the same transaction.
So currval, used correctly after nextval will under any circumstance give 
you the
same value as your last nextval in your transaction, no matter how many 
nextval()
calls are made in another transactions in the same time.

Here is the relevant section from Postgres documentation:
--------- cite --------
The available sequence functions are:

nextval
Advance the sequence object to its next value and return that value. This 
is done atomically: even if multiple server processes execute nextval 
concurrently, each will safely receive a distinct sequence value.

currval
Return the value most recently obtained by nextval for this sequence in the 
current server process. (An error is reported if nextval has never been 
called for this sequence in this process.) Notice that because this is 
returning a process-local value, it gives a predictable answer even if 
other server processes are executing nextval meanwhile.

setval
Reset the sequence object's counter value. The two-parameter form sets the 
sequence's last_value field to the specified value and sets its is_called 
field to true, meaning that the next nextval will advance the sequence 
before returning a value. In the three-parameter form, is_called may be set 
either true or false. If it's set to false, the next nextval will return 
exactly the specified value, and sequence advancement commences with the 
following nextval. For example,


SELECT setval('foo', 42);           Next nextval() will return 43
SELECT setval('foo', 42, true);     Same as above
SELECT setval('foo', 42, false);    Next nextval() will return 42

The result returned by setval is just the value of its second argument.


Important: To avoid blocking of concurrent transactions that obtain numbers 
from the same sequence, a nextval operation is never rolled back; that is, 
once a value has been fetched it is considered used, even if the 
transaction that did the nextval later aborts. This means that aborted 
transactions may leave unused "holes" in the sequence of assigned values. 
setval operations are never rolled back, either.

If a sequence object has been created with default parameters, nextval() 
calls on it will return successive values beginning with one. Other 
behaviors can be obtained by using special parameters in the CREATE 
SEQUENCE command; see its command reference page for more information.
-------------------

HTH
Tino Wildenhain