Обсуждение: insert rule doesn't see id field

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

insert rule doesn't see id field

От
Ron Peterson
Дата:
Two seperate problems, really, but first the SQL:

CREATE SEQUENCE person_id_seq;
CREATE TABLE person (
   name_last           VARCHAR( 50 )                       NOT NULL,
   name_first          VARCHAR( 50 )                       NOT NULL,
   id                  INTEGER                       DEFAULT nextval( 'person_id_seq' )                       PRIMARY
KEY
);
CREATE INDEX person_name_idx ON person ( name_last, name_first );

CREATE TRIGGER person_id_noup   BEFORE UPDATE ON person   FOR EACH ROW   EXECUTE PROCEDURE noup( 'id' );

CREATE RULE person_insert AS
ON INSERT TO person
DO   INSERT INTO person_log ( name_last, name_first, mod_type, person_id )   VALUES ( new.name_last, new.name_first,
'I',new.id );
 

(Problem 1)

My insert rule creates a record in person_log just fine.  It inserts
values for all of the fields except person_id.  Why doesn't new.id
contain a value?  Corresponding update and delete rules work as
expected.

(Problem 2)

I thought that the idea behind noup was to protect single columns from
update.  However, when I apply the noup trigger as above, I can't
update /any/ column.  Is this the intended behaviour?

e.g.

directory=# select * from person;name_last | name_first | id
-----------+------------+----Peterson  | Ronald     |  1Humbert   | Humbert    |  2
(2 rows)

directory=# update person set name_first='Ron' where name_first='Ronald';
NOTICE:  id: update not allowed
UPDATE 0

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
BTW, PostgreSQL 7.2.1-2woody2 on Debian.

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Tom Lane
Дата:
Ron Peterson <rpeterso@mtholyoke.edu> writes:
> CREATE RULE person_insert AS
> ON INSERT TO person
> DO
>     INSERT INTO person_log ( name_last, name_first, mod_type, person_id )
>     VALUES ( new.name_last, new.name_first, 'I', new.id );
> [where id is a serial column]

> My insert rule creates a record in person_log just fine.  It inserts
> values for all of the fields except person_id.  Why doesn't new.id
> contain a value?

This is a bug in 7.2.*.  It's fixed in 7.3.  However, your rule will
still not work the way you would like, because rules are macros: the
default expression for id will get evaluated once in the rule and once
in your original query, leading to two different sequence numbers
getting inserted.

The only way to make this example work is to issue the log insertion
from a trigger, not a rule.

> (Problem 2)

> I thought that the idea behind noup was to protect single columns from
> update.  However, when I apply the noup trigger as above, I can't
> update /any/ column.  Is this the intended behaviour?

Idly looking at the source code for contrib/noupdate/noup.c, I don't
believe that it has ever worked as advertised: it seems to reject any
non-null value for the target column, independently of whether the
value is the same as before (which is what I'd have thought it should
do).

Is anyone interested in fixing it?  Or should we just remove it?
If it's been there since 6.4 and you're the first person to try to use
it, as seems to be the case, then I'd have to say that it's a waste of
space in the distribution.
        regards, tom lane


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:

> > I thought that the idea behind noup was to protect single columns from
> > update.  However, when I apply the noup trigger as above, I can't
> > update /any/ column.  Is this the intended behaviour?
> 
> Idly looking at the source code for contrib/noupdate/noup.c, I don't
> believe that it has ever worked as advertised: it seems to reject any
> non-null value for the target column, independently of whether the
> value is the same as before (which is what I'd have thought it should
> do).
> 
> Is anyone interested in fixing it?  Or should we just remove it?
> If it's been there since 6.4 and you're the first person to try to use
> it, as seems to be the case, then I'd have to say that it's a waste of
> space in the distribution.

I'm going to see if I can create this function.  The issue I face is
that I'm allowing certain clients to access parts of a PostgreSQL
database on MS Access via ODBC.  This means I can't really control how
people may try to edit the data.  Well, I could, by using MS Access
security features, but I'd rather do what I can on the back end.

If someone changes an ID field, then as long as foreign key contraints
on other related tables are set to cascade or whatever, that won't be
a problem.  But what if someone updates an ID field to something
higher than my current sequence?  Then when the sequence hits that ID,
it will crap out.  Maybe just try again, but what if that happened to
a bunch of records?  Could be a pain.

So that's the problem I'd like to prevent, for which I think this
function would be useful.  So I'll hack at it and see what I come up
with.  Might not happen immediately, though..

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Wed, Jan 08, 2003 at 01:13:03PM -0500, Ron Peterson wrote:
> On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:
> 
> > > I thought that the idea behind noup was to protect single columns from
> > > update.  However, when I apply the noup trigger as above, I can't
> > > update /any/ column.  Is this the intended behaviour?
> > 
> > Idly looking at the source code for contrib/noupdate/noup.c, I don't
> > believe that it has ever worked as advertised: it seems to reject any
> > non-null value for the target column, independently of whether the
> > value is the same as before (which is what I'd have thought it should
> > do).
> > 
> > Is anyone interested in fixing it?  Or should we just remove it?
> > If it's been there since 6.4 and you're the first person to try to use
> > it, as seems to be the case, then I'd have to say that it's a waste of
> > space in the distribution.
> 
> I'm going to see if I can create this function.

Well, I think I've thunk something up.  Of course I'm happy to submit
my modification for distribution or ridicule, as the case may be.
Where should I submit this?

I made a function noupcols() which takes one or more column names as
arguments.  The function then creates a new tuple by getting the old
values for those columns, and then doing an SPI_modifytuple on the new
tuple using the old values for those columns.

I'm kind of flying by the seat of my pants here, so if anyone would
care to critically review my code, by all means...

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
dev@archonet.com
Дата:
> On Wed, Jan 08, 2003 at 01:13:03PM -0500, Ron Peterson wrote:
>> On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:
>>
>> > > I thought that the idea behind noup was to protect single columns
>> from
>> > > update.  However, when I apply the noup trigger as above, I can't
>> > > update /any/ column.  Is this the intended behaviour?
>> >

>> I'm going to see if I can create this function.
>
> Well, I think I've thunk something up.  Of course I'm happy to submit
> my modification for distribution or ridicule, as the case may be.
> Where should I submit this?
>
> I made a function noupcols() which takes one or more column names as
> arguments.  The function then creates a new tuple by getting the old
> values for those columns, and then doing an SPI_modifytuple on the new
> tuple using the old values for those columns.
>
> I'm kind of flying by the seat of my pants here, so if anyone would
> care to critically review my code, by all means...

Sounds similar to the plpgsql example at:

http://www.archonet.com/pgdocs/lock-field.html

which silently discards changes. It's trivial (apart from quoting issues)
to write a trigger generator to customise the above in plpgsql (see the
Cookbook on techdocs.postgresql.org for examples)

- Richard Huxton


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Thu, Jan 09, 2003 at 07:54:04PM -0000, dev@archonet.com wrote:

> Sounds similar to the plpgsql example at:
> 
> http://www.archonet.com/pgdocs/lock-field.html
> 
> which silently discards changes. It's trivial (apart from quoting issues)
> to write a trigger generator to customise the above in plpgsql (see the
> Cookbook on techdocs.postgresql.org for examples)

Ah - I wish I saw that earlier.  Thanks for pointer.  OTOH, I learned
something...

FWIW (probably just a good laugh):

#include "executor/spi.h"     /* this is what you need to work with SPI */
#include "commands/trigger.h" /* and triggers */
#include <ctype.h>            /* tolower () */
#include <stdlib.h>

extern Datum noupcols (PG_FUNCTION_ARGS);

/*
noupcols () -- revoke permission on column(s)

e.g.

CREATE FUNCTION noupcols ()    RETURNS opaque    AS '/usr/lib/postgresql/lib/noupcols.so'   LANGUAGE 'C';

CREATE TRIGGER person_noupcols   BEFORE UPDATE ON person   FOR EACH ROW   EXECUTE PROCEDURE noupcols( 'name_last', 'id'
);

Based on code from contrib/noup.c

The approach adopted here is to set the values of all of the columns
specified by noupcols to their old values.
*/

PG_FUNCTION_INFO_V1 (noupcols);

Datum
noupcols (PG_FUNCTION_ARGS)
{   TriggerData *trigdata = (TriggerData *) fcinfo->context;   Trigger     *trigger;           /* to get trigger name
*/  Relation    rel;                /* triggered relation */   char        **args;             /* arguments: column
names*/   int         ncols;              /* # of args specified in CREATE TRIGGER */   int         *colindices;
/*array of column indices to modify */   Datum       *oldcolvals;        /* old column values */   HeapTuple   oldtuple
=NULL;    /* tuple before being modified */   HeapTuple   newtuple = NULL;    /* new tuple after user-specified update
*/  HeapTuple   newnewtuple = NULL; /* tuple to return, after restoring newtuple's protected columns to their old
values*/   TupleDesc   tupdesc;            /* tuple description */   bool        isnull;             /* to know is some
columnNULL or not */   int         ret;   int         i;
 
   if (!CALLED_AS_TRIGGER (fcinfo))       elog(ERROR, "noup: not fired by trigger manager");
   if (TRIGGER_FIRED_FOR_STATEMENT (trigdata->tg_event))       elog (ERROR, "noup: can't process STATEMENT events");
   if (TRIGGER_FIRED_BY_INSERT (trigdata->tg_event))       elog (ERROR, "noup: can't process INSERT events");
   else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))       elog (ERROR, "noup: can't process DELETE events");
   oldtuple = trigdata->tg_trigtuple;   newtuple = trigdata->tg_newtuple;
   trigger = trigdata->tg_trigger;   rel = trigdata->tg_relation;
   tupdesc = rel->rd_att;
   ncols = trigger->tgnargs;   args = trigger->tgargs;
   colindices = (int *) malloc (ncols * sizeof (int));
   /* Connect to SPI manager */   if ((ret = SPI_connect()) < 0)       elog (ERROR, "noupcol: SPI_connect returned %d",
ret);
   /* Allocate space to place column values */   oldcolvals = (Datum*) palloc (ncols * sizeof (Datum));
   /* For each column ... */   for (i = 0; i < ncols; i++)   {       /* get index of column in tuple */
colindices[i]= SPI_fnumber (tupdesc, args[i]);
 
       /* Bad guys may give us un-existing column in CREATE TRIGGER */       if (colindices < 0)       {           elog
(ERROR,"noupcols: there is no attribute %s in relation %s",                 args[i],                 SPI_getrelname
(rel));          pfree (oldcolvals);           free (colindices);           SPI_finish ();           return
PointerGetDatum(NULL);       }
 
       /* Get previous value of column */       oldcolvals[i] = SPI_getbinval (oldtuple, tupdesc, colindices[i],
&isnull);  }
 
   /* Restore protected columns to their old values */   newnewtuple = SPI_modifytuple (rel, newtuple, ncols,
colindices,oldcolvals, NULL);
 
   pfree (oldcolvals);   free (colindices);   SPI_finish ();
   if (SPI_result == SPI_ERROR_ARGUMENT) {       elog (ERROR, "noupcols: bad argument to SPI_modifytuple\n");
returnPointerGetDatum (NULL);   }
 
   if (SPI_result == SPI_ERROR_NOATTRIBUTE) {       elog (ERROR, "noupcols: bad attribute value passed to
SPI_modifytuple\n");      return PointerGetDatum (NULL);   }
 
   return PointerGetDatum (newnewtuple);
}


-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Thu, Jan 09, 2003 at 04:50:56PM -0500, Ron Peterson wrote:

>     colindices = (int *) malloc (ncols * sizeof (int));

Of course we should verify that malloc succeeded...

if (colindices == NULL) {elog (ERROR, "noupcol: malloc failed\n");SPI_finish();return PointerGetDatum (NULL);
}

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Tom Lane
Дата:
Ron Peterson <rpeterso@mtholyoke.edu> writes:
> On Thu, Jan 09, 2003 at 04:50:56PM -0500, Ron Peterson wrote:
>> colindices = (int *) malloc (ncols * sizeof (int));

> Of course we should verify that malloc succeeded...

Actually, the correct answer is "you should not be using malloc() in
backend functions".  You should be using palloc, or possibly
MemoryContextAlloc, either of which will elog if it can't get space.

> if (colindices == NULL) {
>     elog (ERROR, "noupcol: malloc failed\n");
>     SPI_finish();
>     return PointerGetDatum (NULL);
> }

This is even more pointless.  Control does not return from elog(ERROR),
so the two following lines are dead code.
        regards, tom lane


Re: insert rule doesn't see id field

От
"Radu-Adrian Popescu"
Дата:
To everyone interested, check out Tom Lane's and Bruce's comments on
pgsql-hackers:
http://archives.postgresql.org/pgsql-hackers/2003-01/msg00446.php
There seems to be some consensus towards removing $ from the list of allowed
operator characters.

Regards,
=====
Radu-Adrian Popescu
CSA, DBA, Developer
Aldratech Ltd.

----- Original Message -----
From: "Ron Peterson" <rpeterso@mtholyoke.edu>
To: <pgsql-sql@postgresql.org>
Sent: Thursday, January 09, 2003 9:12 PM
Subject: Re: [SQL] insert rule doesn't see id field


On Wed, Jan 08, 2003 at 01:13:03PM -0500, Ron Peterson wrote:
> On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:
>
> > > I thought that the idea behind noup was to protect single columns from
> > > update.  However, when I apply the noup trigger as above, I can't
> > > update /any/ column.  Is this the intended behaviour?
> >
> > Idly looking at the source code for contrib/noupdate/noup.c, I don't
> > believe that it has ever worked as advertised: it seems to reject any
> > non-null value for the target column, independently of whether the
> > value is the same as before (which is what I'd have thought it should
> > do).
> >
> > Is anyone interested in fixing it?  Or should we just remove it?
> > If it's been there since 6.4 and you're the first person to try to use
> > it, as seems to be the case, then I'd have to say that it's a waste of
> > space in the distribution.
>
> I'm going to see if I can create this function.

Well, I think I've thunk something up.  Of course I'm happy to submit
my modification for distribution or ridicule, as the case may be.
Where should I submit this?

I made a function noupcols() which takes one or more column names as
arguments.  The function then creates a new tuple by getting the old
values for those columns, and then doing an SPI_modifytuple on the new
tuple using the old values for those columns.

I'm kind of flying by the seat of my pants here, so if anyone would
care to critically review my code, by all means...

--
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ----

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/users-lounge/docs/faq.html





Re: insert rule doesn't see id field

От
"Radu-Adrian Popescu"
Дата:
I'm extremely sorry about the post in this thread ! Had a brain cramp, my
appologies. Should have been Re: [SQL] SQL function parse error.
Terribly sorry again !

=====
Radu-Adrian Popescu
CSA, DBA, Developer
Aldratech Ltd.
----- Original Message -----
From: "Radu-Adrian Popescu" <radu.popescu@aldratech.com>
To: "Ron Peterson" <rpeterso@mtholyoke.edu>; <pgsql-sql@postgresql.org>
Sent: Friday, January 10, 2003 11:31 AM
Subject: Re: [SQL] insert rule doesn't see id field


To everyone interested, check out Tom Lane's and Bruce's comments on
pgsql-hackers:
http://archives.postgresql.org/pgsql-hackers/2003-01/msg00446.php
There seems to be some consensus towards removing $ from the list of allowed
operator characters.

Regards,
=====
Radu-Adrian Popescu
CSA, DBA, Developer
Aldratech Ltd.

----- Original Message -----
From: "Ron Peterson" <rpeterso@mtholyoke.edu>
To: <pgsql-sql@postgresql.org>
Sent: Thursday, January 09, 2003 9:12 PM
Subject: Re: [SQL] insert rule doesn't see id field


On Wed, Jan 08, 2003 at 01:13:03PM -0500, Ron Peterson wrote:
> On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:
>
> > > I thought that the idea behind noup was to protect single columns from
> > > update.  However, when I apply the noup trigger as above, I can't
> > > update /any/ column.  Is this the intended behaviour?
> >
> > Idly looking at the source code for contrib/noupdate/noup.c, I don't
> > believe that it has ever worked as advertised: it seems to reject any
> > non-null value for the target column, independently of whether the
> > value is the same as before (which is what I'd have thought it should
> > do).
> >
> > Is anyone interested in fixing it?  Or should we just remove it?
> > If it's been there since 6.4 and you're the first person to try to use
> > it, as seems to be the case, then I'd have to say that it's a waste of
> > space in the distribution.
>
> I'm going to see if I can create this function.

Well, I think I've thunk something up.  Of course I'm happy to submit
my modification for distribution or ridicule, as the case may be.
Where should I submit this?

I made a function noupcols() which takes one or more column names as
arguments.  The function then creates a new tuple by getting the old
values for those columns, and then doing an SPI_modifytuple on the new
tuple using the old values for those columns.

I'm kind of flying by the seat of my pants here, so if anyone would
care to critically review my code, by all means...

--
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ----

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/users-lounge/docs/faq.html




---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command   (send "unregister YourEmailAddressHere" to
majordomo@postgresql.org)





Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Thu, Jan 09, 2003 at 11:53:42PM -0500, Tom Lane wrote:
> Ron Peterson <rpeterso@mtholyoke.edu> writes:
> > On Thu, Jan 09, 2003 at 04:50:56PM -0500, Ron Peterson wrote:
> >> colindices = (int *) malloc (ncols * sizeof (int));
> 
> > Of course we should verify that malloc succeeded...
> 
> Actually, the correct answer is "you should not be using malloc() in
> backend functions".  You should be using palloc, or possibly
> MemoryContextAlloc, either of which will elog if it can't get space.
> 
> > if (colindices == NULL) {
> >     elog (ERROR, "noupcol: malloc failed\n");
> >     SPI_finish();
> >     return PointerGetDatum (NULL);
> > }
> 
> This is even more pointless.  Control does not return from elog(ERROR),
> so the two following lines are dead code.

Thanks.  Didn't know that.

Not that you're obligated to review my code in any way (i.e. ignore
this question if you have better things to do), but does the rest of
my code look o.k.?  I was pretty pleased with myself that I figured
out how to modify a tuple w/ SPI, and might like to do more of the
same.  I'd rather not develop bad habits, though...

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: noupcol code cleanup

От
Ron Peterson
Дата:
Well, I went through this again myself, and fixed a lot of stuff.  I'm
going to drop this thread, but didn't want the last chunk of code I
posted to be so crappy.  This is what I have come up with, FWIW:

#include "executor/spi.h"     /* this is what you need to work with SPI */
#include "commands/trigger.h" /* and triggers */
#include "utils/lsyscache.h"  /* for get_typlenbyval */

extern Datum noupcols (PG_FUNCTION_ARGS);

/*
noupcols () -- revoke permission on column(s)

e.g.

CREATE FUNCTION noupcols ()    RETURNS opaque    AS '/usr/lib/postgresql/lib/noupcols.so'   LANGUAGE 'C';

CREATE TRIGGER person_noupcols   BEFORE UPDATE ON person   FOR EACH ROW   EXECUTE PROCEDURE noupcols( 'name_last', 'id'
);

Based on code from contrib/noup.c

The approach adopted here is to set the values of all of the columns
specified by noupcols to their old values.
*/

PG_FUNCTION_INFO_V1 (noupcols);

Datum
noupcols (PG_FUNCTION_ARGS)
{   TriggerData *trigdata = (TriggerData *) fcinfo->context;   Trigger     *trigger;           /* to get trigger name
*/  Relation    rel;                /* triggered relation */   char        **args;             /* arguments: column
names*/   int         ncols;              /* # of args specified in CREATE TRIGGER */   int         *colindices;
/*array of column indices to modify */   Datum       *oldcolvals;        /* old column values */   Datum
*newcolval;        /* new column value */   HeapTuple   oldtuple = NULL;    /* tuple before being modified */
HeapTuple  newtuple = NULL;    /* new tuple after user-specified update */   HeapTuple   newnewtuple = NULL; /* tuple
toreturn, after restoring newtuple's protected columns to their old values */   TupleDesc   tupdesc;            /*
tupledescription */   bool        isnull;             /* to know is some column NULL or not */   Oid         oid;
        /* is Datum of type ByVal? */   bool        typByVal;           /* is Datum of type ByVal? */   int16
typLen;            /* Datum size */   int         ret;   int         i;
 
   if (!CALLED_AS_TRIGGER (fcinfo))       elog(ERROR, "noup: not fired by trigger manager");
   if (TRIGGER_FIRED_FOR_STATEMENT (trigdata->tg_event))       elog (ERROR, "noup: can't process STATEMENT events");
   if (TRIGGER_FIRED_BY_INSERT (trigdata->tg_event))       elog (ERROR, "noup: can't process INSERT events");
   else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))       elog (ERROR, "noup: can't process DELETE events");
   oldtuple = trigdata->tg_trigtuple;   newtuple = trigdata->tg_newtuple;
   trigger = trigdata->tg_trigger;   rel = trigdata->tg_relation;
   tupdesc = rel->rd_att;
   ncols = trigger->tgnargs;   args = trigger->tgargs;
   colindices = (int *) palloc (ncols * sizeof (int));
   /* Connect to SPI manager */   if ((ret = SPI_connect()) < 0)       elog (ERROR, "noupcol: SPI_connect returned %d",
ret);
   /* Allocate space to place column values */   oldcolvals = (Datum*) palloc (ncols * sizeof (Datum));   newcolval =
(Datum*)palloc (sizeof (Datum));
 
   /* For each column ... */   for (i = 0; i < ncols; i++)   {       /* get index of column in tuple */
colindices[i]= SPI_fnumber (tupdesc, args[i]);
 
       /* Bad guys may give us un-existing column in CREATE TRIGGER */       if (colindices[i] ==
SPI_ERROR_NOATTRIBUTE){           elog (ERROR, "noupcols: there is no attribute '%s' in relation '%s'",
args[i],                SPI_getrelname (rel));       }
 
       /* Get previous value of column */       oldcolvals[i] = SPI_getbinval (oldtuple, tupdesc, colindices[i],
&isnull);      *newcolval = SPI_getbinval (newtuple, tupdesc, colindices[i], &isnull);
 
      /* need this for datumIsEqual, below */       oid = SPI_gettypeid (tupdesc, colindices[i]);
get_typlenbyval(oid, &typLen, &typByVal );
 
        /* if an update is attempted on a locked column, post a notification that it isn't allowed */       if (!
datumIsEqual(oldcolvals[i], *newcolval, typByVal, typLen)) {           elog (NOTICE, "noupcols: attribute '%s' in
relation'%s' is locked",                 args[i],                 SPI_getrelname (rel));       }          }
 
   /* Restore protected columns to their old values */   newnewtuple = SPI_modifytuple (rel, newtuple, ncols,
colindices,oldcolvals, NULL);
 
   if (SPI_result == SPI_ERROR_ARGUMENT) {       elog (ERROR, "noupcols: bad argument to SPI_modifytuple\n");   }
   if (SPI_result == SPI_ERROR_NOATTRIBUTE) {       elog (ERROR, "noupcols: bad attribute value passed to
SPI_modifytuple\n");  }
 
   pfree (oldcolvals);   pfree (newcolval);   pfree (colindices);   SPI_finish ();
   return PointerGetDatum (newnewtuple);
}


-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Ron Peterson
Дата:
On Tue, Jan 07, 2003 at 11:01:08AM -0500, Tom Lane wrote:
> Ron Peterson <rpeterso@mtholyoke.edu> writes:
> > CREATE RULE person_insert AS
> > ON INSERT TO person
> > DO
> >     INSERT INTO person_log ( name_last, name_first, mod_type, person_id )
> >     VALUES ( new.name_last, new.name_first, 'I', new.id );
> > [where id is a serial column]
> 
> > My insert rule creates a record in person_log just fine.  It inserts
> > values for all of the fields except person_id.  Why doesn't new.id
> > contain a value?
> 
> This is a bug in 7.2.*.  It's fixed in 7.3.  However, your rule will
> still not work the way you would like, because rules are macros: the
> default expression for id will get evaluated once in the rule and once
> in your original query, leading to two different sequence numbers
> getting inserted.

I just installed 7.3.1.  It works now, as you say, but it breaks if the
id field being updated by an insert rule references the id field it's
logging.  And like you say, the rule also updates the sequence - not a
killer, but not so great.

I started writing a trigger.  Meanwhile I'm just going to log updates
and deletes.  After all, if a record has never been updated or deleted,
what's to audit?

One thing's tripping me up a bit while writing a trigger (in C - I like
C).  I'd like the trigger function arguments to specify an attribute
mapping from the table being logged to the log table - e.g. logfun
('logtable', 'oldatt1', 'newatt1', 'oldatt2', 'newatt2', etc.).  I
thought I'd be good and check that the types and field lengths match
before attempting to insert the log record.  I can find out this info
for the relation pulling the trigger easy enought, but how would I go
about getting this info when all I have is the table/field name?  I
could create and execute a SQL query something like the following, but
is that really the way to get at this info in C code?

select relname, attname, typname, typlen
from pg_class c, pg_attribute a, pg_type t
where c.oid=a.attrelid and a.atttypid=t.oid and get just the relevant record(s);

-- 
Ron Peterson                          -o)
Network & Systems Manager             /\\
Mount Holyoke College                _\_v
http://www.mtholyoke.edu/~rpeterso   ---- 


Re: insert rule doesn't see id field

От
Tom Lane
Дата:
Ron Peterson <rpeterso@mtholyoke.edu> writes:
> I can find out this info
> for the relation pulling the trigger easy enought, but how would I go
> about getting this info when all I have is the table/field name?  I
> could create and execute a SQL query something like the following, but
> is that really the way to get at this info in C code?

Open the target relation and examine its tuple descriptor ...
        regards, tom lane