pg.ddx.io  pgsql-sql@postgresql.org mailing list archive  
help / color / mirror / Atom feed
trigger conversion advice needed
3+ messages / 2 participants
[nested] [flat]

* trigger conversion advice needed
@ 2003-11-26 11:51  Clint Stotesbery <cstotes@hotmail.com>
  0 siblings, 1 reply; 3+ messages in thread

From: Clint Stotesbery @ 2003-11-26 11:51 UTC (permalink / raw)
  To: pgsql-sql

I'm working on converting a simple trigger from Oracle to Postgres and I 
have a couple ofl questions that I need some help on please. First here's 
the Oracle trigger:

CREATE OR REPLACE TRIGGER t_ship_date
AFTER UPDATE OR INSERT OF order_date ON orders
BEGIN
   UPDATE orders
   SET ship_date = working_5days(order_date);
END;
/

When I was working on converting the trigger I noticed that Postgres doesn't 
have the OF table_attribute ON syntax support. I just want the trigger to 
fire when the order_date field in the order table is updated or inserted 
like it is specified in the Oracle trigger specification above. So I did 
this in Postgres:

CREATE OR REPLACE FUNCTION t_ship_date()
RETURNS TRIGGER AS '
   BEGIN
      UPDATE orders
      SET ship_date = working_5days(new.order_date);

      RETURN NEW;
   END;
   ' LANGUAGE 'plpgsql';

I justed used new.order_date in the Postgres one version. I'm pretty sure 
that this isn't going to work, it will probably update every ship_date which 
is not what I want. I just want to update the ship_date when the record's 
order_date is updated. Is there some way in Postgres to specify a trigger to 
fire only when a certain field in a table is changed or inserted (like I had 
in the Oracle version)? I couldn't find anything for triggers to do that in 
the docs so I hope someone can shed some light on this for me. I thought 
maybe something like this could work too (probably closer to being correct):

CREATE OR REPLACE FUNCTION t_ship_date()
RETURNS TRIGGER AS '
   BEGIN
      IF TG_OP = ''INSERT'' THEN
         UPDATE orders
         SET ship_date = working_5days(new.order_date)
         where order_no = new.order_no;
      ELSIF TG_OP =''UPDATE'' THEN
         UPDATE orders
         SET ship_date = working_5days(new.order_date)
         where order_no = old.order_no;
      END IF;

      RETURN NEW;
   END;
   ' LANGUAGE 'plpgsql';

The working_5days function just adds 5 business days to a date fyi. Now the 
second question I have is due to an error I keep getting when I try and make 
the trigger definition below:

CREATE TRIGGER t_ship_date AFTER UPDATE OR INSERT ON orders
EXECUTE PROCEDURE t_ship_date();

I always get a parse error at or near execute. What am I doing wrong? If I 
could get the trigger to compile then I could test it to see if it works the 
same as the Oracle version. I wouldn't even have to ask the first question 
if I could get it to compile but I thought I might as well ask anyway so I 
don't have to post another message. Thanks for the help.
-Clint

P.S. 7.3.4 is the postgres version on the server.

_________________________________________________________________
Has one of the new viruses infected your computer?  Find out with a FREE 
online computer virus scan from McAfee. Take the FreeScan now!  
http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963




^ permalink  raw  reply  [nested|flat] 3+ messages in thread

* Re: trigger conversion advice needed
@ 2003-11-26 15:40  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Clint Stotesbery <cstotes@hotmail.com>
  0 siblings, 0 replies; 3+ messages in thread

From: Tom Lane @ 2003-11-26 15:40 UTC (permalink / raw)
  To: cstotesbery@acm.org; +Cc: pgsql-sql

"Clint Stotesbery" <cstotes@hotmail.com> writes:
> I'm working on converting a simple trigger from Oracle to Postgres and I 
> have a couple ofl questions that I need some help on please. First here's 
> the Oracle trigger:

> CREATE OR REPLACE TRIGGER t_ship_date
> AFTER UPDATE OR INSERT OF order_date ON orders
> BEGIN
>    UPDATE orders
>    SET ship_date = working_5days(order_date);
> END;

It looks to me like this trigger implicitly assumes that an UPDATE
command would only affect the row it was fired for --- which is not at
all how Postgres will interpret such a command.

(Alternatively, maybe the trigger actually does result in recomputing
every row's ship_date?  You would only notice if ship_date had been
changed manually in some rows to be different from order_date + 5...)

Guessing at what is actually wanted here, my inclination would be to use
a BEFORE INSERT OR UPDATE trigger and to detect updates by change from
OLD to NEW.  The INSERT case would simply do

	NEW.ship_date := working_5days(NEW.order_date);
	RETURN NEW;

The UPDATE case would look like

	IF NEW.order_date <> OLD.order_date THEN
	    NEW.ship_date := working_5days(NEW.order_date);
	END IF;
	RETURN NEW;

Pretty simple when you get the hang of it.

> CREATE TRIGGER t_ship_date AFTER UPDATE OR INSERT ON orders
> EXECUTE PROCEDURE t_ship_date();

> I always get a parse error at or near execute.

You need to say FOR EACH ROW in there too.

			regards, tom lane



^ permalink  raw  reply  [nested|flat] 3+ messages in thread

* Re: trigger conversion advice needed
@ 2003-11-26 15:56  Clint Stotesbery <cstotes@hotmail.com>
  0 siblings, 0 replies; 3+ messages in thread

From: Clint Stotesbery @ 2003-11-26 15:56 UTC (permalink / raw)
  To: tgl@sss.pgh.pa.us; +Cc: pgsql-sql

Thanks for the advice Tom. I figured out why my create trigger statement 
wouldn't compile. Postgres expects a FOR EACH ROW or FOR EACH STATEMENT 
clause before the EXECUTE portion. Oracle assumes a statement level trigger 
unless you specify it to be for each row. In addition Oracle allows for 
specific columns to be monitored for updates like I had in the Oracle 
trigger (AFTER UPDATE OR INSERT OF order_date ON orders).

Well I ended up adding FOR EACH STATEMENT to the Postgres version after the 
first email. I got a message back that said statement triggers weren't 
implemented in Postgres yet even though according to the 7.3 docs it can be 
used. I looked at the changelog for 7.4 and it said:
"Add statement-level triggers (Neil)

While this allows a trigger to fire at the end of a statement, it does not 
allow the trigger to access all rows modified by the statement. This 
capability is planned for a future release."

I wonder if that means that I can specify FOR EACH STATEMENT and have it 
compile fine but it seems like that I can't acccess new and old though still 
in 7.4. I'll have to experiment with what you suggested and perhaps look 
into upgrading to 7.4 as well.
Thanks,
Clint




----Original Message Follows----
From: Tom Lane <tgl@sss.pgh.pa.us>
To: cstotesbery@acm.org
CC: pgsql-sql@postgresql.org
Subject: Re: [SQL] trigger conversion advice needed
Date: Wed, 26 Nov 2003 10:40:08 -0500
Received: from alias2.acm.org ([199.222.69.92]) by mc11-f24.hotmail.com with 
Microsoft SMTPSVC(5.0.2195.6713); Wed, 26 Nov 2003 07:40:10 -0800
Received: from sss.pgh.pa.us ([192.204.191.242])        by alias2.acm.org 
(ACM Email Forwarding Service) with ESMTP id CRY73883        for 
<cstotesbery@acm.org>; Wed, 26 Nov 2003 10:40:10 -0500
Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1])by 
sss.pgh.pa.us (8.12.10/8.12.10) with ESMTP id hAQFe819015058;Wed, 26 Nov 
2003 10:40:08 -0500 (EST)
X-Message-Info: JGTYoYF78jE74k1WFZAS8n73gEHv7D0r
In-reply-to: <BAY9-F11pKkVavr8nCy0001de1f@hotmail.com>
References: <BAY9-F11pKkVavr8nCy0001de1f@hotmail.com>
Comments: In-reply-to "Clint Stotesbery" <cstotes@hotmail.com>message dated 
"Wed, 26 Nov 2003 11:51:42 +0000"
Message-ID: <15057.1069861208@sss.pgh.pa.us>
Return-Path: tgl@sss.pgh.pa.us
X-OriginalArrivalTime: 26 Nov 2003 15:40:10.0631 (UTC) 
FILETIME=[936E3170:01C3B433]

"Clint Stotesbery" <cstotes@hotmail.com> writes:
 > I'm working on converting a simple trigger from Oracle to Postgres and I
 > have a couple ofl questions that I need some help on please. First here's
 > the Oracle trigger:

 > CREATE OR REPLACE TRIGGER t_ship_date
 > AFTER UPDATE OR INSERT OF order_date ON orders
 > BEGIN
 >    UPDATE orders
 >    SET ship_date = working_5days(order_date);
 > END;

It looks to me like this trigger implicitly assumes that an UPDATE
command would only affect the row it was fired for --- which is not at
all how Postgres will interpret such a command.

(Alternatively, maybe the trigger actually does result in recomputing
every row's ship_date?  You would only notice if ship_date had been
changed manually in some rows to be different from order_date + 5...)

Guessing at what is actually wanted here, my inclination would be to use
a BEFORE INSERT OR UPDATE trigger and to detect updates by change from
OLD to NEW.  The INSERT case would simply do

	NEW.ship_date := working_5days(NEW.order_date);
	RETURN NEW;

The UPDATE case would look like

	IF NEW.order_date <> OLD.order_date THEN
	    NEW.ship_date := working_5days(NEW.order_date);
	END IF;
	RETURN NEW;

Pretty simple when you get the hang of it.

 > CREATE TRIGGER t_ship_date AFTER UPDATE OR INSERT ON orders
 > EXECUTE PROCEDURE t_ship_date();

 > I always get a parse error at or near execute.

You need to say FOR EACH ROW in there too.

			regards, tom lane

_________________________________________________________________
Set yourself up for fun at home!  Get tips on home entertainment equipment, 
video game reviews, and more here.   
http://special.msn.com/home/homeent.armx




^ permalink  raw  reply  [nested|flat] 3+ messages in thread


end of thread, other threads:[~2003-11-26 15:56 UTC | newest]

Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2003-11-26 11:51 trigger conversion advice needed Clint Stotesbery <cstotes@hotmail.com>
2003-11-26 15:40 ` Tom Lane <tgl@sss.pgh.pa.us>
2003-11-26 15:56 Re: trigger conversion advice needed Clint Stotesbery <cstotes@hotmail.com>

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox