Thread: rewriting values with before trigger

rewriting values with before trigger

From
Robert Treat
Date:
Is there a way to use triggers to rewrite data before determining if the
data for that field is valid?

postgres=# create table foo (
postgres(# bar timestamptz
postgres(# );
CREATE
postgres=# create or replace function test() returns opaque as '
postgres'# begin
postgres'# NEW.bar := NULL;
postgres'# return NEW;
postgres'# end;
postgres'# ' language 'plpgsql';
CREATE
postgres=# create trigger baz before insert on foo for each row execute
procedure test();
CREATE
postgres=# insert into foo values (now());
INSERT 411474706 1
postgres=# select * from foo;
 bar
-----

(1 row)

postgres=# insert into foo values ('');
ERROR:  Bad timestamp external representation ''

Is there anyway to do be able to change the '' into NULL before data
validity is checked with a trigger?

(FWIW this is 7.2, if this would actually work in 7.3 please lmk)


TIA,
Robert Treat


Re: [SQL] rewriting values with before trigger

From
Josh Berkus
Date:
Robert,

> Is there anyway to do be able to change the '' into NULL before data
> validity is checked with a trigger?

What about using a RULE instead?

--
Josh Berkus
Aglio Database Solutions
San Francisco


Re: rewriting values with before trigger

From
"Nigel J. Andrews"
Date:
On 24 Apr 2003, Robert Treat wrote:

> Is there a way to use triggers to rewrite data before determining if the
> data for that field is valid?
>
> ...
>
> postgres=# insert into foo values ('');
> ERROR:  Bad timestamp external representation ''
>
> Is there anyway to do be able to change the '' into NULL before data
> validity is checked with a trigger?
>
> (FWIW this is 7.2, if this would actually work in 7.3 please lmk)

Just so you know 7.3 is the same. I've just been doing something similar,
i.e. wanting to get untyped values into a before trigger but then it's
eminently sensible for that to not be possible.

I hadn't really considered rules but then the process I wanted done was way to
complicated for one of those.

Fortunately the design is such that I could just move the code I would have
written in the trigger into the access function that the middle layer is
supposed to use.


--
Nigel J. Andrews


Re: [SQL] rewriting values with before trigger

From
Robert Treat
Date:
On Thu, 2003-04-24 at 12:39, Josh Berkus wrote:
> Robert,
>
> > Is there anyway to do be able to change the '' into NULL before data
> > validity is checked with a trigger?
>
> What about using a RULE instead?
>

RULE's follow this same behavior, erroring out if the data is not a
valid timestamp. (At least I've not been able to write a rule that
doesn't follow this) In fact you actually can't create the rule if you
have a where clause that isn't a proper matching datatype.

I seem to recall a solution for folks who need '' to represent 0 in int
fields was to use triggers or rules, but I guess that really isn't
possible :-(

Robert Treat




Re: [SQL] rewriting values with before trigger

From
Dennis Gearon
Date:
How about putting the data validity and conversion routine in ONE trigger?

OR, deliberately name your triggers with alphanumerical prefixes that forces them to fire in a certain order, and
makingthe trigger that does the conversion fire first? 

I have no idea how the transport of a value of '' happens in the parser if it's expecing a NULL/INT value, if it would
evenmake it to the trigger stage <shrug>. 

Robert Treat wrote:
> On Thu, 2003-04-24 at 12:39, Josh Berkus wrote:
>
>>Robert,
>>
>>
>>>Is there anyway to do be able to change the '' into NULL before data
>>>validity is checked with a trigger?
>>
>>What about using a RULE instead?
>>
>
>
> RULE's follow this same behavior, erroring out if the data is not a
> valid timestamp. (At least I've not been able to write a rule that
> doesn't follow this) In fact you actually can't create the rule if you
> have a where clause that isn't a proper matching datatype.
>
> I seem to recall a solution for folks who need '' to represent 0 in int
> fields was to use triggers or rules, but I guess that really isn't
> possible :-(
>
> Robert Treat
>
>
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/docs/faqs/FAQ.html
>


Re: [SQL] rewriting values with before trigger

From
Robert Treat
Date:
On Thu, 2003-04-24 at 15:10, Dennis Gearon wrote:
> I have no idea how the transport of a value of '' happens in the parser if it's expecing a NULL/INT value, if it
wouldeven make it to the trigger stage <shrug>. 
>

:-) Thats the problem, it doesn't.

Robert Treat


Re: [SQL] rewriting values with before trigger

From
Dennis Gearon
Date:
Well,
    does ''::INT do anything valuable?
    change column to a string, convert to INTS on the way out, STRINGS on the way in?
    use an external language to make transitions.

Robert Treat wrote:
> On Thu, 2003-04-24 at 15:10, Dennis Gearon wrote:
>
>>I have no idea how the transport of a value of '' happens in the parser if it's expecing a NULL/INT value, if it
wouldeven make it to the trigger stage <shrug>. 
>>
>
>
> :-) Thats the problem, it doesn't.
>
> Robert Treat
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/docs/faqs/FAQ.html
>


Re: [SQL] rewriting values with before trigger

From
Robert Treat
Date:
On Thu, 2003-04-24 at 15:35, Dennis Gearon wrote:
> Well,
>     does ''::INT do anything valuable?

    not in 7.3+, and given my original problem involves timestamps, not in
7.2 either.

>     change column to a string, convert to INTS on the way out, STRINGS on the way in?
>     use an external language to make transitions.
>

yeah, I've thought of some other crazy ways to get around this, but the
problem is due to a bug in the application side. I was hoping I could
write a quick hack (like adding a rule/trigger) to get around this until
the app was fixed, but I'm not going to make my side a kludge when it
isn't one now.


Robert Treat


Re: [SQL] rewriting values with before trigger

From
Dennis Gearon
Date:
I **LIKE** your kind of thinking :-)

Don't mess up the data.

Don't mess up the schema.

It hurts or causes LOTS of labor later on.

Robert Treat wrote:
> On Thu, 2003-04-24 at 15:35, Dennis Gearon wrote:
>
>>Well,
>>    does ''::INT do anything valuable?
>
>
>     not in 7.3+, and given my original problem involves timestamps, not in
> 7.2 either.
>
>
>>    change column to a string, convert to INTS on the way out, STRINGS on the way in?
>>    use an external language to make transitions.
>>
>
>
> yeah, I've thought of some other crazy ways to get around this, but the
> problem is due to a bug in the application side. I was hoping I could
> write a quick hack (like adding a rule/trigger) to get around this until
> the app was fixed, but I'm not going to make my side a kludge when it
> isn't one now.
>
>
> Robert Treat
>
>
>


Re: [SQL] rewriting values with before trigger

From
nolan@celery.tssi.com
Date:
> OR, deliberately name your triggers with alphanumerical prefixes that
> forces them to fire in a certain order, and making the trigger that
> does the conversion fire first?

The SQL 99 standard mandates that triggers fire the order defined, though
the docs say pgsql does it in alphabetical order, possibly because that
was easier to implement.

It is probably better to assume that in any given situation they will fire
in a random order and sequence events yourself when necessary.

That may mean throwing the '' into NULL logic into every trigger for that
table, though there are probably more elegant ways to achieve that result.

If God (or Codd?) had meant us to enable triggers to fire in a particular
order, there would be a 'firing order nnnn' sequencing parameter in the
standard.

--
Mike Nolan


Re: [SQL] rewriting values with before trigger

From
"Matthew Nuzum"
Date:
I'm by no means an expert in this, but maybe this idea would work in your
rule?

Write a function that takes text as it's input and returns either a
timestamp or NULL and then do something like:
return_timestamp(mydate::text)

This way, a valid date will be converted to it's text equiv.  You can then
use the function to look for '' and if true, return NULL and if false cast
the text string back into a timestamp or whatever and return it.

Of course, I don't know if a function that is set to return a timestamp can
even return NULL.  That might cause an error by itself.

--
Matthew Nuzum
www.bearfruit.org
cobalt@bearfruit.org

> -----Original Message-----
> From: pgsql-sql-owner@postgresql.org [mailto:pgsql-sql-
> owner@postgresql.org] On Behalf Of Robert Treat
> Sent: Thursday, April 24, 2003 3:49 PM
> To: gearond@cvc.net
> Cc: Josh Berkus; pgsql-general@postgresql.org; pgsql-sql@postgresql.org
> Subject: Re: [GENERAL] [SQL] rewriting values with before trigger
>
> On Thu, 2003-04-24 at 15:35, Dennis Gearon wrote:
> > Well,
> >     does ''::INT do anything valuable?
>
>     not in 7.3+, and given my original problem involves timestamps, not
> in
> 7.2 either.
>
> >     change column to a string, convert to INTS on the way out, STRINGS
> on the way in?
> >     use an external language to make transitions.
> >
>
> yeah, I've thought of some other crazy ways to get around this, but the
> problem is due to a bug in the application side. I was hoping I could
> write a quick hack (like adding a rule/trigger) to get around this until
> the app was fixed, but I'm not going to make my side a kludge when it
> isn't one now.
>
>
> Robert Treat
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster


Re: [SQL] rewriting values with before trigger

From
"Nigel J. Andrews"
Date:
On Thu, 24 Apr 2003, Matthew Nuzum wrote:

> I'm by no means an expert in this, but maybe this idea would work in your
> rule?
>
> Write a function that takes text as it's input and returns either a
> timestamp or NULL and then do something like:
> return_timestamp(mydate::text)
>
> This way, a valid date will be converted to it's text equiv.  You can then
> use the function to look for '' and if true, return NULL and if false cast
> the text string back into a timestamp or whatever and return it.
>
> Of course, I don't know if a function that is set to return a timestamp can
> even return NULL.  That might cause an error by itself.

No reason why it can't return a null and indeed that's a decent
suggestion. What I was going to (re-)say is based on something I've been doing
recently where the db interface for the application is defined as stored procs
only. That enabled me to simply use functions that took the tables columns as
text and run their magic without compromising the db design by making integer
etc. columns text type.

If Mr Treat can get the app. coders to change

    INSERT INTO mytable ....

into

    SELECT insert_into_mytable(...)

then he can get around the problem.


>
> --
> Matthew Nuzum
> www.bearfruit.org
> cobalt@bearfruit.org
>
> > -----Original Message-----
> > From: pgsql-sql-owner@postgresql.org [mailto:pgsql-sql-
> > owner@postgresql.org] On Behalf Of Robert Treat
> > Sent: Thursday, April 24, 2003 3:49 PM
> > To: gearond@cvc.net
> > Cc: Josh Berkus; pgsql-general@postgresql.org; pgsql-sql@postgresql.org
> > Subject: Re: [GENERAL] [SQL] rewriting values with before trigger
> >
> > On Thu, 2003-04-24 at 15:35, Dennis Gearon wrote:
> > > Well,
> > >     does ''::INT do anything valuable?
> >
> >     not in 7.3+, and given my original problem involves timestamps, not
> > in
> > 7.2 either.
> >
> > >     change column to a string, convert to INTS on the way out, STRINGS
> > on the way in?
> > >     use an external language to make transitions.
> > >
> >
> > yeah, I've thought of some other crazy ways to get around this, but the
> > problem is due to a bug in the application side. I was hoping I could
> > write a quick hack (like adding a rule/trigger) to get around this until
> > the app was fixed, but I'm not going to make my side a kludge when it
> > isn't one now.
> >
> >
> > Robert Treat
> >
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 4: Don't 'kill -9' the postmaster
>
>
> ---------------------------(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
>

--
Nigel J. Andrews


Re: [SQL] rewriting values with before trigger

From
Tom Lane
Date:
Robert Treat <xzilla@users.sourceforge.net> writes:
> yeah, I've thought of some other crazy ways to get around this, but the
> problem is due to a bug in the application side. I was hoping I could
> write a quick hack (like adding a rule/trigger) to get around this until
> the app was fixed, but I'm not going to make my side a kludge when it
> isn't one now.

The only way I can see to do it is to make a view that has 'text'
datatypes in place of real ones, with an ON INSERT rule that invokes
your conversion functions and then inserts the result to the real table.
Dunno if that's too high on your kluge meter.

            regards, tom lane


Re: [SQL] rewriting values with before trigger

From
elein
Date:
I don't think this is a bug at all.
Argument creation has to come before the execution
of the function.  That in this case the argument is a row type
doesn't matter.  It has nothing to do with the content of the
function and everything to do with creating the row NEW.
How can you possibly assign a value to NEW.bar if NEW as
a whole does not exist?

What are you really trying to do here?  Maybe setting the
table column's default to NULL will achieve what you want.

elein

On Thursday 24 April 2003 12:49, Robert Treat wrote:
> On Thu, 2003-04-24 at 15:35, Dennis Gearon wrote:
> > Well,
> >     does ''::INT do anything valuable?
>
>     not in 7.3+, and given my original problem involves timestamps, not in
> 7.2 either.
>
> >     change column to a string, convert to INTS on the way out, STRINGS on
> > the way in? use an external language to make transitions.
>
> yeah, I've thought of some other crazy ways to get around this, but the
> problem is due to a bug in the application side. I was hoping I could
> write a quick hack (like adding a rule/trigger) to get around this until
> the app was fixed, but I'm not going to make my side a kludge when it
> isn't one now.
>
>
> Robert Treat
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster

--
----------------------------------------------------------------------------------------
elein@varlena.com     Database Consulting     www.varlena.com
              I have always depended on the [QA] of strangers.


Re: [SQL] rewriting values with before trigger

From
Robert Treat
Date:
On Thursday 24 April 2003 08:28 pm, elein wrote:
> I don't think this is a bug at all.
> Argument creation has to come before the execution
> of the function.  That in this case the argument is a row type
> doesn't matter.  It has nothing to do with the content of the
> function and everything to do with creating the row NEW.
> How can you possibly assign a value to NEW.bar if NEW as
> a whole does not exist?
>

You misunderstood. I don't think it's a bug in postgresql,  it's a bug in the
application that is hitting against my database. When it doesn't have a value
for the timestamp field, it either needs to drop it from the insert statment
or convert it to null; not send a ''

> What are you really trying to do here?  Maybe setting the
> table column's default to NULL will achieve what you want.
>

I have an application that is inserting information into a table periodically.
Sometimes it passes in timestamps for certain fields, but sometimes it
doesn't have any timestamp information. When it doesn't have information, it
should send NULL. Unfortunatly the app writers wrote it to send ''. Default's
don't work because the app is trying to post data, it's just not a valid
datatype.  Luckily in this instance I can tell the app guys they have to fix
thier app instead of having to muck up the database.

Robert Treat


Re: [SQL] rewriting values with before trigger

From
Josh Berkus
Date:
Robert,

> You misunderstood. I don't think it's a bug in postgresql,  it's a bug in
the
> application that is hitting against my database. When it doesn't have a
value
> for the timestamp field, it either needs to drop it from the insert statment
> or convert it to null; not send a ''

Incidentally, this sort of problem is why most of my apps are based on "push"
data functions.    i.e., instead of the client calling:
INSERT INTO foo VALUES ( id, bar1, bar2, bar3 );
it calls
SELECT df_modify_foo ( id, bar1, bar2, bar3 );

Data-push functions allow me to do a whole array of validation and custom
error message return that would be impractical with triggers.   It also
allows me to build security checks in to the back-end, via:

SELECT df_modify_foo ( user_id, session_key, id, bar1, bar2, bar3 )

... allowing me to check all of the following things:
Does the user have a valid session?
Does the user have rights to foo?
Does the user have a lock on foo?
Is this a new foo record, or a modified one?
etc.

--
-Josh Berkus
 Aglio Database Solutions
 San Francisco


Re: [SQL] rewriting values with before trigger

From
Dennis Gearon
Date:
It's a lot of work to write the functions, but it is the best way to keep the db intact.

Josh Berkus wrote:
> Robert,
>
>
>>You misunderstood. I don't think it's a bug in postgresql,  it's a bug in
>
> the
>
>>application that is hitting against my database. When it doesn't have a
>
> value
>
>>for the timestamp field, it either needs to drop it from the insert statment
>>or convert it to null; not send a ''
>
>
> Incidentally, this sort of problem is why most of my apps are based on "push"
> data functions.    i.e., instead of the client calling:
> INSERT INTO foo VALUES ( id, bar1, bar2, bar3 );
> it calls
> SELECT df_modify_foo ( id, bar1, bar2, bar3 );
>
> Data-push functions allow me to do a whole array of validation and custom
> error message return that would be impractical with triggers.   It also
> allows me to build security checks in to the back-end, via:
>
> SELECT df_modify_foo ( user_id, session_key, id, bar1, bar2, bar3 )
>
> ... allowing me to check all of the following things:
> Does the user have a valid session?
> Does the user have rights to foo?
> Does the user have a lock on foo?
> Is this a new foo record, or a modified one?
> etc.
>


Re: [SQL] rewriting values with before trigger

From
elein
Date:
OK.  I understand what you mean.  I was really focussing
on the engine handling rather than the application behaviour.

elein

On Thursday 24 April 2003 21:03, Robert Treat wrote:
> On Thursday 24 April 2003 08:28 pm, elein wrote:
> > I don't think this is a bug at all.
> > Argument creation has to come before the execution
> > of the function.  That in this case the argument is a row type
> > doesn't matter.  It has nothing to do with the content of the
> > function and everything to do with creating the row NEW.
> > How can you possibly assign a value to NEW.bar if NEW as
> > a whole does not exist?
>
> You misunderstood. I don't think it's a bug in postgresql,  it's a bug in
> the application that is hitting against my database. When it doesn't have a
> value for the timestamp field, it either needs to drop it from the insert
> statment or convert it to null; not send a ''
>
> > What are you really trying to do here?  Maybe setting the
> > table column's default to NULL will achieve what you want.
>
> I have an application that is inserting information into a table
> periodically. Sometimes it passes in timestamps for certain fields, but
> sometimes it doesn't have any timestamp information. When it doesn't have
> information, it should send NULL. Unfortunatly the app writers wrote it to
> send ''. Default's don't work because the app is trying to post data, it's
> just not a valid datatype.  Luckily in this instance I can tell the app
> guys they have to fix thier app instead of having to muck up the database.
>
> Robert Treat

--
----------------------------------------------------------------------------------------
elein@varlena.com     Database Consulting     www.varlena.com
              I have always depended on the [QA] of strangers.