Обсуждение: ON DELETE trigger blocks delete from my table
Hi,
I am using postgres 7.4.5 on Redhat Enterprise Linux 3.
My background is really on Oracle, and I am porting a largish database over to postgres.
Here is my problem:
On oracle, I had a table with an “on update or delete” trigger that copied the current row out to an audit table. Works like a champ. On postgres, when I try to delete a row, all it gives back to me is “DELETE 0” and does nothing.
Here is the text of the trigger:
~~~~~~~~~~
CREATE OR REPLACE FUNCTION public.func_job_status_upd()
RETURNS trigger AS
'
begin
insert into x_job_status values ( OLD.job_id, OLD.job_status_type_id, OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date);
return new;
end;
'
LANGUAGE 'plpgsql' VOLATILE;
~~~~~~~~~~
Any help would be appreciated!
Thanks,
naeem
.Anyway, setting the trigger AFTER DELETE works ok.
On Mon, 2004-10-25 at 15:56, Naeem Bari wrote:
Hi,
I am using postgres 7.4.5 on Redhat Enterprise Linux 3.
My background is really on Oracle, and I am porting a largish database over to postgres.
Here is my problem:
On oracle, I had a table with an “on update or delete” trigger that copied the current row out to an audit table. Works like a champ. On postgres, when I try to delete a row, all it gives back to me is “DELETE 0” and does nothing.
Here is the text of the trigger:
~~~~~~~~~~
CREATE OR REPLACE FUNCTION public.func_job_status_upd()
RETURNS trigger AS
'
begin
insert into x_job_status values ( OLD.job_id, OLD.job_status_type_id, OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date);
return new;
end;
'
LANGUAGE 'plpgsql' VOLATILE;
~~~~~~~~~~
Any help would be appreciated!
Thanks,
naeem
Вложения
"Naeem Bari" <naeem.bari@agilissystems.com> writes:
> CREATE OR REPLACE FUNCTION public.func_job_status_upd()
> RETURNS trigger AS
> '
> begin
> insert into x_job_status values ( OLD.job_id, OLD.job_status_type_id,
> OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date);
> return new;
> end;
> '
> LANGUAGE 'plpgsql' VOLATILE;
If this is a BEFORE trigger, you probably need "RETURN OLD". "NEW" will
be NULL in a delete trigger, so you're returning NULL which cancels the
operation.
regards, tom lane
On 10/25/2004 2:56 PM, Naeem Bari wrote: > Hi, > > I am using postgres 7.4.5 on Redhat Enterprise Linux 3. > > My background is really on Oracle, and I am porting a largish database > over to postgres. > > Here is my problem: > > On oracle, I had a table with an "on update or delete" trigger that > copied the current row out to an audit table. Works like a champ. On > postgres, when I try to delete a row, all it gives back to me is "DELETE > 0" and does nothing. > > Here is the text of the trigger: > > ~~~~~~~~~~ > CREATE OR REPLACE FUNCTION public.func_job_status_upd() > RETURNS trigger AS > ' > begin > insert into x_job_status values ( OLD.job_id, OLD.job_status_type_id, > OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date); > return new; There is no NEW row on DELETE. You can either let the trigger fire AFTER, causing its return value to be ignored, or define different trigger procedures for UPDATE/DELETE, or you can check inside the trigger for which event it was actually fired and return NEW/OLD accordingly. Jan > end; > ' > LANGUAGE 'plpgsql' VOLATILE; > ~~~~~~~~~~ > > Any help would be appreciated! > > Thanks, > naeem > -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com #
On 10/25/2004 3:33 PM, Franco Bruno Borghesi wrote: > I've made a test case, and setting the trigger BEFORE DELETE doesn't > delete the rows from the table (but it does execute the trigger, and it > does insert the rows in the audit table), I dont' know why :(. Because the internal variable for NEW is initialize to NULL and returning NULL from a BEFORE trigger silently suppresses the operation on the original row that it was fired for. Jan > > Anyway, setting the trigger AFTER DELETE works ok. > > On Mon, 2004-10-25 at 15:56, Naeem Bari wrote: > >> Hi, >> >> >> >> I am using postgres 7.4.5 on Redhat Enterprise Linux 3. >> >> >> >> My background is really on Oracle, and I am porting a largish database >> over to postgres. >> >> >> >> Here is my problem: >> >> >> >> On oracle, I had a table with an “on update or delete” trigger that >> copied the current row out to an audit table. Works like a champ. On >> postgres, when I try to delete a row, all it gives back to me is >> “DELETE 0” and does nothing. >> >> >> >> Here is the text of the trigger: >> >> >> >> ~~~~~~~~~~ >> >> CREATE OR REPLACE FUNCTION public.func_job_status_upd() >> >> RETURNS trigger AS >> >> ' >> >> begin >> >> insert into x_job_status values ( OLD.job_id, >> OLD.job_status_type_id, OLD.status_date, OLD.notes, >> OLD.edit_person_id, OLD.edit_date); >> >> return new; >> >> end; >> >> ' >> >> LANGUAGE 'plpgsql' VOLATILE; >> >> ~~~~~~~~~~ >> >> >> >> Any help would be appreciated! >> >> >> >> Thanks, >> >> naeem >> >> > -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com #
I understand. Makes sense. Is there anyway for my trigger function to
"know" that it is being called on a delete or on an update? Because I do
need to "return new" on update... and I really don't want to write 2
different functions, one for update and one for delete...
I would change the trigger to fire on "after" rather than before as Jan
Weick suggests, but does that mean that if the trigger fails, the
transaction would be committed anyways?
Thanks for your help!
naeem
-----Original Message-----
From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
Sent: Monday, October 25, 2004 2:48 PM
To: Naeem Bari
Cc: pgsql-general@postgresql.org
Subject: Re: [GENERAL] ON DELETE trigger blocks delete from my table
"Naeem Bari" <naeem.bari@agilissystems.com> writes:
> CREATE OR REPLACE FUNCTION public.func_job_status_upd()
> RETURNS trigger AS
> '
> begin
> insert into x_job_status values ( OLD.job_id,
OLD.job_status_type_id,
> OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date);
> return new;
> end;
> '
> LANGUAGE 'plpgsql' VOLATILE;
If this is a BEFORE trigger, you probably need "RETURN OLD". "NEW" will
be NULL in a delete trigger, so you're returning NULL which cancels the
operation.
regards, tom lane
Ok, a really newbie question - I think I will switch to using "after" rather than "before" - but can I modify the trigger statement without dropping the trigger function? The reason I ask is that I actually wrote a program that takes oracle's DDL and generates all the tables, audit tables, triggers and sequences that I need. So I really have like 50 tables that are affected by this issue - would much rather modify my program than hand fix 50 problems :) BTW, I did not find much that did what my program does. Or maybe I did not look hard enough? Basically my program eats "meta ddl" (pseudo ddl that I cam up with that specifies the table name, the columns, the column that should be a sequence number, whether a table should be audited or not, plus table and column comments) and spits out DDL for both oracle and postgres. Keeps my DDL all nice and neat and consistent, and I have to write only a small amount of DDL to generate a lot of it :) Thanks again for the help guys, Naeem -----Original Message----- From: Jan Wieck [mailto:JanWieck@Yahoo.com] Sent: Monday, October 25, 2004 2:52 PM To: Franco Bruno Borghesi Cc: Naeem Bari; pgsql-general@postgresql.org Subject: Re: [GENERAL] ON DELETE trigger blocks delete from my table On 10/25/2004 3:33 PM, Franco Bruno Borghesi wrote: > I've made a test case, and setting the trigger BEFORE DELETE doesn't > delete the rows from the table (but it does execute the trigger, and it > does insert the rows in the audit table), I dont' know why :(. Because the internal variable for NEW is initialize to NULL and returning NULL from a BEFORE trigger silently suppresses the operation on the original row that it was fired for. Jan > > Anyway, setting the trigger AFTER DELETE works ok. > > On Mon, 2004-10-25 at 15:56, Naeem Bari wrote: > >> Hi, >> >> >> >> I am using postgres 7.4.5 on Redhat Enterprise Linux 3. >> >> >> >> My background is really on Oracle, and I am porting a largish database >> over to postgres. >> >> >> >> Here is my problem: >> >> >> >> On oracle, I had a table with an "on update or delete" trigger that >> copied the current row out to an audit table. Works like a champ. On >> postgres, when I try to delete a row, all it gives back to me is >> "DELETE 0" and does nothing. >> >> >> >> Here is the text of the trigger: >> >> >> >> ~~~~~~~~~~ >> >> CREATE OR REPLACE FUNCTION public.func_job_status_upd() >> >> RETURNS trigger AS >> >> ' >> >> begin >> >> insert into x_job_status values ( OLD.job_id, >> OLD.job_status_type_id, OLD.status_date, OLD.notes, >> OLD.edit_person_id, OLD.edit_date); >> >> return new; >> >> end; >> >> ' >> >> LANGUAGE 'plpgsql' VOLATILE; >> >> ~~~~~~~~~~ >> >> >> >> Any help would be appreciated! >> >> >> >> Thanks, >> >> naeem >> >> > -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com #
On 10/25/2004 3:47 PM, Tom Lane wrote: > "Naeem Bari" <naeem.bari@agilissystems.com> writes: >> CREATE OR REPLACE FUNCTION public.func_job_status_upd() >> RETURNS trigger AS >> ' >> begin >> insert into x_job_status values ( OLD.job_id, OLD.job_status_type_id, >> OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date); >> return new; >> end; >> ' >> LANGUAGE 'plpgsql' VOLATILE; > > If this is a BEFORE trigger, you probably need "RETURN OLD". "NEW" will > be NULL in a delete trigger, so you're returning NULL which cancels the > operation. ... which would then again not work for the UPDATE case (not with the same internal consequences though). Jan > > regards, tom lane > > ---------------------------(end of broadcast)--------------------------- > TIP 2: you can get off all lists at once with the unregister command > (send "unregister YourEmailAddressHere" to majordomo@postgresql.org) -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com #
On 10/25/2004 3:53 PM, Naeem Bari wrote:
> I understand. Makes sense. Is there anyway for my trigger function to
> "know" that it is being called on a delete or on an update? Because I do
> need to "return new" on update... and I really don't want to write 2
> different functions, one for update and one for delete...
>
> I would change the trigger to fire on "after" rather than before as Jan
> Weick suggests, but does that mean that if the trigger fails, the
> transaction would be committed anyways?
The variable TG_OP contains a string of 'INSERT', 'UPDATE' or 'DELETE'
as per the documentation:
http://www.postgresql.org/docs/current/static/plpgsql-trigger.html
Making it an AFTER trigger still ensures that the transaction is rolled
back if the trigger fails. What it also ensures is that no trigger fired
later can modify the NEW row after your auditing already took place. As
your trigger is, this doesn't matter to you. But as soon as you include
some new value in your auditing table you might be surprised not to find
that new value in the row.
In PostgreSQL a BEFORE trigger procedure on INSERT or UPDATE can modify
values in NEW because it is called BEFORE the new row is actually stored
in the table. This is usefull for enforcing timestamps, usernames,
derived values, you name it. AFTER triggers can't do that and are
guaranteed to see the values that really have been stored.
Jan
>
> Thanks for your help!
> naeem
>
> -----Original Message-----
> From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
> Sent: Monday, October 25, 2004 2:48 PM
> To: Naeem Bari
> Cc: pgsql-general@postgresql.org
> Subject: Re: [GENERAL] ON DELETE trigger blocks delete from my table
>
> "Naeem Bari" <naeem.bari@agilissystems.com> writes:
>> CREATE OR REPLACE FUNCTION public.func_job_status_upd()
>> RETURNS trigger AS
>> '
>> begin
>> insert into x_job_status values ( OLD.job_id,
> OLD.job_status_type_id,
>> OLD.status_date, OLD.notes, OLD.edit_person_id, OLD.edit_date);
>> return new;
>> end;
>> '
>> LANGUAGE 'plpgsql' VOLATILE;
>
> If this is a BEFORE trigger, you probably need "RETURN OLD". "NEW" will
> be NULL in a delete trigger, so you're returning NULL which cancels the
> operation.
>
> regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/docs/faqs/FAQ.html
--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me. #
#================================================== JanWieck@Yahoo.com #
On Mon, 2004-10-25 at 15:09 -0500, Naeem Bari wrote: > Ok, a really newbie question - I think I will switch to using "after" > rather than "before" - but can I modify the trigger statement without > dropping the trigger function? CREATE OR REPLACE FUNCTION ... -- Oliver Elphick olly@lfix.co.uk Isle of Wight http://www.lfix.co.uk/oliver GPG: 1024D/A54310EA 92C8 39E7 280E 3631 3F0E 1EC0 5664 7A2F A543 10EA ======================================== "Only take heed to thyself, and keep thy soul diligently, lest thou forget the things which thine eyes have seen, and lest they depart from thy heart all the days of thy life; but teach them to thy sons, and to thy sons' sons..." Deuteronomy 4:9
Interesting about the meta DDL. I wrote a very small language called QDL
for Query Description Language that uses the same idea. You feed QDL and
the SQL schema into the compiler and it writes C modules with embedded SQL.
Makes porting my application from one database to another a snap from the
application's perspective. It also makes embedded SQL easier to work with
than it normally is, but it's still less flexible than dynamic functions.
Embedded SQL is better than dynamic query building for safety critical full
path testing, and this method makes it more manageable.
Rick
"Naeem Bari"
<naeem.bari@agilissyste To: "Jan Wieck" <JanWieck@Yahoo.com>, "Franco Bruno
Borghesi"
ms.com> <franco@akyasociados.com.ar>
Sent by: cc: <pgsql-general@postgresql.org>
pgsql-general-owner@pos Subject: Re: [GENERAL] ON DELETE trigger blocks delete from my
table
tgresql.org
10/25/2004 03:09 PM
Ok, a really newbie question - I think I will switch to using "after"
rather than "before" - but can I modify the trigger statement without
dropping the trigger function? The reason I ask is that I actually wrote
a program that takes oracle's DDL and generates all the tables, audit
tables, triggers and sequences that I need. So I really have like 50
tables that are affected by this issue - would much rather modify my
program than hand fix 50 problems :)
BTW, I did not find much that did what my program does. Or maybe I did
not look hard enough? Basically my program eats "meta ddl" (pseudo ddl
that I cam up with that specifies the table name, the columns, the
column that should be a sequence number, whether a table should be
audited or not, plus table and column comments) and spits out DDL for
both oracle and postgres. Keeps my DDL all nice and neat and consistent,
and I have to write only a small amount of DDL to generate a lot of it
:)
Thanks again for the help guys,
Naeem
-----Original Message-----
From: Jan Wieck [mailto:JanWieck@Yahoo.com]
Sent: Monday, October 25, 2004 2:52 PM
To: Franco Bruno Borghesi
Cc: Naeem Bari; pgsql-general@postgresql.org
Subject: Re: [GENERAL] ON DELETE trigger blocks delete from my table
On 10/25/2004 3:33 PM, Franco Bruno Borghesi wrote:
> I've made a test case, and setting the trigger BEFORE DELETE doesn't
> delete the rows from the table (but it does execute the trigger, and
it
> does insert the rows in the audit table), I dont' know why :(.
Because the internal variable for NEW is initialize to NULL and
returning NULL from a BEFORE trigger silently suppresses the operation
on the original row that it was fired for.
Jan
>
> Anyway, setting the trigger AFTER DELETE works ok.
>
> On Mon, 2004-10-25 at 15:56, Naeem Bari wrote:
>
>> Hi,
>>
>>
>>
>> I am using postgres 7.4.5 on Redhat Enterprise Linux 3.
>>
>>
>>
>> My background is really on Oracle, and I am porting a largish
database
>> over to postgres.
>>
>>
>>
>> Here is my problem:
>>
>>
>>
>> On oracle, I had a table with an "on update or delete" trigger that
>> copied the current row out to an audit table. Works like a champ. On
>> postgres, when I try to delete a row, all it gives back to me is
>> "DELETE 0" and does nothing.
>>
>>
>>
>> Here is the text of the trigger:
>>
>>
>>
>> ~~~~~~~~~~
>>
>> CREATE OR REPLACE FUNCTION public.func_job_status_upd()
>>
>> RETURNS trigger AS
>>
>> '
>>
>> begin
>>
>> insert into x_job_status values ( OLD.job_id,
>> OLD.job_status_type_id, OLD.status_date, OLD.notes,
>> OLD.edit_person_id, OLD.edit_date);
>>
>> return new;
>>
>> end;
>>
>> '
>>
>> LANGUAGE 'plpgsql' VOLATILE;
>>
>> ~~~~~~~~~~
>>
>>
>>
>> Any help would be appreciated!
>>
>>
>>
>> Thanks,
>>
>> naeem
>>
>>
>
--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me. #
#================================================== JanWieck@Yahoo.com #
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
naeem.bari@agilissystems.com ("Naeem Bari") writes:
> I understand. Makes sense. Is there anyway for my trigger function to
> "know" that it is being called on a delete or on an update? Because I do
> need to "return new" on update... and I really don't want to write 2
> different functions, one for update and one for delete...
>
Yes, plpgsql sets a variable TG_OP to INSERT, UPDATE or DELETE.
so, for example
IF ( TG_OP = ''DELETE'' ) THEN
RETURN old;
ELSE
RETURN new;
END IF;
--
Remove -42 for email