Thread: 8.1, OID's and plpgsql

8.1, OID's and plpgsql

From
"Uwe C. Schroeder"
Date:
Hi everyone,

in 8.1 by default tables have no OID's anymore. Since OID's are 4 byte it's
probably a good idea to discourage the use of them (they produced a lot of
trouble in the past anyways, particularly with backup/restores etc)

Now there's the issue with stored procs. A usual construct would be to
...
...
INSERT xxxxxx;
GET DIAGNOSTICS lastoid=RESULT_OID;
SELECT .... oid=lastoid;
....
....

Is there anything one could sanely replace this construct with?
I personally don't think that using the full primary key is really a good
option. Say you have a 3 column primary key - one being a "serial", the
others for example being timestamps, one of them generated with "default"
options. In order to retrieve the record I just inserted (where I don't know
the "serial" value or the timestamp) I'd have to

1) store the "nextval" of the sequence into a variable
2) generate the timestamp and store it to a variable
3) generate the full insert statement and retain the other values of the
primary key
4) issue a select to get the record.

Personally I think this adds unneccessary overhead. IMHO this diminishes the
use of defaults and sequences unless there is some easier way to retrieve the
last record. I must be missing something here - am I ?

    UC


Re: 8.1, OID's and plpgsql

From
Richard Huxton
Date:
Uwe C. Schroeder wrote:
> Hi everyone,
>
> in 8.1 by default tables have no OID's anymore. Since OID's are 4 byte it's
> probably a good idea to discourage the use of them (they produced a lot of
> trouble in the past anyways, particularly with backup/restores etc)
>
> Now there's the issue with stored procs. A usual construct would be to
> ...
> ...
> INSERT xxxxxx;
> GET DIAGNOSTICS lastoid=RESULT_OID;
> SELECT .... oid=lastoid;
> ....
> ....
>
> Is there anything one could sanely replace this construct with?
> I personally don't think that using the full primary key is really a good
> option.

There we disagree. That's what the primary-key is for. Of course that
means we want a last_primary_key_from_insert() system-function.

 > Say you have a 3 column primary key - one being a "serial", the
> others for example being timestamps, one of them generated with "default"
> options.

Then you have a bad primary key - the timestamps add nothing to the
serial (or vice-versa).

 > In order to retrieve the record I just inserted (where I don't know
> the "serial" value or the timestamp) I'd have to
>
> 1) store the "nextval" of the sequence into a variable
> 2) generate the timestamp and store it to a variable
> 3) generate the full insert statement and retain the other values of the
> primary key
> 4) issue a select to get the record.
>
> Personally I think this adds unneccessary overhead. IMHO this diminishes the
> use of defaults and sequences unless there is some easier way to retrieve the
> last record. I must be missing something here - am I ?

Yes - add a SERIAL column with UNIQUE and fetch on that if you really
need to. This effectively gives you your OID back.

--
   Richard Huxton
   Archonet Ltd

Re: 8.1, OID's and plpgsql

From
Jaime Casanova
Date:
On 12/1/05, Uwe C. Schroeder <uwe@oss4u.com> wrote:
>
> Hi everyone,
>
> in 8.1 by default tables have no OID's anymore. Since OID's are 4 byte it's
> probably a good idea to discourage the use of them (they produced a lot of
> trouble in the past anyways, particularly with backup/restores etc)
>
> Now there's the issue with stored procs. A usual construct would be to
> ...
> ...
> INSERT xxxxxx;
> GET DIAGNOSTICS lastoid=RESULT_OID;
> SELECT .... oid=lastoid;
> ....
> ....
>
> Is there anything one could sanely replace this construct with?
> I personally don't think that using the full primary key is really a good
> option. Say you have a 3 column primary key - one being a "serial", the
> others for example being timestamps, one of them generated with "default"
> options. In order to retrieve the record I just inserted (where I don't know
> the "serial" value or the timestamp) I'd have to
>
> 1) store the "nextval" of the sequence into a variable
> 2) generate the timestamp and store it to a variable
> 3) generate the full insert statement and retain the other values of the
> primary key
> 4) issue a select to get the record.
>
> Personally I think this adds unneccessary overhead. IMHO this diminishes the
> use of defaults and sequences unless there is some easier way to retrieve the
> last record. I must be missing something here - am I ?
>
>        UC
>

If you are using a SERIAL in your PK, why you need the other two
fields? The serial will undoubtly identify a record?

you just retrieve the current value you inserted with currval

--
Atentamente,
Jaime Casanova
(DBA: DataBase Aniquilator ;)

Re: 8.1, OID's and plpgsql

From
Martijn van Oosterhout
Date:
On Thu, Dec 01, 2005 at 09:01:05AM -0800, Uwe C. Schroeder wrote:
> Now there's the issue with stored procs. A usual construct would be to
> ...
> ...
> INSERT xxxxxx;
> GET DIAGNOSTICS lastoid=RESULT_OID;
> SELECT .... oid=lastoid;
> ....
> ....
>
> Is there anything one could sanely replace this construct with?

currval()?

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

Attachment

Re: 8.1, OID's and plpgsql

From
"Uwe C. Schroeder"
Date:
On Thursday 01 December 2005 10:24, Jaime Casanova wrote:
> On 12/1/05, Uwe C. Schroeder <uwe@oss4u.com> wrote:
> > Hi everyone,
> >
> > in 8.1 by default tables have no OID's anymore. Since OID's are 4 byte
> > it's probably a good idea to discourage the use of them (they produced a
> > lot of trouble in the past anyways, particularly with backup/restores
> > etc)
> >
> > Now there's the issue with stored procs. A usual construct would be to
> > ...
> > ...
> > INSERT xxxxxx;
> > GET DIAGNOSTICS lastoid=RESULT_OID;
> > SELECT .... oid=lastoid;
> > ....
> > ....
> >
> > Is there anything one could sanely replace this construct with?
> > I personally don't think that using the full primary key is really a good
> > option. Say you have a 3 column primary key - one being a "serial", the
> > others for example being timestamps, one of them generated with "default"
> > options. In order to retrieve the record I just inserted (where I don't
> > know the "serial" value or the timestamp) I'd have to
> >
> > 1) store the "nextval" of the sequence into a variable
> > 2) generate the timestamp and store it to a variable
> > 3) generate the full insert statement and retain the other values of the
> > primary key
> > 4) issue a select to get the record.
> >
> > Personally I think this adds unneccessary overhead. IMHO this diminishes
> > the use of defaults and sequences unless there is some easier way to
> > retrieve the last record. I must be missing something here - am I ?
> >
> >        UC
>
> If you are using a SERIAL in your PK, why you need the other two
> fields? The serial will undoubtly identify a record?
>
> you just retrieve the current value you inserted with currval
>

No it doesn't. the serial identifies the record, the timestamp identifies the
version/time-validity of the record.
If a primary key needs to be something as simple as a serial then we could
just keep the OID's as well and pump them up to 32 bytes.

curval() doesn't do it, since that will only identify a group of records since
my PK is not just a simple int4.

sample:

create table xxx (
  id serial,
  field varchar,
 ...
 ...
 valid_from timestamptz
)

PK is id,valid_from
There may be several records with the same id but different valid_from dates.
I'm storing a full timestamp, but the application only uses the date part -
the timestamp is just to correct for timezones.

From the application logic a record is considered valid until a record with a
newer valid_from is found. From that point on the records are referenced
depending on several legal factors (this is commercial insurance, lots of
lawyers and state/fed regulations)


I guess I either stick to the OID's which work fine, or I just have to store
the whole PK in variables and forget about defaults.

Why not have something like the rowid in oracle?


    UC


Re: 8.1, OID's and plpgsql

From
Jaime Casanova
Date:
On 12/1/05, Uwe C. Schroeder <uwe@oss4u.com> wrote:
> On Thursday 01 December 2005 10:24, Jaime Casanova wrote:
> > On 12/1/05, Uwe C. Schroeder <uwe@oss4u.com> wrote:
> > > Hi everyone,
> > >
> > > in 8.1 by default tables have no OID's anymore. Since OID's are 4 byte
> > > it's probably a good idea to discourage the use of them (they produced a
> > > lot of trouble in the past anyways, particularly with backup/restores
> > > etc)
> > >
> > > Now there's the issue with stored procs. A usual construct would be to
> > > ...
> > > ...
> > > INSERT xxxxxx;
> > > GET DIAGNOSTICS lastoid=RESULT_OID;
> > > SELECT .... oid=lastoid;
> > > ....
> > > ....
> > >
> > > Is there anything one could sanely replace this construct with?
> > > I personally don't think that using the full primary key is really a good
> > > option. Say you have a 3 column primary key - one being a "serial", the
> > > others for example being timestamps, one of them generated with "default"
> > > options. In order to retrieve the record I just inserted (where I don't
> > > know the "serial" value or the timestamp) I'd have to
> > >
> > > 1) store the "nextval" of the sequence into a variable
> > > 2) generate the timestamp and store it to a variable
> > > 3) generate the full insert statement and retain the other values of the
> > > primary key
> > > 4) issue a select to get the record.
> > >
> > > Personally I think this adds unneccessary overhead. IMHO this diminishes
> > > the use of defaults and sequences unless there is some easier way to
> > > retrieve the last record. I must be missing something here - am I ?
> > >
> > >        UC
> >
> > If you are using a SERIAL in your PK, why you need the other two
> > fields? The serial will undoubtly identify a record?
> >
> > you just retrieve the current value you inserted with currval
> >
>
> No it doesn't. the serial identifies the record, the timestamp identifies the
> version/time-validity of the record.

you don't need valid_from to be part of the PK, just the serial...

> If a primary key needs to be something as simple as a serial then we could
> just keep the OID's as well and pump them up to 32 bytes.
>

No. because tables with OIDs are not the default anymore and is not
recomended to use OIDs as PK

> curval() doesn't do it, since that will only identify a group of records since
> my PK is not just a simple int4.
>

currval() identifies the last value you inserted... that's one of the
reason to prefer SERIAL over OIDs... an API for manage them...

> sample:
>
> create table xxx (
>  id serial,
>  field varchar,
>  ...
>  ...
>  valid_from timestamptz
> )
>
> PK is id,valid_from
> There may be several records with the same id but different valid_from dates.
> I'm storing a full timestamp, but the application only uses the date part -
> the timestamp is just to correct for timezones.
>

obviously you are using wrong the datatype serial if you let the
serial column insert always its default then there won't be several
record with the same id

> From the application logic a record is considered valid until a record with a
> newer valid_from is found. From that point on the records are referenced
> depending on several legal factors (this is commercial insurance, lots of
> lawyers and state/fed regulations)
>

and? you still don't need valid_from as part of the PK if id is a serial...

i think what you really want is to make id an integer and then let
valid_from as part of PK...

and make a select to retrieve the valid one

SELECT * FROM xxx WHERE id = ??? ORDER BY valid_from DESC LIMIT 1

>
> I guess I either stick to the OID's which work fine, or I just have to store
> the whole PK in variables and forget about defaults.
>
> Why not have something like the rowid in oracle?
>
>
>        UC
>




--
regards,
Jaime Casanova
(DBA: DataBase Aniquilator ;)

Re: 8.1, OID's and plpgsql

From
"Jim C. Nasby"
Date:
On Thu, Dec 01, 2005 at 07:18:10PM -0800, Uwe C. Schroeder wrote:
> Why not have something like the rowid in oracle?

http://www.postgresql.org/docs/8.1/interactive/datatype-oid.html, search
on ctid. And
http://www.postgresql.org/docs/8.1/interactive/ddl-system-columns.html.

From the 2nd URL:
ctid

    The physical location of the row version within its table. Note that
    although the ctid can be used to locate the row version very
    quickly, a row's ctid will change each time it is updated or moved
    by VACUUM FULL. Therefore ctid is useless as a long-term row
    identifier. The OID, or even better a user-defined serial number,
    should be used to identify logical rows.

Though I think that a lazy vacuum can change (well, technically remove)
a ctid. AFAIK, it's not safe to use a ctid outside of the transaction
you got it in. Though come to think about it, I don't think there's any
way to get the ctid of a row you just inserted anyway...

Maybe the docs should be changed to just say that you should never reuse
a ctid outside of the transaction you obtained the ctid in?
--
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

Re: 8.1, OID's and plpgsql

From
Tom Lane
Date:
"Jim C. Nasby" <jim@nasby.net> writes:
> Maybe the docs should be changed to just say that you should never reuse
> a ctid outside of the transaction you obtained the ctid in?

That's not a sufficient rule either: someone else could still delete or
update the row while your transaction runs.  You'd really have to SELECT
FOR UPDATE or FOR SHARE to be sure the ctid remains stable.  (Of course,
this isn't an issue for the case of a row you just inserted yourself,
since no one else can see it yet to change it.)

The paragraph defining ctid is not the place for a discussion of how it
could be used ... I'm not quite sure where is, though.

            regards, tom lane

Re: 8.1, OID's and plpgsql

From
"Jim C. Nasby"
Date:
On Fri, Dec 02, 2005 at 06:58:39PM -0500, Tom Lane wrote:
> "Jim C. Nasby" <jim@nasby.net> writes:
> > Maybe the docs should be changed to just say that you should never reuse
> > a ctid outside of the transaction you obtained the ctid in?
>
> That's not a sufficient rule either: someone else could still delete or
> update the row while your transaction runs.  You'd really have to SELECT
> FOR UPDATE or FOR SHARE to be sure the ctid remains stable.  (Of course,
> this isn't an issue for the case of a row you just inserted yourself,
> since no one else can see it yet to change it.)
>
> The paragraph defining ctid is not the place for a discussion of how it
> could be used ... I'm not quite sure where is, though.

Maybe the MVCC paragraph?

Related to the original question though, is there actually any way to
get the ctid of a row that was just inserted?
--
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

Re: 8.1, OID's and plpgsql

From
"Jim C. Nasby"
Date:
On Fri, Dec 02, 2005 at 06:58:39PM -0500, Tom Lane wrote:
> "Jim C. Nasby" <jim@nasby.net> writes:
> > Maybe the docs should be changed to just say that you should never reuse
> > a ctid outside of the transaction you obtained the ctid in?
>
> That's not a sufficient rule either: someone else could still delete or
> update the row while your transaction runs.  You'd really have to SELECT
> FOR UPDATE or FOR SHARE to be sure the ctid remains stable.  (Of course,

Erm, even if they do delete or update the row, wouldn't it's ctid still
remain valid since nothing could vacuum it yet? Of course, now it'd
probably see the old version of the row, but that behavior could be
changed so that the database would follow t_ctid in that case.
--
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

Re: 8.1, OID's and plpgsql

From
"Uwe C. Schroeder"
Date:
the ctid seems to be the solution to my problem. I'm inserting the record in a
transaction so the ctid shouldn't change while the transaction isn't finished
(either rolled back or committed).
One question though. How would I get the ctid of the just inserted record. GET
DIAGNOSTICS only handles row count and oid per the docs.

THX

UC


On Friday 02 December 2005 15:58, Tom Lane wrote:
> "Jim C. Nasby" <jim@nasby.net> writes:
> > Maybe the docs should be changed to just say that you should never reuse
> > a ctid outside of the transaction you obtained the ctid in?
>
> That's not a sufficient rule either: someone else could still delete or
> update the row while your transaction runs.  You'd really have to SELECT
> FOR UPDATE or FOR SHARE to be sure the ctid remains stable.  (Of course,
> this isn't an issue for the case of a row you just inserted yourself,
> since no one else can see it yet to change it.)
>
> The paragraph defining ctid is not the place for a discussion of how it
> could be used ... I'm not quite sure where is, though.
>
>             regards, tom lane


Re: 8.1, OID`s and plpgsql

From
"Greg Sabino Mullane"
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


> Related to the original question though, is there actually any way to
> get the ctid of a row that was just inserted?

No. You'd have to identify the rows some other way (a sequence is
the canonical way), and then grab the ctid from that.

- --
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200512042018
http://biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B906714964AC8
-----BEGIN PGP SIGNATURE-----

iD8DBQFDk5WBvJuQZxSWSsgRAnaaAKDswxUhZH4wHAJJDTZSBtTVNY/9/gCgk3La
KWRzIVIeamQZvhr+TaFp4RY=
=Nevb
-----END PGP SIGNATURE-----