Обсуждение: BUG #4380: Comparison of OLD and NEW columns in trigger does not always work
BUG #4380: Comparison of OLD and NEW columns in trigger does not always work
От
"Daryl Joubert"
Дата:
The following bug has been logged online: Bug reference: 4380 Logged by: Daryl Joubert Email address: daryl@ftcxpress.com PostgreSQL version: 8.3.3 Operating system: WinXP SP2 Description: Comparison of OLD and NEW columns in trigger does not always work Details: When comparing NEW.column_name to OLD.column_name in 'PG_UPDATE' operation in a trigger, I get unpredictable results. Use the following script to create the "Business Partner" table and its trigger, then add a few rows of data to "First Name", "Middle Name" and "Last Name" using pgAdmin, and watch how "Name" is built up for the former 3 columns. Then: change the "Middle Name" column of an existing row repeatedly and you should see that sometimes "Name" is updated, sometimes not. I can repeat the problem here within 5 to 10 changes of "Middle Name". Am I doing something wrong? Here is the script: CREATE TABLE "Business Partner" ( "Partner Number" serial NOT NULL, "First Name" character varying, "Middle Name" character varying, "Last Name" character varying, "Name" character varying, CONSTRAINT "PK Business Partner" PRIMARY KEY ("Partner Number") ) WITH (OIDS=FALSE); CREATE FUNCTION t_business_partner() RETURNS trigger AS $BODY$ DECLARE BEGIN IF (TG_OP = 'INSERT') THEN IF NEW."Name" IS NULL OR NEW."Name" = '' THEN IF NEW."Middle Name" IS NULL OR NEW."Middle Name" = '' THEN NEW."Name" := NEW."First Name" || ' ' || NEW."Last Name"; ELSE NEW."Name" := NEW."First Name" || ' ' || NEW."Middle Name" || ' ' || NEW."Last Name"; END IF; END IF; NEW."Name" = initcap(NEW."Name"); NEW."First Name" = initcap(NEW."First Name"); NEW."Middle Name" = initcap(NEW."Middle Name"); NEW."Last Name" = initcap(NEW."Last Name"); RETURN NEW; END IF; IF (TG_OP = 'UPDATE') THEN IF NEW."Name" IS NULL OR NEW."Name" = '' OR NEW."First Name" <> OLD."First Name" OR NEW."Middle Name" <> OLD."Middle Name" OR NEW."Last Name" <> OLD."Last Name" THEN IF NEW."Middle Name" IS NULL OR NEW."Middle Name" = '' THEN NEW."Name" = NEW."First Name" || ' ' || NEW."Last Name"; ELSE NEW."Name" = NEW."First Name" || ' ' || NEW."Middle Name" || ' ' || NEW."Last Name"; END IF; NEW."Name" = initcap(NEW."Name"); NEW."First Name" = initcap(NEW."First Name"); NEW."Middle Name" = initcap(NEW."Middle Name"); NEW."Last Name" = initcap(NEW."Last Name"); END IF; RETURN NEW; END IF; IF (TG_OP = 'DELETE') THEN RETURN OLD; END IF; END; $BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100; CREATE TRIGGER "TR Business Partner" BEFORE INSERT OR UPDATE OR DELETE ON "Business Partner" FOR EACH ROW EXECUTE PROCEDURE t_business_partner();
Re: BUG #4380: Comparison of OLD and NEW columns in trigger does not always work
От
Stephan Szabo
Дата:
On Wed, 27 Aug 2008, Daryl Joubert wrote: > > The following bug has been logged online: > > Bug reference: 4380 > Logged by: Daryl Joubert > Email address: daryl@ftcxpress.com > PostgreSQL version: 8.3.3 > Operating system: WinXP SP2 > Description: Comparison of OLD and NEW columns in trigger does not > always work > Details: > > When comparing NEW.column_name to OLD.column_name in 'PG_UPDATE' operation > in a trigger, I get unpredictable results. Use the following script to > create the "Business Partner" table and its trigger, then add a few rows of > data to "First Name", "Middle Name" and "Last Name" using pgAdmin, and watch > how "Name" is built up for the former 3 columns. > > Then: change the "Middle Name" column of an existing row repeatedly and you > should see that sometimes "Name" is updated, sometimes not. I can repeat the > problem here within 5 to 10 changes of "Middle Name". Am I doing something > wrong? Here is the script: Well, the function does the wrong thing if you set a field to NULL or change a field that was previously NULL to a non-NULL value since a <> NULL is unknown not true. And once that happens you might need to do a couple of updates to get out of the odd state. Is it possible that the updates that are failing fit that pattern? If so, using IS DISTINCT FROM rather than <> may work.