Attempt to fix inheritance limitations: unique and foreign key constraints

2018-06-12 Thread Raphael Medaer

Hi pg-hackers,

I'm trying to fix some of limitations in table inheritance. My first use 
case concerns "referencing" foreign keys in parent table.


The attached patch propagates foreign keys to inherited tables. I'm 
automatically cloning foreign keys from parent table into children (with 
right dependencies). It's the native implementation of work-around 
described in documentation section 5.9.1. (Caveats).


To be honest it's my first pg hack. Thus it might contain (serious) 
issues (please be lenient with it).

Furthermore it's not yet documented (TODO !!)

As far as I tested it works pretty well; the internal triggers are 
installed on CREATE TABLE .. INHERIT and even after ALTER TABLE .. INHERIT.


If you have few minutes to challenge this hack and give your advices, be 
my guest !


Kind regards,

--
Raphael Medaer
Product Development Engineer
Escaux

Escaux, Communication as easy as the web
Chaussée de Bruxelles 408, 1300 Wavre, Belgium
Direct: +3227887564
Main: +3226860900
www.escaux.com <http://www.escaux.com>

/Dit bericht is onderworpen aan de voorwaarden beschikbaar op onze 
website <https://www.escaux.com/docs/ContractInfo.html>.
Ce message est soumis aux conditions disponibles sur notre site web 
<https://www.escaux.com/docs/ContractInfo.html>.
This message is subject to the terms and conditions available on our 
website <https://www.escaux.com/docs/ContractInfo.html>. /
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 7a6d158f89..7c15c1292b 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -1047,6 +1047,39 @@ ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId)
 	heap_close(constrRel, RowExclusiveLock);
 }
 
+bool
+relation_constraint_oid_exists(Oid relid, Oid conid)
+{
+	boolexists = false;
+	Relationpg_constraint;
+	HeapTuple   tuple;
+	SysScanDesc scan;
+	ScanKeyData key;
+
+	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
+
+	ScanKeyInit(&key,
+			Anum_pg_constraint_conrelid,
+			BTEqualStrategyNumber,
+			F_OIDEQ,
+			ObjectIdGetDatum(relid));
+
+	scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
+			NULL, 1, &key);
+
+	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+	{
+		if (HeapTupleGetOid(tuple) == conid) {
+			exists = true;
+			break;
+		}
+	}
+
+	systable_endscan(scan);
+	heap_close(pg_constraint, AccessShareLock);
+
+	return exists;
+}
 
 /*
  * get_relation_constraint_oid
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 2ea05f350b..dbb82f95bc 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -279,6 +279,48 @@ deleteDependencyRecordsForClass(Oid classId, Oid objectId,
 	return count;
 }
 
+/**
+ *
+ */
+long
+deleteDependencyRecordsForRefObject(Oid classId, Oid objectId, Oid refObjectId)
+{
+	longcount = 0;
+	ScanKeyData keys[2];
+	SysScanDesc scan;
+	Relationrel;
+	HeapTuple   tuple;
+
+	rel = heap_open(DependRelationId, RowExclusiveLock);
+
+	/* Use index to filter class/object */
+	ScanKeyInit(&keys[0],
+			Anum_pg_depend_classid,
+			BTEqualStrategyNumber, F_OIDEQ,
+			ObjectIdGetDatum(classId));
+	ScanKeyInit(&keys[1],
+			Anum_pg_depend_objid,
+			BTEqualStrategyNumber, F_OIDEQ,
+			ObjectIdGetDatum(objectId));
+	scan = systable_beginscan(rel, DependDependerIndexId, true, NULL, 2, keys);
+
+	while(HeapTupleIsValid(tuple = systable_getnext(scan)))
+	{
+		Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tuple);
+
+		if (depform->refobjid == refObjectId) {
+			CatalogTupleDelete(rel, &tuple->t_self);
+			count++;
+		}
+	}
+
+	systable_endscan(scan);
+	heap_close(rel, RowExclusiveLock);
+
+	return count;
+}
+
+
 /*
  * Adjust dependency record(s) to point to a different object of the same type
  *
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d20991a1e5..fbbbf59afa 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -338,6 +338,10 @@ static void validateCheckConstraint(Relation rel, HeapTuple constrtup);
 static void validateForeignKeyConstraint(char *conname,
 			 Relation rel, Relation pkrel,
 			 Oid pkindOid, Oid constraintOid);
+static void
+createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
+			  Constraint *fkconstraint, Oid constraintOid,
+			  Oid indexOid);
 static void ATController(AlterTableStmt *parsetree,
 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
@@ -410,7 +414,7 @@ static ObjectAddress ATAddCheckConstraint(List **wqueue,
 	 LOCKMODE lockmode);
 static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
 		  Relation r

Re: Attempt to fix inheritance limitations: unique and foreign key constraints

2018-06-15 Thread Raphael Medaer

Hi Robert,


Sounds very similar to commit 3de241dba86f3dd000434f70aebba725fb928032.


I'm reusing part of the code from this commit (mainly 
"CloneForeignKeyConstraints")..

But this commit concerns only partitioned tables.. not inherited tables.

Kind regards,

--
Raphael Medaer
Product Development Engineer
Escaux

Escaux, Communication as easy as the web
Chaussée de Bruxelles 408, 1300 Wavre, Belgium
Direct: +3227887564
Main: +3226860900
www.escaux.com <http://www.escaux.com>

/Dit bericht is onderworpen aan de voorwaarden beschikbaar op onze 
website <https://www.escaux.com/docs/ContractInfo.html>.
Ce message est soumis aux conditions disponibles sur notre site web 
<https://www.escaux.com/docs/ContractInfo.html>.
This message is subject to the terms and conditions available on our 
website <https://www.escaux.com/docs/ContractInfo.html>. /