ADD CONSTRAINT ... FOREIGN KEY and custom data type. - Mailing list pgsql-hackers

From Panon, Paul-Andre
Subject ADD CONSTRAINT ... FOREIGN KEY and custom data type.
Date
Msg-id 2417BD0B3A2D5A4086512AD8BDDB1D4E010A0864@scvanex1.sierrasys.com
Whole thread Raw
Responses Re: ADD CONSTRAINT ... FOREIGN KEY and custom data type.  (Stephan Szabo <sszabo@megazone23.bigpanda.com>)
List pgsql-hackers
For a project we are working on, I have created a custom postgresql data
type which is similar to MS SQL Server's uniqueidentifier data type. It uses
dynamic link library extension that calls the FreeDCE library to generate
GUIDs. Support for the data type and support functions is added to a
PostgreSQL database using the attached SQL script. The functions all seems
to work fine, including use of merge sorts and hash joins during SQL JOIN
statements when using the data type as part of a primary key.  However
adding foreign key constraints sometimes causes a problem.

I never have a problem adding a foreign key to a parent table with a
multi-part key as long as the child table is empty. Adding data to the child
entity afterwards seems to properly enforce RI.  However, if data exists in
the child entity, an RI check is performed on the existing data and this
check sometimes seems to break. As far as I can tell, the RI check in the
latter case seems to confuse the order the Key parts in either the Primary
Key or the Foreign Key. In the case of a multi-part key RI, it was
complaining that it couldn't perform a type conversion between the type of
two different key parts of the primary key.

So in a database with the following table definitions (OK I know it isn't
exactly great DB design to have 4 uniqueidentifiers in a PK, but please bear
with me) : 

--------------

CREATE TABLE Mo_Cvg_Rptd (      Emp_Grp_ID           uniqueidentifier NOT NULL,      Ben_Plan_ID
uniqueidentifierNOT NULL,      Grp_Rate_ID          uniqueidentifier NOT NULL,      Rate_Step_ID
uniqueidentifierNOT NULL,      Cvg_Yr_Mo            date NOT NULL,      Rptg_Session_ID      uniqueidentifier,
Mo_Cvg_Rptd_Sts_Cd  int2,      Mo_Except_Sts_Cd     int2,      Mo_Except_Desc       varchar(150),      Mdfy_Dt
   DATETIME NOT NULL DEFAULT date('now'),      PRIMARY KEY (Emp_Grp_ID, Ben_Plan_ID, Grp_Rate_ID,
Rate_Step_ID,Cvg_Yr_Mo)
 
);


CREATE TABLE Prior_Mo_Prd_Adjmt (      Emp_Grp_ID           uniqueidentifier NOT NULL,      Ben_Plan_ID
uniqueidentifierNOT NULL,      Grp_Rate_ID          uniqueidentifier NOT NULL,      Rate_Step_ID
uniqueidentifierNOT NULL,      Cvg_Yr_Mo            date NOT NULL,      Prior_Prd_Adjmt_Amt  int2,
Prior_Prd_Adjmt_Descvarchar(150),      Prior_Prd_Adjmt_Except_Sts_Cd int2,      Prior_Prd_Adjmt_Except_Desc
varchar(150),     PRIMARY KEY (Emp_Grp_ID, Ben_Plan_ID, Grp_Rate_ID,              Rate_Step_ID, Cvg_Yr_Mo)
 
);

ALTER TABLE Prior_Mo_Prd_Adjmt    ADD CONSTRAINT FK_PriorMoPrdAdjmt_MoCvgRptd FOREIGN KEY(Emp_Grp_ID,
                                        Ben_Plan_ID,
Grp_Rate_ID,                                                           Rate_Step_ID,
                       Cvg_Yr_Mo)   REFERENCES Mo_Cvg_Rptd;
 

--------------

If I want to change a column in Prior_Mo_Prd_Adjmt (with the aid of Erwin),
I have to drop the table and recreate it with a script similar to the
following:

**********************

CREATE TABLE prior_mo_prd_adjmtL25D4340000 (emp_grp_id uniqueidentifier,    ben_plan_id uniqueidentifier, grp_rate_id
uniqueidentifier, rate_step_id uniqueidentifier,    cvg_yr_mo date, prior_prd_adjmt_amt int4, prior_prd_adjmt_desc
varchar(150),prior_prd_adjmt_except_sts_cd int2,    prior_prd_adjmt_except_desc varchar(150));
 


INSERT INTO prior_mo_prd_adjmtL25D4340000 (emp_grp_id, ben_plan_id,
grp_rate_id,   rate_step_id, cvg_yr_mo, prior_prd_adjmt_amt, prior_prd_adjmt_desc,   prior_prd_adjmt_except_sts_cd,
prior_prd_adjmt_except_desc)  SELECT emp_grp_id, ben_plan_id, grp_rate_id,       rate_step_id, cvg_yr_mo,
prior_prd_adjmt_amt,prior_prd_adjmt_desc,       prior_prd_adjmt_except_sts_cd, prior_prd_adjmt_except_desc   FROM
prior_mo_prd_adjmt;


DROP TABLE prior_mo_prd_adjmt;


CREATE TABLE Prior_Mo_Prd_Adjmt (      Emp_Grp_ID           uniqueidentifier NOT NULL,      Ben_Plan_ID
uniqueidentifierNOT NULL,      Grp_Rate_ID          uniqueidentifier NOT NULL,      Rate_Step_ID
uniqueidentifierNOT NULL,      Cvg_Yr_Mo            date NOT NULL,      Prior_Prd_Adjmt_Amt  numeric(9,2),
Prior_Prd_Adjmt_Descvarchar(150),      Prior_Prd_Adjmt_Except_Sts_Cd int2,      Prior_Prd_Adjmt_Except_Desc
varchar(150),     PRIMARY KEY (Emp_Grp_ID, Ben_Plan_ID, Grp_Rate_ID,              Rate_Step_ID, Cvg_Yr_Mo)
 
);

CREATE UNIQUE INDEX IDX_Prior_Mo_Prd_Adjmt_PK ON Prior_Mo_Prd_Adjmt
(      Emp_Grp_ID,      Ben_Plan_ID,      Grp_Rate_ID,      Rate_Step_ID,      Cvg_Yr_Mo
);

ALTER TABLE Prior_Mo_Prd_Adjmt    ADD CONSTRAINT FK_PriorMoPrdAdjmt_MoCvgRptd FOREIGN KEY(Emp_Grp_ID,
                                        Ben_Plan_ID,
Grp_Rate_ID,                                                           Rate_Step_ID,
                       Cvg_Yr_Mo)   REFERENCES Mo_Cvg_Rptd;
 


INSERT INTO Prior_Mo_Prd_Adjmt (Emp_Grp_ID, Ben_Plan_ID, Grp_Rate_ID,    Rate_Step_ID, Cvg_Yr_Mo, Prior_Prd_Adjmt_Amt,
Prior_Prd_Adjmt_Desc,   Prior_Prd_Adjmt_Except_Sts_Cd, Prior_Prd_Adjmt_Except_Desc) SELECT    emp_grp_id, ben_plan_id,
grp_rate_id,rate_step_id, cvg_yr_mo,    prior_prd_adjmt_amt, prior_prd_adjmt_desc,
 
prior_prd_adjmt_except_sts_cd,    prior_prd_adjmt_except_desc FROM prior_mo_prd_adjmtL25D4340000;


DROP TABLE prior_mo_prd_adjmtL25D4340000;

**********************

Now the interesting thing is that if the ALTER TABLE statement is placed
after the INSERT I get the following error:

psql:upgradetohbtweb205.sql:61: NOTICE:  ALTER TABLE ... ADD CONSTRAINT will
create implicit trigger(s) for FOREIGN KEY check(s)
psql:upgradetohbtweb205.sql:61: ERROR:  Unable to identify an operator '='
for types 'uniqueidentifier' and 'date'       You will have to retype this query using an explicit cast

But I get no error with the ALTER before the INSERT!

In this case I can work around the bug, but I can't in the case of a 3+
table PK chain grandparent->parent->child where I don't want to have to drop
the child table (and anything referring to it) to be able to change the
parent table. (The child will have a FK to the parent which will break with
the above error when I try to recreate it on the new incarnation of the
parent.)

I haven't seen any references to similar foreign key problems in the lists,
which is why I am not sure if the problem is a function of the extended
type. However since the behaviour is different - for the same data -
depending on whether the RI check is made when creating the FOREIGN KEY vs.
when adding data after the key is entered, it seems reasonable to suspect a
bug in the first case.

Any chance this might be addressed for 7.1?

Thank you,

Paul-Andre Panon

--
Paul-AndrePanon@SierraSystems.com
<<PGUniqID.sql>> 



pgsql-hackers by date:

Previous
From: "Eduardo Stern"
Date:
Subject: Re: ODBC Problem v7.1 beta4
Next
From: "Dan Wilson"
Date:
Subject: Re: [GENERAL] Re: Re: Re: grant privileges to a database [URGENT]