List *clone = NIL;
/*
- * Search for any constraints where this partition is in the referenced
- * side. However, we must ignore any constraint whose parent constraint
- * is also going to be cloned, to avoid duplicates. So do it in two
- * steps: first construct the list of constraints to clone, then go over
- * that list cloning those whose parents are not in the list. (We must
- * not rely on the parent being seen first, since the catalog scan could
- * return children first.)
+ * Search for any constraints where this partition's parent is in the
+ * referenced side. However, we must not clone any constraint whose
+ * parent constraint is also going to be cloned, to avoid duplicates. So
+ * do it in two steps: first construct the list of constraints to clone,
+ * then go over that list cloning those whose parents are not in the list.
+ * (We must not rely on the parent being seen first, since the catalog
+ * scan could return children first.)
*/
pg_constraint = table_open(ConstraintRelationId, RowShareLock);
ScanKeyInit(&key[0],
{
Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
- /* Only try to clone the top-level constraint; skip child ones. */
- if (constrForm->conparentid != InvalidOid)
- continue;
-
clone = lappend_oid(clone, constrForm->oid);
}
systable_endscan(scan);
elog(ERROR, "cache lookup failed for constraint %u", constrOid);
constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
+ /*
+ * As explained above: don't try to clone a constraint for which we're
+ * going to clone the parent.
+ */
+ if (list_member_oid(clone, constrForm->conparentid))
+ {
+ ReleaseSysCache(tuple);
+ continue;
+ }
+
/*
* Because we're only expanding the key space at the referenced side,
* we don't need to prevent any operation in the referencing table, so
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table fkpart8.tbl1
drop cascades to table fkpart8.tbl2
+-- ensure FK referencing a multi-level partitioned table are
+-- enforce reference to sub-children.
+CREATE SCHEMA fkpart9
+ CREATE TABLE pk (a INT PRIMARY KEY) PARTITION BY RANGE (a)
+ CREATE TABLE fk (
+ fk_a INT REFERENCES pk(a) ON DELETE CASCADE
+ )
+ CREATE TABLE pk1 PARTITION OF pk FOR VALUES FROM (30) TO (50) PARTITION BY RANGE (a)
+ CREATE TABLE pk11 PARTITION OF pk1 FOR VALUES FROM (30) TO (40);
+INSERT INTO fkpart9.pk VALUES (35);
+INSERT INTO fkpart9.fk VALUES (35);
+DELETE FROM fkpart9.pk WHERE a=35;
+SELECT fk.fk_a, pk.a
+FROM fkpart9.fk
+LEFT JOIN fkpart9.pk ON fk.fk_a = pk.a
+WHERE fk.fk_a=35;
+ fk_a | a
+------+---
+(0 rows)
+
+DROP SCHEMA fkpart9 CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to table fkpart9.pk
+drop cascades to table fkpart9.fk
ALTER TABLE fkpart8.tbl2 DROP CONSTRAINT tbl2_f1_fkey;
COMMIT;
DROP SCHEMA fkpart8 CASCADE;
+
+-- ensure FK referencing a multi-level partitioned table are
+-- enforce reference to sub-children.
+CREATE SCHEMA fkpart9
+ CREATE TABLE pk (a INT PRIMARY KEY) PARTITION BY RANGE (a)
+ CREATE TABLE fk (
+ fk_a INT REFERENCES pk(a) ON DELETE CASCADE
+ )
+ CREATE TABLE pk1 PARTITION OF pk FOR VALUES FROM (30) TO (50) PARTITION BY RANGE (a)
+ CREATE TABLE pk11 PARTITION OF pk1 FOR VALUES FROM (30) TO (40);
+INSERT INTO fkpart9.pk VALUES (35);
+INSERT INTO fkpart9.fk VALUES (35);
+DELETE FROM fkpart9.pk WHERE a=35;
+SELECT fk.fk_a, pk.a
+FROM fkpart9.fk
+LEFT JOIN fkpart9.pk ON fk.fk_a = pk.a
+WHERE fk.fk_a=35;
+DROP SCHEMA fkpart9 CASCADE;