diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index ea655a10a8..5c32a4f20a 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -2299,6 +2299,14 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</>:<replaceable>&lt;salt&gt;<
      </row>
 
      <row>
+      <entry><structfield>confiselement</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>If a foreign key, is it an array <literal>ELEMENT</literal>
+      foreign key?</entry>
+     </row>
+
+     <row>
       <entry><structfield>connoinherit</structfield></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
@@ -2324,6 +2332,18 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</>:<replaceable>&lt;salt&gt;<
      </row>
 
      <row>
+      <entry><structfield>confelement</structfield></entry>
+      <entry><type>bool[]</type></entry>
+      <entry></entry>
+      <entry>
+        If a foreign key, list of booleans expressing which columns
+        are array <literal>ELEMENT</literal> columns; see
+        <xref linkend="sql-createtable-element-foreign-key-constraints">
+        for details
+      </entry>
+     </row>
+
+     <row>
       <entry><structfield>conpfeqop</structfield></entry>
       <entry><type>oid[]</type></entry>
       <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</></entry>
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index b05a9c2150..c1c847bc7e 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -881,7 +881,112 @@ CREATE TABLE order_items (
     <xref linkend="sql-createtable">.
    </para>
   </sect2>
-
+  
+   <sect2 id="ddl-constraints-element-fk">
+    <title>Array ELEMENT Foreign Keys</title>
+ 
+    <indexterm>
+     <primary>ELEMENT foreign key</primary>
+    </indexterm>
+ 
+    <indexterm>
+     <primary>constraint</primary>
+     <secondary>Array ELEMENT foreign key</secondary>
+    </indexterm>
+ 
+    <indexterm>
+     <primary>constraint</primary>
+     <secondary>ELEMENT foreign key</secondary>
+    </indexterm>
+ 
+    <indexterm>
+     <primary>referential integrity</primary>
+    </indexterm>
+ 
+    <para>
+     Another option you have with foreign keys is to use a
+     referencing column which is an array of elements with
+     the same type (or a compatible one) as the referenced
+     column in the related table. This feature is called
+     <firstterm>array element foreign key</firstterm> and is implemented
+     in PostgreSQL with <firstterm>ELEMENT foreign key constraints</firstterm>,
+     as described in the following example:
+ 
+    <programlisting>
+    CREATE TABLE drivers (
+        driver_id integer PRIMARY KEY,
+        first_name text,
+        last_name text,
+        ...
+    );
+
+    CREATE TABLE races (
+        race_id integer PRIMARY KEY,
+        title text,
+        race_day DATE,
+        ...
+        final_positions integer[] <emphasis>ELEMENT REFERENCES drivers</emphasis>
+    );
+    </programlisting>
+ 
+     The above example uses an array (<literal>final_positions</literal>)
+     to store the results of a race: for each of its elements
+     a referential integrity check is enforced on the
+     <literal>drivers</literal> table.
+     Note that <literal>ELEMENT REFERENCES</literal> is an extension
+     of PostgreSQL and it is not included in the SQL standard.
+    </para>
+ 
+    <para>
+     Even though the most common use case for array <literal>ELEMENT</literal>
+     foreign keys is on a single column key, you can define an <quote>array
+     <literal>ELEMENT</literal> foreign key constraint</quote> on a group
+     of columns. As the following example shows, it must be written in table
+     constraint form:
+ 
+    <programlisting>
+    CREATE TABLE available_moves (
+        kind text,
+        move text,
+        description text,
+        PRIMARY KEY (kind, move)
+    );
+
+    CREATE TABLE paths (
+        description text,
+        kind text,
+        moves text[],
+        <emphasis>FOREIGN KEY (kind, ELEMENT moves) REFERENCES available_moves (kind, move)</emphasis>
+    );
+
+    INSERT INTO available_moves VALUES ('relative', 'LN', 'look north');
+    INSERT INTO available_moves VALUES ('relative', 'RL', 'rotate left');
+    INSERT INTO available_moves VALUES ('relative', 'RR', 'rotate right');
+    INSERT INTO available_moves VALUES ('relative', 'MF', 'move forward');
+    INSERT INTO available_moves VALUES ('absolute', 'N', 'move north');
+    INSERT INTO available_moves VALUES ('absolute', 'S', 'move south');
+    INSERT INTO available_moves VALUES ('absolute', 'E', 'move east');
+    INSERT INTO available_moves VALUES ('absolute', 'W', 'move west');
+
+    INSERT INTO paths VALUES ('L-shaped path', 'relative', '{LN, RL, MF, RR, MF, MF}');
+    INSERT INTO paths VALUES ('L-shaped path', 'absolute', '{W, N, N}');
+    </programlisting>
+ 
+    On top of standard foreign key requirements,
+    array <literal>ELEMENT</literal> foreign key constraints
+    require that the referencing column is an array of a compatible
+    type of the corresponding referenced column.
+   </para>
+ 
+   <para>
+    For more detailed information on array <literal>ELEMENT</literal>
+    foreign key options and special cases, please refer to the documentation
+    for <xref linkend="sql-createtable-foreign-key"> and
+    <xref linkend="sql-createtable-element-foreign-key-constraints">.
+   </para>
+ 
+  </sect2>
+ 
   <sect2 id="ddl-constraints-exclusion">
    <title>Exclusion Constraints</title>
 
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index b15c19d3d0..229876d735 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -65,7 +65,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
   GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <replaceable>sequence_options</replaceable> ) ] |
   UNIQUE <replaceable class="PARAMETER">index_parameters</replaceable> |
   PRIMARY KEY <replaceable class="PARAMETER">index_parameters</replaceable> |
-  REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
+  [ELEMENT] REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
     [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
 [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
 
@@ -76,7 +76,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
   UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
   PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
   EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
-  FOREIGN KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> [, ... ] ) ]
+  FOREIGN KEY ( [ELEMENT] <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> [, ... ] ) ]
     [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
 [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
 
@@ -779,10 +779,11 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
     </listitem>
    </varlistentry>
 
-   <varlistentry>
+    <varlistentry id="sql-createtable-foreign-key" xreflabel="FOREIGN KEY">
     <term><literal>REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> ) ] [ MATCH <replaceable class="parameter">matchtype</replaceable> ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal> (column constraint)</term>
 
-   <term><literal>FOREIGN KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] )
+   <term>
+   <literal>FOREIGN KEY ( [ELEMENT] <replaceable class="parameter">column_name</replaceable> [, ... ] )
     REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ]
     [ MATCH <replaceable class="parameter">matchtype</replaceable> ]
     [ ON DELETE <replaceable class="parameter">action</replaceable> ]
@@ -806,6 +807,19 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
      </para>
 
      <para>
+       In case the column name <replaceable class="parameter">column</replaceable>
+       is prepended with the <literal>ELEMENT</literal> keyword and <replaceable
+       class="parameter">column</replaceable> is an array of elements compatible
+       with the corresponding <replaceable class="parameter">refcolumn</replaceable>
+       in <replaceable class="parameter">reftable</replaceable>, an
+       array <literal>ELEMENT</literal> foreign key constraint is put in place
+       (see <xref linkend="sql-createtable-element-foreign-key-constraints">
+       for more information).
+       Multi-column keys with more than one <literal>ELEMENT</literal> column
+       are currently not allowed.
+      </para>
+ 
+      <para>
       A value inserted into the referencing column(s) is matched against the
       values of the referenced table and referenced columns using the
       given match type.  There are three match types: <literal>MATCH
@@ -868,7 +882,8 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
          <para>
           Delete any rows referencing the deleted row, or update the
           values of the referencing column(s) to the new values of the
-          referenced columns, respectively.
+          referenced columns, respectively. Currently not supported
+          with array <literal>ELEMENT</literal> foreign keys.
          </para>
         </listitem>
        </varlistentry>
@@ -877,7 +892,8 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
         <term><literal>SET NULL</literal></term>
         <listitem>
          <para>
-          Set the referencing column(s) to null.
+           Set the referencing column(s) to null. Currently not supported
+           with array <literal>ELEMENT</literal> foreign keys.
          </para>
         </listitem>
        </varlistentry>
@@ -889,6 +905,8 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
           Set the referencing column(s) to their default values.
           (There must be a row in the referenced table matching the default
           values, if they are not null, or the operation will fail.)
+          Currently not supported with array <literal>ELEMENT</literal>
+          foreign keys.
          </para>
         </listitem>
        </varlistentry>
@@ -904,6 +922,61 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
     </listitem>
    </varlistentry>
 
+   <varlistentry id="sql-createtable-element-foreign-key-constraints" xreflabel="ELEMENT REFERENCES">
+    <term><literal>ELEMENT REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> ) ] [ MATCH <replaceable class="parameter">matchtype</replaceable> ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal> (column constraint)</term>
+
+    <listitem>
+     <para>
+      The <literal>ELEMENT REFERENCES</literal> definition specifies
+      an <quote>array <literal>ELEMENT</literal> foreign key</quote>,
+      a special kind of foreign key
+      constraint requiring the referencing column to be an array of elements
+      of the same type (or a compatible one) as the referenced column
+      in the referenced table. The value of each element of the
+      <replaceable class="parameter">refcolumn</replaceable> array
+      will be matched against some row of <replaceable
+      class="parameter">reftable</replaceable>.
+     </para>
+ 
+     <para>
+      Array <literal>ELEMENT</literal> foreign keys are an extension
+      of PostgreSQL and are not included in the SQL standard.
+     </para>
+ 
+     <para>
+      Even with <literal>ELEMENT</literal> foreign keys, modifications
+      in the referenced column can trigger actions to be performed on
+      the referencing array.
+      Similarly to standard foreign keys, you can specify these
+      actions using the <literal>ON DELETE</literal> and
+      <literal>ON UPDATE</literal> clauses.
+      However, only the two following actions for each clause are
+     currently allowed:
+ 
+      <variablelist>
+       <varlistentry>
+        <term><literal>NO ACTION</literal></term>
+        <listitem>
+         <para>
+          Same as standard foreign key constraints. This is the default action.
+         </para>
+        </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+        <term><literal>RESTRICT</literal></term>
+        <listitem>
+         <para>
+          Same as standard foreign key constraints.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+    </listitem>
+   </varlistentry>
+ 
    <varlistentry>
     <term><literal>DEFERRABLE</literal></term>
     <term><literal>NOT DEFERRABLE</literal></term>
@@ -1859,7 +1932,16 @@ CREATE TABLE cities_ab_10000_to_100000
     <productname>PostgreSQL</productname> extension.
    </para>
   </refsect2>
-
+ 
+  <refsect2>
+   <title id="sql-createtable-foreign-key-arrays">Array <literal>ELEMENT</literal> Foreign Keys</title>
+ 
+   <para>
+    Array <literal>ELEMENT</literal> foreign keys and the
+    <literal>ELEMENT REFERENCES</literal> clause
+    are a <productname>PostgreSQL</productname> extension.
+   </para>
+  </refsect2>
  </refsect1>
 
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a376b99f1e..a25ccd084c 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2099,7 +2099,9 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
 							  NULL,
 							  NULL,
 							  0,
-							  ' ',
+ 							  false,
+	 						  NULL,
+ 							  ' ',
 							  ' ',
 							  ' ',
 							  NULL, /* not an exclusion constraint */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 027abd56b0..a2e8baba55 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1212,6 +1212,8 @@ index_constraint_create(Relation heapRelation,
 								   NULL,
 								   NULL,
 								   0,
+ 								   false,
+  								   NULL,
 								   ' ',
 								   ' ',
 								   ' ',
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 98bcfa08c6..0c731b1085 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -1226,7 +1226,9 @@ CREATE VIEW referential_constraints AS
                                   WHEN 'd' THEN 'SET DEFAULT'
                                   WHEN 'r' THEN 'RESTRICT'
                                   WHEN 'a' THEN 'NO ACTION' END
-             AS character_data) AS delete_rule
+             AS character_data) AS delete_rule,
+
+            con.confiselement AS is_element            
 
     FROM (pg_namespace ncon
           INNER JOIN pg_constraint con ON ncon.oid = con.connamespace
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 1336c46d3f..b96294f6a6 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -63,6 +63,8 @@ CreateConstraintEntry(const char *constraintName,
 					  const Oid *ppEqOp,
 					  const Oid *ffEqOp,
 					  int foreignNKeys,
+ 					  bool confisElement,
+ 					  const bool *foreignElement,
 					  char foreignUpdateType,
 					  char foreignDeleteType,
 					  char foreignMatchType,
@@ -82,6 +84,7 @@ CreateConstraintEntry(const char *constraintName,
 	Datum		values[Natts_pg_constraint];
 	ArrayType  *conkeyArray;
 	ArrayType  *confkeyArray;
+ 	ArrayType  *confelementArray;
 	ArrayType  *conpfeqopArray;
 	ArrayType  *conppeqopArray;
 	ArrayType  *conffeqopArray;
@@ -132,10 +135,15 @@ CreateConstraintEntry(const char *constraintName,
 			fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
 		conffeqopArray = construct_array(fkdatums, foreignNKeys,
 										 OIDOID, sizeof(Oid), true, 'i');
+ 		for (i = 0; i < foreignNKeys; i++)
+ 			fkdatums[i] = BoolGetDatum(foreignElement[i]);
+ 		confelementArray = construct_array(fkdatums, foreignNKeys,
+ 										   BOOLOID, 1, true, 'c');
 	}
 	else
 	{
 		confkeyArray = NULL;
+ 		confelementArray = NULL;
 		conpfeqopArray = NULL;
 		conppeqopArray = NULL;
 		conffeqopArray = NULL;
@@ -177,6 +185,7 @@ CreateConstraintEntry(const char *constraintName,
 	values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
 	values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
 	values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
+  	values[Anum_pg_constraint_coniselement - 1] = BoolGetDatum(confisElement);
 
 	if (conkeyArray)
 		values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
@@ -188,6 +197,11 @@ CreateConstraintEntry(const char *constraintName,
 	else
 		nulls[Anum_pg_constraint_confkey - 1] = true;
 
+ 	if (confelementArray)
+ 		values[Anum_pg_constraint_confelement - 1] = PointerGetDatum(confelementArray);
+ 	else
+ 		nulls[Anum_pg_constraint_confelement - 1] = true;
+ 
 	if (conpfeqopArray)
 		values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
 	else
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 7d9c769b06..25951c89c7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -41,6 +41,7 @@
 #include "catalog/pg_inherits_fn.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
+#include "catalog/pg_operator.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
@@ -6995,6 +6996,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 	Relation	pkrel;
 	int16		pkattnum[INDEX_MAX_KEYS];
 	int16		fkattnum[INDEX_MAX_KEYS];
+ 	bool		fkattelement[INDEX_MAX_KEYS];
 	Oid			pktypoid[INDEX_MAX_KEYS];
 	Oid			fktypoid[INDEX_MAX_KEYS];
 	Oid			opclasses[INDEX_MAX_KEYS];
@@ -7082,6 +7084,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 	 */
 	MemSet(pkattnum, 0, sizeof(pkattnum));
 	MemSet(fkattnum, 0, sizeof(fkattnum));
+ 	MemSet(fkattelement, 0, sizeof(fkattelement));
 	MemSet(pktypoid, 0, sizeof(pktypoid));
 	MemSet(fktypoid, 0, sizeof(fktypoid));
 	MemSet(opclasses, 0, sizeof(opclasses));
@@ -7094,6 +7097,39 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 									 fkattnum, fktypoid);
 
 	/*
+ 	 * If an array ELEMENT FK, decode the content of
+ 	 * the fk_element_attrs array.
+ 	 */
+ 	if (fkconstraint->fk_is_element)
+ 	{
+ 		ListCell   *l;
+ 		int			attnum;
+ 		bool		element_found = false;
+ 
+ 		attnum = 0;
+ 		foreach(l, fkconstraint->fk_element_attrs)
+ 		{
+ 			if (lfirst_int(l)) {
+ 
+ 				/*
+ 				 * Currently, the ELEMENT flag cannot be set on more than
+ 				 * one column.
+ 				 */
+ 				if (element_found) {
+ 					ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_FOREIGN_KEY),
+ 						errmsg("array ELEMENT foreign keys support only one ELEMENT column")));
+ 				}
+ 
+ 				fkattelement[attnum] = true;
+ 				element_found = true;
+ 			}
+ 			attnum++;
+ 		}
+ 
+ 	}
+ 
+ 	/*
 	 * If the attribute list for the referenced table was omitted, lookup the
 	 * definition of the primary key and use it.  Otherwise, validate the
 	 * supplied attribute list.  In either case, discover the index OID and
@@ -7140,6 +7176,22 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 	 */
 	old_check_ok = (fkconstraint->old_conpfeqop != NIL);
 	Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
+ 
+ 	/* Enforce array ELEMENT foreign key restrictions */
+ 	if (fkconstraint->fk_is_element)
+ 	{
+ 		/*
+ 		 * Array ELEMENT foreign keys support only NO ACTION and
+ 		 * RESTRICT actions
+ 		 */
+ 		if ((fkconstraint->fk_upd_action != FKCONSTR_ACTION_NOACTION
+ 				&& fkconstraint->fk_upd_action != FKCONSTR_ACTION_RESTRICT)
+ 			|| (fkconstraint->fk_del_action != FKCONSTR_ACTION_NOACTION
+ 				&& fkconstraint->fk_del_action != FKCONSTR_ACTION_RESTRICT))
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
+ 				errmsg("array ELEMENT foreign keys only support NO ACTION and RESTRICT actions")));
+ 	}
 
 	for (i = 0; i < numpks; i++)
 	{
@@ -7156,6 +7208,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 		Oid			ffeqop;
 		int16		eqstrategy;
 		Oid			pfeqop_right;
+ 		Oid			fk_element_type = InvalidOid;
 
 		/* We need several fields out of the pg_opclass entry */
 		cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
@@ -7189,26 +7242,51 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
 				 eqstrategy, opcintype, opcintype, opfamily);
 
-		/*
-		 * Are there equality operators that take exactly the FK type? Assume
-		 * we should look through any domain here.
-		 */
-		fktyped = getBaseType(fktype);
-
-		pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
-									 eqstrategy);
-		if (OidIsValid(pfeqop))
-		{
-			pfeqop_right = fktyped;
-			ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
-										 eqstrategy);
-		}
-		else
-		{
-			/* keep compiler quiet */
-			pfeqop_right = InvalidOid;
-			ffeqop = InvalidOid;
-		}
+ 		if (fkattelement[i])
+  		{
+ 			/*
+ 			 * For every array ELEMENT FK, look if an equality operator that
+ 			 * takes exactly the FK element type exists.  Assume we should
+ 			 * look through any domain here.
+ 			 */
+ 			fk_element_type = get_base_element_type(fktype);
+ 			if (!OidIsValid(fk_element_type))
+ 				ereport(ERROR,
+ 					(errcode(ERRCODE_DATATYPE_MISMATCH),
+ 					 errmsg("foreign key constraint \"%s\" cannot be implemented",
+ 							fkconstraint->conname),
+ 					 errdetail("Key column \"%s\" has type %s which is not an array type.",
+ 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
+ 							   format_type_be(fktype))));
+ 
+ 			pfeqop = get_opfamily_member(opfamily, opcintype, fk_element_type,
+  										 eqstrategy);
+ 			pfeqop_right = fk_element_type;
+ 			ffeqop = ARRAY_EQ_OP;
+  		}
+  		else
+  		{
+ 			/*
+ 			 * Are there equality operators that take exactly the FK type?
+ 			 * Assume we should look through any domain here.
+ 			 */
+ 			fktyped = getBaseType(fktype);
+ 
+ 			pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
+ 										 eqstrategy);
+ 			if (OidIsValid(pfeqop))
+ 			{
+ 				pfeqop_right = fktyped;
+ 				ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
+ 											 eqstrategy);
+ 			}
+ 			else
+ 			{
+ 				/* keep compiler quiet */
+ 				pfeqop_right = InvalidOid;
+ 				ffeqop = InvalidOid;
+ 			}
+  		}
 
 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
 		{
@@ -7225,25 +7303,46 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 			Oid			target_typeids[2];
 
 			input_typeids[0] = pktype;
-			input_typeids[1] = fktype;
+ 			if (fkattelement[i])
+ 				input_typeids[1] = fk_element_type;
+ 			else
+ 				input_typeids[1] = fktype;
 			target_typeids[0] = opcintype;
 			target_typeids[1] = opcintype;
 			if (can_coerce_type(2, input_typeids, target_typeids,
 								COERCION_IMPLICIT))
 			{
-				pfeqop = ffeqop = ppeqop;
+ 				pfeqop = ppeqop;
 				pfeqop_right = opcintype;
+ 				/*
+ 				 * In case of an array ELEMENT FK, the ffeqop must be left
+ 				 * untouched; otherwise we use the primary equality operator.
+ 				 */
+ 				if (!fkattelement[i])
+ 					ffeqop = ppeqop;
 			}
 		}
 
+ 		/*
+ 		 * In case of an array ELEMENT FK, make sure TYPECACHE_EQ_OPR exists
+ 		 * for the FK element_type and it is compatible with pfeqop
+ 		 */
+ 		if (fkattelement[i] && OidIsValid(pfeqop))
+ 		{
+ 			TypeCacheEntry *typentry = lookup_type_cache(fk_element_type,
+ 										 TYPECACHE_EQ_OPR);
+ 			if (!OidIsValid(typentry->eq_opr)
+ 				|| !equality_ops_are_compatible(typentry->eq_opr, pfeqop))
+ 				/* Error: incompatible operators */
+ 				pfeqop = InvalidOid;
+ 		}
+ 
 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("foreign key constraint \"%s\" "
-							"cannot be implemented",
+ 					 errmsg("foreign key constraint \"%s\" cannot be implemented",
 							fkconstraint->conname),
-					 errdetail("Key columns \"%s\" and \"%s\" "
-							   "are of incompatible types: %s and %s.",
+ 					 errdetail("Key columns \"%s\" and \"%s\" are of incompatible types: %s and %s.",
 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
 							   strVal(list_nth(fkconstraint->pk_attrs, i)),
 							   format_type_be(fktype),
@@ -7274,8 +7373,16 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 			 * column types to the right (foreign) operand type of the pfeqop.
 			 * We may assume that pg_constraint.conkey is not changing.
 			 */
-			old_fktype = tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid;
-			new_fktype = fktype;
+ 			if (fkattelement[i])
+ 			{
+ 				old_fktype = get_base_element_type(tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid);
+ 				new_fktype = fk_element_type;
+ 			}
+ 			else
+ 			{
+ 				old_fktype = tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid;
+ 				new_fktype = fktype;
+ 			}
 			old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
 										&old_castfunc);
 			new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
@@ -7345,6 +7452,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 									  ppeqoperators,
 									  ffeqoperators,
 									  numpks,
+ 									  fkconstraint->fk_is_element,
+ 									  fkattelement,
 									  fkconstraint->fk_upd_action,
 									  fkconstraint->fk_del_action,
 									  fkconstraint->fk_matchtype,
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 45d1f515eb..c6ba754c87 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -603,6 +603,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 											  NULL,
 											  NULL,
 											  0,
+ 											  false,
+ 											  NULL,
 											  ' ',
 											  ' ',
 											  ' ',
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index c2fc59d1aa..16479fa83b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3076,6 +3076,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 							  NULL,
 							  NULL,
 							  0,
+	 						  false,
+ 							  NULL,
 							  ' ',
 							  ' ',
 							  ' ',
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 67ac8145a0..0e4361230c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2847,6 +2847,8 @@ _copyConstraint(const Constraint *from)
 	COPY_SCALAR_FIELD(fk_upd_action);
 	COPY_SCALAR_FIELD(fk_del_action);
 	COPY_NODE_FIELD(old_conpfeqop);
+ 	COPY_SCALAR_FIELD(fk_is_element);
+ 	COPY_NODE_FIELD(fk_element_attrs);
 	COPY_SCALAR_FIELD(old_pktable_oid);
 	COPY_SCALAR_FIELD(skip_validation);
 	COPY_SCALAR_FIELD(initially_valid);
@@ -2868,6 +2870,17 @@ _copyDefElem(const DefElem *from)
 	return newnode;
 }
 
+static ForeignKeyColumnElem *
+_copyForeignKeyColumnElem(const ForeignKeyColumnElem *from)
+{
+	ForeignKeyColumnElem *newnode = makeNode(ForeignKeyColumnElem);
+
+	COPY_NODE_FIELD(name);
+	COPY_SCALAR_FIELD(element);
+
+	return newnode;
+}
+
 static LockingClause *
 _copyLockingClause(const LockingClause *from)
 {
@@ -5456,6 +5469,9 @@ copyObjectImpl(const void *from)
 		case T_DefElem:
 			retval = _copyDefElem(from);
 			break;
+ 		case T_ForeignKeyColumnElem:
+ 			retval = _copyForeignKeyColumnElem(from);
+ 			break;
 		case T_LockingClause:
 			retval = _copyLockingClause(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 91d64b7331..c121a0a5cb 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2579,6 +2579,8 @@ _equalConstraint(const Constraint *a, const Constraint *b)
 	COMPARE_SCALAR_FIELD(fk_upd_action);
 	COMPARE_SCALAR_FIELD(fk_del_action);
 	COMPARE_NODE_FIELD(old_conpfeqop);
+ 	COMPARE_SCALAR_FIELD(fk_is_element);
+ 	COMPARE_NODE_FIELD(fk_element_attrs);
 	COMPARE_SCALAR_FIELD(old_pktable_oid);
 	COMPARE_SCALAR_FIELD(skip_validation);
 	COMPARE_SCALAR_FIELD(initially_valid);
@@ -2599,6 +2601,16 @@ _equalDefElem(const DefElem *a, const DefElem *b)
 }
 
 static bool
+_equalForeignKeyColumnElem(const ForeignKeyColumnElem *a,
+ 		const ForeignKeyColumnElem *b)
+ {
+ 	COMPARE_NODE_FIELD(name);
+ 	COMPARE_SCALAR_FIELD(element);
+ 
+ 	return true;
+}
+
+static bool
 _equalLockingClause(const LockingClause *a, const LockingClause *b)
 {
 	COMPARE_NODE_FIELD(lockedRels);
@@ -3606,6 +3618,9 @@ equal(const void *a, const void *b)
 		case T_DefElem:
 			retval = _equalDefElem(a, b);
 			break;
+ 		case T_ForeignKeyColumnElem:
+ 			retval = _equalForeignKeyColumnElem(a, b);
+ 			break;
 		case T_LockingClause:
 			retval = _equalLockingClause(a, b);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3a23f0bb16..3fa2b399b3 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2726,6 +2726,15 @@ _outTableLikeClause(StringInfo str, const TableLikeClause *node)
 }
 
 static void
+_outForeignKeyColumnElem(StringInfo str, const ForeignKeyColumnElem *node)
+{
+ 	WRITE_NODE_TYPE("FOREIGNKEYCOLUMNELEM");
+ 
+ 	WRITE_NODE_FIELD(name);
+ 	WRITE_BOOL_FIELD(element);
+}
+ 
+static void
 _outLockingClause(StringInfo str, const LockingClause *node)
 {
 	WRITE_NODE_TYPE("LOCKINGCLAUSE");
@@ -3467,6 +3476,8 @@ _outConstraint(StringInfo str, const Constraint *node)
 			WRITE_CHAR_FIELD(fk_upd_action);
 			WRITE_CHAR_FIELD(fk_del_action);
 			WRITE_NODE_FIELD(old_conpfeqop);
+ 			WRITE_BOOL_FIELD(fk_is_element);
+ 			WRITE_NODE_FIELD(fk_element_attrs);
 			WRITE_OID_FIELD(old_pktable_oid);
 			WRITE_BOOL_FIELD(skip_validation);
 			WRITE_BOOL_FIELD(initially_valid);
@@ -4175,6 +4186,9 @@ outNode(StringInfo str, const void *obj)
 			case T_TableLikeClause:
 				_outTableLikeClause(str, obj);
 				break;
+ 			case T_ForeignKeyColumnElem:
+ 				_outForeignKeyColumnElem(str, obj);
+ 				break;
 			case T_LockingClause:
 				_outLockingClause(str, obj);
 				break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0f3998ff89..16c71ad07d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -392,7 +392,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 				execute_param_clause using_clause returning_clause
 				opt_enum_val_list enum_val_list table_func_column_list
 				create_generic_options alter_generic_options
-				relation_expr_list dostmt_opt_list
+				relation_expr_list dostmt_opt_list foreignKeyColumnList
 				transform_element_list transform_type_list
 				TriggerTransitions TriggerReferencing
 				publication_name_list
@@ -466,7 +466,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <node>	def_arg columnElem where_clause where_or_current_clause
 				a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound
 				columnref in_expr having_clause func_table xmltable array_expr
-				ExclusionWhereClause operator_def_arg
+				ExclusionWhereClause foreignKeyColumnElem operator_def_arg
 %type <list>	rowsfrom_item rowsfrom_list opt_col_def_list
 %type <boolean> opt_ordinality
 %type <list>	ExclusionConstraintList ExclusionConstraintElem
@@ -622,7 +622,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
 	DOUBLE_P DROP
 
-	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
+	EACH ELEMENT ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
 	EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
 	EXTENSION EXTERNAL EXTRACT
 
@@ -766,6 +766,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
 /* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
 %right		PRESERVE STRIP_P
+%nonassoc	ELEMENT
 
 %%
 
@@ -3435,6 +3436,24 @@ ColConstraintElem:
 					n->fk_matchtype		= $4;
 					n->fk_upd_action	= (char) ($5 >> 8);
 					n->fk_del_action	= (char) ($5 & 0xFF);
+ 					n->fk_is_element		= false;
+ 					n->skip_validation  = false;
+ 					n->initially_valid  = true;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ELEMENT REFERENCES qualified_name opt_column_list
+ 				key_match key_actions
+ 				{
+ 					Constraint *n = makeNode(Constraint);
+ 					n->contype = CONSTR_FOREIGN;
+ 					n->location = @1;
+ 					n->pktable			= $3;
+ 					n->fk_attrs			= NIL;
+ 					n->pk_attrs			= $4;
+ 					n->fk_matchtype		= $5;
+ 					n->fk_upd_action	= (char) ($6 >> 8);
+ 					n->fk_del_action	= (char) ($6 & 0xFF);
+ 					n->fk_is_element		= true;
 					n->skip_validation  = false;
 					n->initially_valid  = true;
 					$$ = (Node *)n;
@@ -3625,8 +3644,9 @@ ConstraintElem:
 								   NULL, yyscanner);
 					$$ = (Node *)n;
 				}
-			| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
-				opt_column_list key_match key_actions ConstraintAttributeSpec
+ 			| FOREIGN KEY '(' foreignKeyColumnList ')' REFERENCES
+ 				qualified_name opt_column_list key_match key_actions
+ 				ConstraintAttributeSpec
 				{
 					Constraint *n = makeNode(Constraint);
 					n->contype = CONSTR_FOREIGN;
@@ -3649,7 +3669,31 @@ ConstraintElem:
 opt_no_inherit:	NO INHERIT							{  $$ = TRUE; }
 			| /* EMPTY */							{  $$ = FALSE; }
 		;
-
+ 
+foreignKeyColumnList:
+ 			foreignKeyColumnElem
+ 				{ $$ = list_make1($1); }
+ 			| foreignKeyColumnList ',' foreignKeyColumnElem
+ 				{ $$ = lappend($1, $3); }
+ 		;
+ 
+foreignKeyColumnElem:
+ 			ELEMENT ColId
+ 				{
+ 					ForeignKeyColumnElem *n = makeNode(ForeignKeyColumnElem);
+ 					n->name = (Node *) makeString($2);
+ 					n->element = true;
+ 					$$ = (Node *) n;
+ 				}
+ 			| ColId
+ 				{
+ 					ForeignKeyColumnElem *n = makeNode(ForeignKeyColumnElem);
+ 					n->name = (Node *) makeString($1);
+ 					n->element = false;
+ 					$$ = (Node *) n;
+ 				}
+ 		;
+ 
 opt_column_list:
 			'(' columnList ')'						{ $$ = $2; }
 			| /*EMPTY*/								{ $$ = NIL; }
@@ -14676,6 +14720,7 @@ unreserved_keyword:
 			| DOUBLE_P
 			| DROP
 			| EACH
+			| ELEMENT
 			| ENABLE_P
 			| ENCODING
 			| ENCRYPTED
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index ee5f3a3a52..128ed3b92a 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -743,6 +743,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 				 * list of FK constraints to be processed later.
 				 */
 				constraint->fk_attrs = list_make1(makeString(column->colname));
+ 				constraint->fk_element_attrs =
+ 						list_make1_int(constraint->fk_is_element);
 				cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
 				break;
 
@@ -856,6 +858,33 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
 			break;
 
 		case CONSTR_FOREIGN:
+ 			/*
+ 			 * Split the content of foreignKeyColumnList
+ 			 * in two separate list. One list of fields
+ 			 * and one list of boolean values.
+ 			 */
+ 			{
+ 				ListCell *i;
+ 				List *old_fk_attrs = constraint->fk_attrs;
+ 
+ 				constraint->fk_attrs = NIL;
+ 				constraint->fk_is_element = false;
+ 				constraint->fk_element_attrs = NIL;
+ 				foreach (i, old_fk_attrs)
+ 				{
+ 					ForeignKeyColumnElem *elem =
+ 						(ForeignKeyColumnElem *)lfirst(i);
+ 
+ 					Assert(IsA(elem, ForeignKeyColumnElem));
+ 					constraint->fk_attrs =
+ 						lappend(constraint->fk_attrs, elem->name);
+ 					constraint->fk_is_element |= elem->element;
+ 					constraint->fk_element_attrs =
+ 						lappend_int(constraint->fk_element_attrs,
+ 									elem->element);
+ 				}
+ 			}
+ 
 			if (cxt->isforeign)
 				ereport(ERROR,
 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index c2891e6fa1..c09277ef3a 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -115,12 +115,15 @@ typedef struct RI_ConstraintInfo
 	NameData	conname;		/* name of the FK constraint */
 	Oid			pk_relid;		/* referenced relation */
 	Oid			fk_relid;		/* referencing relation */
+ 	bool		confiselement;		/* is an array ELEMENT FK */
 	char		confupdtype;	/* foreign key's ON UPDATE action */
 	char		confdeltype;	/* foreign key's ON DELETE action */
 	char		confmatchtype;	/* foreign key's match type */
 	int			nkeys;			/* number of key columns */
 	int16		pk_attnums[RI_MAX_NUMKEYS]; /* attnums of referenced cols */
 	int16		fk_attnums[RI_MAX_NUMKEYS]; /* attnums of referencing cols */
+ 	bool		fk_element_atts[RI_MAX_NUMKEYS];	/* referencing cols is
+ 												 * an array ELEMENT FK */
 	Oid			pf_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = FK) */
 	Oid			pp_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = PK) */
 	Oid			ff_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (FK = FK) */
@@ -204,7 +207,8 @@ static void ri_GenerateQual(StringInfo buf,
 				const char *sep,
 				const char *leftop, Oid leftoptype,
 				Oid opoid,
-				const char *rightop, Oid rightoptype);
+ 				const char *rightop, Oid rightoptype,
+ 				bool is_array);
 static void ri_add_cast_to(StringInfo buf, Oid typid);
 static void ri_GenerateQualCollation(StringInfo buf, Oid collation);
 static int ri_NullCheck(HeapTuple tup,
@@ -395,6 +399,7 @@ RI_FKey_check(TriggerData *trigdata)
 	if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
 	{
 		StringInfoData querybuf;
+ 		StringInfoData countbuf;
 		char		pkrelname[MAX_QUOTED_REL_NAME_LEN];
 		char		attname[MAX_QUOTED_NAME_LEN];
 		char		paramname[16];
@@ -407,12 +412,24 @@ RI_FKey_check(TriggerData *trigdata)
 		 *		   FOR KEY SHARE OF x
 		 * The type id's for the $ parameters are those of the
 		 * corresponding FK attributes.
+ 		 *
+ 		 * In case of an array ELEMENT foreign key, the previous query is used
+ 		 * to count the number of matching rows and see if every combination
+ 		 * is actually referenced.
+ 		 * The wrapping query is
+ 		 *  SELECT 1 WHERE  1 *
+ 		 *    (SELECT count(DISTINCT y) FROM UNNEST($1) y WHERE y IS NOT NULL)
+ 		 *    [ * ...] = (SELECT count(*) FROM (<QUERY>) z)
 		 * ----------
 		 */
 		initStringInfo(&querybuf);
 		quoteRelationName(pkrelname, pk_rel);
 		appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", pkrelname);
 		querysep = "WHERE";
+ 		if (riinfo->confiselement) {
+ 			initStringInfo(&countbuf);
+ 			appendStringInfo(&countbuf, "SELECT 1 WHERE 1");
+ 		}
 		for (i = 0; i < riinfo->nkeys; i++)
 		{
 			Oid			pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
@@ -421,18 +438,40 @@ RI_FKey_check(TriggerData *trigdata)
 			quoteOneName(attname,
 						 RIAttName(pk_rel, riinfo->pk_attnums[i]));
 			sprintf(paramname, "$%d", i + 1);
+ 			/*
+ 			 * In case of an array ELEMENT foreign key, we check that every
+ 			 * DISTINCT NOT NULL value in the array is present in the PK
+ 			 * table.
+ 			 */
+ 			if (riinfo->fk_element_atts[i])
+ 			{
+ 				appendStringInfo(&countbuf,
+ 					" * (SELECT count(DISTINCT y) FROM UNNEST(%s) y WHERE y IS NOT NULL)",
+ 					paramname);
+ 			}
 			ri_GenerateQual(&querybuf, querysep,
 							attname, pk_type,
 							riinfo->pf_eq_oprs[i],
-							paramname, fk_type);
+ 							paramname, fk_type,
+ 							riinfo->fk_element_atts[i]);
 			querysep = "AND";
 			queryoids[i] = fk_type;
 		}
 		appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
 
-		/* Prepare and save the plan */
-		qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
-							 &qkey, fk_rel, pk_rel, true);
+ 		if (riinfo->confiselement) {
+ 			appendStringInfo(&countbuf,
+ 							 " = (SELECT count(*) FROM (%s) z)",
+ 							 querybuf.data);
+ 
+ 			/* Prepare and save the plan for array ELEMENT foreign keys */
+ 			qplan = ri_PlanCheck(countbuf.data, riinfo->nkeys, queryoids,
+ 								 &qkey, fk_rel, pk_rel, true);
+ 		}
+ 		else
+ 			/* Prepare and save the plan */
+ 			qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
+ 								 &qkey, fk_rel, pk_rel, true);
 	}
 
 	/*
@@ -559,7 +598,8 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
 			ri_GenerateQual(&querybuf, querysep,
 							attname, pk_type,
 							riinfo->pp_eq_oprs[i],
-							paramname, pk_type);
+ 							paramname, pk_type,
+ 							false);
 			querysep = "AND";
 			queryoids[i] = pk_type;
 		}
@@ -751,7 +791,8 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action)
 					ri_GenerateQual(&querybuf, querysep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = "AND";
 					queryoids[i] = pk_type;
 				}
@@ -974,7 +1015,8 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action)
 					ri_GenerateQual(&querybuf, querysep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = "AND";
 					queryoids[i] = pk_type;
 				}
@@ -1130,7 +1172,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&querybuf, querysep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = "AND";
 					queryoids[i] = pk_type;
 				}
@@ -1309,7 +1352,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&qualbuf, qualsep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									false);
 					querysep = ",";
 					qualsep = "AND";
 					queryoids[i] = pk_type;
@@ -1475,7 +1519,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&qualbuf, qualsep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = ",";
 					qualsep = "AND";
 					queryoids[i] = pk_type;
@@ -1651,7 +1696,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&qualbuf, qualsep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = ",";
 					qualsep = "AND";
 					queryoids[i] = pk_type;
@@ -1817,7 +1863,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&qualbuf, qualsep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = ",";
 					qualsep = "AND";
 					queryoids[i] = pk_type;
@@ -2008,7 +2055,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
 					ri_GenerateQual(&qualbuf, qualsep,
 									paramname, pk_type,
 									riinfo->pf_eq_oprs[i],
-									attname, fk_type);
+ 									attname, fk_type,
+ 									riinfo->fk_element_atts[i]);
 					querysep = ",";
 					qualsep = "AND";
 					queryoids[i] = pk_type;
@@ -2327,6 +2375,14 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	 * For MATCH FULL:
 	 *	 (fk.keycol1 IS NOT NULL [OR ...])
 	 *
+ 	 * In case of an array ELEMENT column, relname is replaced with the
+ 	 * following subquery:
+ 	 *
+ 	 *   SELECT unnest("keycol1") k1, "keycol1" ak1 [, ...]
+ 	 *   FROM ONLY "public"."fk"
+ 	 *
+ 	 * where all the columns are renamed in order to prevent name collisions.
+ 	 *
 	 * We attach COLLATE clauses to the operators when comparing columns
 	 * that have different collations.
 	 *----------
@@ -2338,15 +2394,46 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	{
 		quoteOneName(fkattname,
 					 RIAttName(fk_rel, riinfo->fk_attnums[i]));
-		appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
+ 		if (riinfo->confiselement)
+ 			if (riinfo->fk_element_atts[i])
+ 				appendStringInfo(&querybuf, "%sfk.ak%d %s", sep, i + 1,
+ 								 fkattname);
+ 			else
+ 				appendStringInfo(&querybuf, "%sfk.k%d %s", sep, i + 1,
+ 								 fkattname);
+ 		else
+ 			appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
 		sep = ", ";
 	}
 
 	quoteRelationName(pkrelname, pk_rel);
 	quoteRelationName(fkrelname, fk_rel);
-	appendStringInfo(&querybuf,
-					 " FROM ONLY %s fk LEFT OUTER JOIN ONLY %s pk ON",
-					 fkrelname, pkrelname);
+ 
+ 	if (riinfo->confiselement)
+ 	{
+ 		sep = "";
+ 		appendStringInfo(&querybuf,
+ 				 " FROM (SELECT ");
+ 		for (i = 0; i < riinfo->nkeys; i++)
+ 		{
+ 			quoteOneName(fkattname,
+ 						 RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ 			if (riinfo->fk_element_atts[i])
+ 				appendStringInfo(&querybuf, "%sunnest(%s) k%d, %s ak%d",
+ 						sep, fkattname, i + 1, fkattname, i + 1);
+ 			else
+ 				appendStringInfo(&querybuf, "%s%s k%d", sep, fkattname,
+ 								 i + 1);
+ 			sep = ", ";
+ 		}
+ 		appendStringInfo(&querybuf,
+ 				 " FROM ONLY %s) fk LEFT OUTER JOIN ONLY %s pk ON",
+ 				 fkrelname, pkrelname);
+ 	}
+ 	else
+ 		appendStringInfo(&querybuf,
+ 						 " FROM ONLY %s fk LEFT OUTER JOIN ONLY %s pk ON",
+ 						 fkrelname, pkrelname);
 
 	strcpy(pkattname, "pk.");
 	strcpy(fkattname, "fk.");
@@ -2360,12 +2447,16 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 
 		quoteOneName(pkattname + 3,
 					 RIAttName(pk_rel, riinfo->pk_attnums[i]));
-		quoteOneName(fkattname + 3,
+ 		if (riinfo->confiselement)
+ 			sprintf(fkattname + 3, "k%d", i + 1);
+ 		else
+ 			quoteOneName(fkattname + 3,
 					 RIAttName(fk_rel, riinfo->fk_attnums[i]));
 		ri_GenerateQual(&querybuf, sep,
 						pkattname, pk_type,
 						riinfo->pf_eq_oprs[i],
-						fkattname, fk_type);
+ 						fkattname, fk_type,
+ 						false);
 		if (pk_coll != fk_coll)
 			ri_GenerateQualCollation(&querybuf, pk_coll);
 		sep = "AND";
@@ -2381,7 +2472,10 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	sep = "";
 	for (i = 0; i < riinfo->nkeys; i++)
 	{
-		quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ 		if (riinfo->confiselement)
+ 			sprintf(fkattname, "k%d", i + 1);
+ 		else
+ 			quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
 		appendStringInfo(&querybuf,
 						 "%sfk.%s IS NOT NULL",
 						 sep, fkattname);
@@ -2570,7 +2664,8 @@ ri_GenerateQual(StringInfo buf,
 				const char *sep,
 				const char *leftop, Oid leftoptype,
 				Oid opoid,
-				const char *rightop, Oid rightoptype)
+ 				const char *rightop, Oid rightoptype,
+ 				bool is_array)
 {
 	HeapTuple	opertup;
 	Form_pg_operator operform;
@@ -2591,9 +2686,23 @@ ri_GenerateQual(StringInfo buf,
 		ri_add_cast_to(buf, operform->oprleft);
 	appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
 	appendStringInfoString(buf, oprname);
-	appendStringInfo(buf, ") %s", rightop);
-	if (rightoptype != operform->oprright)
-		ri_add_cast_to(buf, operform->oprright);
+ 	/*
+ 	 * If rightoptype is an array of leftoptype check equality using ANY().
+ 	 * Needed for array support in foreign keys.
+ 	 */
+ 	if (is_array)
+ 	{
+ 		appendStringInfo(buf, ") ANY (%s", rightop);
+ 		if (rightoptype != get_array_type (operform->oprright))
+ 			ri_add_cast_to(buf, get_array_type (operform->oprright));
+ 		appendStringInfo(buf, ")");
+ 	}
+ 	else
+ 	{
+ 		appendStringInfo(buf, ") %s", rightop);
+ 		if (rightoptype != operform->oprright)
+ 			ri_add_cast_to(buf, operform->oprright);
+ 	}
 
 	ReleaseSysCache(opertup);
 }
@@ -2841,6 +2950,7 @@ ri_LoadConstraintInfo(Oid constraintOid)
 	riinfo->confupdtype = conForm->confupdtype;
 	riinfo->confdeltype = conForm->confdeltype;
 	riinfo->confmatchtype = conForm->confmatchtype;
+ 	riinfo->confiselement = conForm->confiselement;
 
 	/*
 	 * We expect the arrays to be 1-D arrays of the right types; verify that.
@@ -2878,6 +2988,23 @@ ri_LoadConstraintInfo(Oid constraintOid)
 	if ((Pointer) arr != DatumGetPointer(adatum))
 		pfree(arr);				/* free de-toasted copy, if any */
 
+ 	adatum = SysCacheGetAttr(CONSTROID, tup,
+ 							 Anum_pg_constraint_confelement, &isNull);
+ 	if (isNull)
+ 		elog(ERROR, "null confelement for constraint %u", constraintOid);
+ 	arr = DatumGetArrayTypeP(adatum);	/* ensure not toasted */
+ 	numkeys = ARR_DIMS(arr)[0];
+ 	if (ARR_NDIM(arr) != 1 ||
+ 		numkeys != riinfo->nkeys ||
+ 		numkeys > RI_MAX_NUMKEYS ||
+ 		ARR_HASNULL(arr) ||
+ 		ARR_ELEMTYPE(arr) != BOOLOID)
+ 		elog(ERROR, "confelement is not a 1-D boolean array");
+ 	memcpy(riinfo->fk_element_atts, ARR_DATA_PTR(arr),
+ 		   numkeys * sizeof(int16));
+ 	if ((Pointer) arr != DatumGetPointer(adatum))
+ 		pfree(arr);				/* free de-toasted copy, if any */
+ 
 	adatum = SysCacheGetAttr(CONSTROID, tup,
 							 Anum_pg_constraint_conpfeqop, &isNull);
 	if (isNull)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 18d9e27d1e..6f0368a523 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -314,6 +314,9 @@ static char *pg_get_viewdef_worker(Oid viewoid,
 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
 static void decompile_column_index_array(Datum column_index_array, Oid relId,
 							 StringInfo buf);
+static void decompile_fk_column_index_array(Datum column_index_array,
+ 								Datum element_array,
+ 								Oid relId, StringInfo buf);
 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
 					   const Oid *excludeOps,
@@ -1876,6 +1879,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 		case CONSTRAINT_FOREIGN:
 			{
 				Datum		val;
+ 				Datum		element;
 				bool		isnull;
 				const char *string;
 
@@ -1888,11 +1892,20 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 				if (isnull)
 					elog(ERROR, "null conkey for constraint %u",
 						 constraintId);
-
-				decompile_column_index_array(val, conForm->conrelid, &buf);
+ 				element = SysCacheGetAttr(CONSTROID, tup,
+ 										  Anum_pg_constraint_confelement,
+ 										  &isnull);
+ 				if (isnull)
+ 					elog(ERROR, "null confelement for constraint %u",
+ 						 constraintId);
+
+ 				decompile_fk_column_index_array(val, element,
+ 												conForm->conrelid, &buf);
+ 
+ 				appendStringInfo(&buf, ") REFERENCES ");
 
 				/* add foreign relation name */
-				appendStringInfo(&buf, ") REFERENCES %s(",
+				appendStringInfo(&buf, "%s(",
 								 generate_relation_name(conForm->confrelid,
 														NIL));
 
@@ -2179,6 +2192,54 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
 }
 
 
+/*
+ * Convert an int16[] Datum and an bool[] Datum into a comma-separated
+ * list of column names for the indicated relation prefixed by
+ * an optional ELEMENT keyword; append the list to buf.
+ *
+ * The two arrays must have the same cardinality.
+ */
+static void
+decompile_fk_column_index_array(Datum column_index_array,
+ 								Datum element_array,
+ 								Oid relId, StringInfo buf)
+{
+ 	Datum	   *keys;
+ 	int			nKeys;
+ 	Datum	   *bools;
+ 	int			nBools;
+ 	int			j;
+ 
+ 	/* Extract data from array of int16 */
+ 	deconstruct_array(DatumGetArrayTypeP(column_index_array),
+ 					  INT2OID, 2, true, 's',
+ 					  &keys, NULL, &nKeys);
+ 
+ 	/* Extract data from array of bool */
+ 	deconstruct_array(DatumGetArrayTypeP(element_array),
+ 					  BOOLOID, 1, true, 'c',
+ 					  &bools, NULL, &nBools);
+ 
+ 	if (nKeys != nBools)
+ 		elog(ERROR, "wrong confelement cardinality");
+ 
+ 	for (j = 0; j < nKeys; j++)
+ 	{
+ 		char	   *colName;
+ 		char	   *element;
+ 
+ 		colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
+ 		element = DatumGetBool(bools[j])?"ELEMENT ":"";
+ 
+ 		if (j == 0)
+ 			appendStringInfo(buf, "%s%s", element,
+ 							 quote_identifier(colName));
+ 		else
+ 			appendStringInfo(buf, ", %s%s", element,
+ 							 quote_identifier(colName));
+ 	}
+}
+
 /* ----------
  * get_expr			- Decompile an expression tree
  *
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index ec035d8434..177254c217 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -90,6 +90,9 @@ CATALOG(pg_constraint,2606)
 	/* Has a local definition and cannot be inherited */
 	bool		connoinherit;
 
+ 	/* true if an array ELEMENT foreign key */
+ 	bool		confiselement;
+ 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 
 	/*
@@ -104,6 +107,12 @@ CATALOG(pg_constraint,2606)
 	int16		confkey[1];
 
 	/*
+ 	 * If a foreign key, true if array ELEMENT foreign key for each column of
+ 	 * the constraint
+ 	 */
+ 	bool		confelement[1];
+ 
+ 	/*
 	 * If a foreign key, the OIDs of the PK = FK equality operators for each
 	 * column of the constraint
 	 */
@@ -150,7 +159,7 @@ typedef FormData_pg_constraint *Form_pg_constraint;
  *		compiler constants for pg_constraint
  * ----------------
  */
-#define Natts_pg_constraint					24
+#define Natts_pg_constraint					26
 #define Anum_pg_constraint_conname			1
 #define Anum_pg_constraint_connamespace		2
 #define Anum_pg_constraint_contype			3
@@ -167,14 +176,16 @@ typedef FormData_pg_constraint *Form_pg_constraint;
 #define Anum_pg_constraint_conislocal		14
 #define Anum_pg_constraint_coninhcount		15
 #define Anum_pg_constraint_connoinherit		16
-#define Anum_pg_constraint_conkey			17
-#define Anum_pg_constraint_confkey			18
-#define Anum_pg_constraint_conpfeqop		19
-#define Anum_pg_constraint_conppeqop		20
-#define Anum_pg_constraint_conffeqop		21
-#define Anum_pg_constraint_conexclop		22
-#define Anum_pg_constraint_conbin			23
-#define Anum_pg_constraint_consrc			24
+#define Anum_pg_constraint_coniselement		17
+#define Anum_pg_constraint_conkey			18
+#define Anum_pg_constraint_confkey			19
+#define Anum_pg_constraint_confelement		20
+#define Anum_pg_constraint_conpfeqop		21
+#define Anum_pg_constraint_conppeqop		22
+#define Anum_pg_constraint_conffeqop		23
+#define Anum_pg_constraint_conexclop		24
+#define Anum_pg_constraint_conbin			25
+#define Anum_pg_constraint_consrc			26
 
 /* ----------------
  *		initial contents of pg_constraint
diff --git a/src/include/catalog/pg_constraint_fn.h b/src/include/catalog/pg_constraint_fn.h
index a4c46897ed..4aa074f9c3 100644
--- a/src/include/catalog/pg_constraint_fn.h
+++ b/src/include/catalog/pg_constraint_fn.h
@@ -44,6 +44,8 @@ extern Oid CreateConstraintEntry(const char *constraintName,
 					  const Oid *ppEqOp,
 					  const Oid *ffEqOp,
 					  int foreignNKeys,
+ 					  bool confisElement,
+ 					  const bool *foreignElement,
 					  char foreignUpdateType,
 					  char foreignDeleteType,
 					  char foreignMatchType,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 01527399b8..6cff3ba4b3 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -461,6 +461,7 @@ typedef enum NodeTag
 	T_InferClause,
 	T_OnConflictClause,
 	T_CommonTableExpr,
+ 	T_ForeignKeyColumnElem,
 	T_RoleSpec,
 	T_TriggerTransition,
 	T_PartitionElem,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1d96169d34..62843df063 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -723,6 +723,21 @@ typedef struct DefElem
 } DefElem;
 
 /*
+  * ForeignKeyColumnElem - foreign key column (used in foreign key
+  * constraint)
+  *
+  * For a foreign key attribute, 'name' is the name of the table column to
+  * index, and element is true if it is an array ELEMENT fk.
+*/
+typedef struct ForeignKeyColumnElem
+{
+ 	NodeTag		type;
+ 	Node	   *name;			/* name of the column, or NULL */
+ 	bool		element;		/* true if an array ELEMENT foreign key */
+ 
+} ForeignKeyColumnElem;
+ 
+ /*
  * LockingClause - raw representation of FOR [NO KEY] UPDATE/[KEY] SHARE
  *		options
  *
@@ -2098,6 +2113,8 @@ typedef struct Constraint
 	char		fk_upd_action;	/* ON UPDATE action */
 	char		fk_del_action;	/* ON DELETE action */
 	List	   *old_conpfeqop;	/* pg_constraint.conpfeqop of my former self */
+ 	bool		fk_is_element;		/* is array ELEMENT foreign key? */
+ 	List	   *fk_element_attrs;	/* array ELEMENT FK attrs */
 	Oid			old_pktable_oid;	/* pg_constraint.confrelid of my former
 									 * self */
 
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index f50e45e886..d3f4803006 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -140,6 +140,7 @@ PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
 PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
+PG_KEYWORD("element", ELEMENT, UNRESERVED_KEYWORD)
 PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
 PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expected/element_foreign_key.out b/src/test/regress/expected/element_foreign_key.out
new file mode 100644
index 0000000000..bfe9ebe20f
--- /dev/null
+++ b/src/test/regress/expected/element_foreign_key.out
@@ -0,0 +1,591 @@
+-- ELEMENT FK CONSTRAINTS
+--
+CREATE TABLE PKTABLEFORARRAY ( ptest1 int PRIMARY KEY, ptest2 text );
+-- Insert test data into PKTABLEFORARRAY
+INSERT INTO PKTABLEFORARRAY VALUES (1, 'Test1');
+INSERT INTO PKTABLEFORARRAY VALUES (2, 'Test2');
+INSERT INTO PKTABLEFORARRAY VALUES (3, 'Test3');
+INSERT INTO PKTABLEFORARRAY VALUES (4, 'Test4');
+INSERT INTO PKTABLEFORARRAY VALUES (5, 'Test5');
+-- Check alter table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAY;
+-- Check alter table with rows
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 1);
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAY;
+-- Check alter table with failing rows
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+INSERT INTO FKTABLEFORARRAY VALUES ('{10,1}', 2);
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fkarray"
+DETAIL:  Key (ftest1)=({10,1}) is not present in table "pktableforarray".
+DROP TABLE FKTABLEFORARRAY;
+-- Check create table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+CREATE TABLE FKTABLEFORARRAYMDIM ( ftest1 int[][] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+CREATE TABLE FKTABLEFORARRAYNOTNULL ( ftest1 int[] NOT NULL ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+-- Insert successful rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 3);
+INSERT INTO FKTABLEFORARRAY VALUES ('{2}', 4);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 5);
+INSERT INTO FKTABLEFORARRAY VALUES ('{3}', 6);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 7);
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,5}', 8);
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,4}', 9);
+INSERT INTO FKTABLEFORARRAY VALUES (NULL, 10);
+INSERT INTO FKTABLEFORARRAY VALUES ('{}', 11);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1,NULL}', 12);
+INSERT INTO FKTABLEFORARRAY VALUES ('{NULL}', 13);
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{4,5},{1,2},{1,3}}', 14);
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{4,5},{NULL,2},{NULL,3}}', 15);
+-- Insert failed rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{6}', 16);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({6}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,6}', 17);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({4,6}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES ('{6,NULL}', 18);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({6,NULL}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES ('{6,NULL,4,NULL}', 19);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({6,NULL,4,NULL}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{1,2},{6,NULL}}', 20);
+ERROR:  insert or update on table "fktableforarraymdim" violates foreign key constraint "fktableforarraymdim_ftest1_fkey"
+DETAIL:  Key (ftest1)=({{1,2},{6,NULL}}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAYNOTNULL VALUES (NULL, 21);
+ERROR:  null value in column "ftest1" violates not-null constraint
+DETAIL:  Failing row contains (null, 21).
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+  ftest1  | ftest2 
+----------+--------
+ {1}      |      3
+ {2}      |      4
+ {1}      |      5
+ {3}      |      6
+ {1}      |      7
+ {4,5}    |      8
+ {4,4}    |      9
+          |     10
+ {}       |     11
+ {1,NULL} |     12
+ {NULL}   |     13
+(11 rows)
+
+-- Delete a row from PK TABLE (must fail due to ON DELETE NO ACTION)
+DELETE FROM PKTABLEFORARRAY WHERE ptest1=1;
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey" on table "fktableforarray"
+DETAIL:  Key (ptest1)=(1) is still referenced from table "fktableforarray".
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+  ftest1  | ftest2 
+----------+--------
+ {1}      |      3
+ {2}      |      4
+ {1}      |      5
+ {3}      |      6
+ {1}      |      7
+ {4,5}    |      8
+ {4,4}    |      9
+          |     10
+ {}       |     11
+ {1,NULL} |     12
+ {NULL}   |     13
+(11 rows)
+
+-- Update a row from PK TABLE (must fail due to ON UPDATE NO ACTION)
+UPDATE PKTABLEFORARRAY SET ptest1=7 WHERE ptest1=1;
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey" on table "fktableforarray"
+DETAIL:  Key (ptest1)=(1) is still referenced from table "fktableforarray".
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+  ftest1  | ftest2 
+----------+--------
+ {1}      |      3
+ {2}      |      4
+ {1}      |      5
+ {3}      |      6
+ {1}      |      7
+ {4,5}    |      8
+ {4,4}    |      9
+          |     10
+ {}       |     11
+ {1,NULL} |     12
+ {NULL}   |     13
+(11 rows)
+
+-- Check UPDATE on FKTABLE
+UPDATE FKTABLEFORARRAY SET ftest1=ARRAY[1] WHERE ftest2=4;
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+  ftest1  | ftest2 
+----------+--------
+ {1}      |      3
+ {1}      |      5
+ {3}      |      6
+ {1}      |      7
+ {4,5}    |      8
+ {4,4}    |      9
+          |     10
+ {}       |     11
+ {1,NULL} |     12
+ {NULL}   |     13
+ {1}      |      4
+(11 rows)
+
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAYNOTNULL;
+DROP TABLE FKTABLEFORARRAYMDIM;
+-- Allowed references with actions (NO ACTION, RESTRICT)
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+-- Not allowed references (SET NULL, SET DEFAULT, CASCADE)
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE SET DEFAULT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE SET NULL, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE SET DEFAULT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE SET NULL, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE NO ACTION, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE RESTRICT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE SET DEFAULT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE SET NULL, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE NO ACTION, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE RESTRICT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE SET DEFAULT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE SET NULL, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE NO ACTION, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE RESTRICT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE SET DEFAULT, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE SET NULL, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE CASCADE, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE CASCADE, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE CASCADE, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE CASCADE, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE CASCADE, ftest2 int );
+ERROR:  array ELEMENT foreign keys only support NO ACTION and RESTRICT actions
+DROP TABLE FKTABLEFORARRAY;
+ERROR:  table "fktableforarray" does not exist
+-- Cleanup
+DROP TABLE PKTABLEFORARRAY;
+-- Check reference on empty table
+CREATE TABLE PKTABLEFORARRAY (ptest1 int PRIMARY KEY);
+CREATE TABLE FKTABLEFORARRAY  (ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY);
+INSERT INTO FKTABLEFORARRAY VALUES ('{}');
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- Repeat a similar test using CHAR(1) keys rather than INTEGER
+CREATE TABLE PKTABLEFORARRAY ( ptest1 CHAR(1) PRIMARY KEY, ptest2 text );
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'Test A');
+INSERT INTO PKTABLEFORARRAY VALUES ('B', 'Test B');
+INSERT INTO PKTABLEFORARRAY VALUES ('C', 'Test C');
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 char(1)[] ELEMENT REFERENCES PKTABLEFORARRAY ON UPDATE RESTRICT ON DELETE RESTRICT, ftest2 int );
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A"}', 1);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"B"}', 2);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"C"}', 3);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A","B","C"}', 4);
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{"D"}', 5);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({D}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A","B","D"}', 6);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({A,B,D}) is not present in table "pktableforarray".
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+ ftest1  | ftest2 
+---------+--------
+ {A}     |      1
+ {B}     |      2
+ {C}     |      3
+ {A,B,C} |      4
+(4 rows)
+
+-- Delete a row from PK TABLE (must fail due to ON DELETE RESTRICT)
+DELETE FROM PKTABLEFORARRAY WHERE ptest1='A';
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey" on table "fktableforarray"
+DETAIL:  Key (ptest1)=(A) is still referenced from table "fktableforarray".
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+ ftest1  | ftest2 
+---------+--------
+ {A}     |      1
+ {B}     |      2
+ {C}     |      3
+ {A,B,C} |      4
+(4 rows)
+
+-- Update a row from PK TABLE (must fail due to ON UPDATE RESTRICT)
+UPDATE PKTABLEFORARRAY SET ptest1='D' WHERE ptest1='B';
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey" on table "fktableforarray"
+DETAIL:  Key (ptest1)=(B) is still referenced from table "fktableforarray".
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+ ftest1  | ftest2 
+---------+--------
+ {A}     |      1
+ {B}     |      2
+ {C}     |      3
+ {A,B,C} |      4
+(4 rows)
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- Repeat a similar test using INT4 keys coerced from INT2
+CREATE TABLE PKTABLEFORARRAY ( ptest1 int4 PRIMARY KEY, ptest2 text );
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES (1, 'Test 1');
+INSERT INTO PKTABLEFORARRAY VALUES (2, 'Test 2');
+INSERT INTO PKTABLEFORARRAY VALUES (3, 'Test 3');
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int2[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1], 1);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[2], 2);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[3], 3);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1,2,3], 4);
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[4], 5);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({4}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1,2,5], 6);
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_ftest1_fkey"
+DETAIL:  Key (ftest1)=({1,2,5}) is not present in table "pktableforarray".
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- Repeat a similar test using FLOAT keys coerced from INTEGER
+CREATE TABLE PKTABLEFORARRAY ( ptest1 float PRIMARY KEY, ptest2 text );
+-- FAILS because equality operator are incompatible
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+ERROR:  foreign key constraint "fktableforarray_ftest1_fkey" cannot be implemented
+DETAIL:  Key columns "ftest1" and "ptest1" are of incompatible types: integer[] and double precision.
+-- Cleanup
+DROP TABLE PKTABLEFORARRAY;
+-- Composite primary keys
+CREATE TABLE PKTABLEFORARRAY ( id1 CHAR(1), id2 CHAR(1), ptest2 text, PRIMARY KEY (id1, id2) );
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'A', 'Test A');
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'B', 'Test B');
+INSERT INTO PKTABLEFORARRAY VALUES ('B', 'C', 'Test B');
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( fid1 CHAR(1), fid2 CHAR(1)[], ftest2 text, FOREIGN KEY (fid1, ELEMENT fid2) REFERENCES PKTABLEFORARRAY);
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('A', ARRAY['A','B'], '1');
+INSERT INTO FKTABLEFORARRAY VALUES ('B', ARRAY['C'], '2');
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('A', ARRAY['A','B', 'C'], '3');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_fid1_fkey"
+DETAIL:  Key (fid1, fid2)=(A, {A,B,C}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY VALUES ('B', ARRAY['A'], '4');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_fid1_fkey"
+DETAIL:  Key (fid1, fid2)=(B, {A}) is not present in table "pktableforarray".
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- Test ELEMENT foreign keys with composite type
+CREATE TYPE INVOICEID AS (year_part INTEGER, progressive_part INTEGER);
+CREATE TABLE PKTABLEFORARRAY ( id INVOICEID PRIMARY KEY,  ptest2 text);
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2010, 99), 'Last invoice for 2010');
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2011, 1), 'First invoice for 2011');
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2011, 2), 'Second invoice for 2011');
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( id SERIAL PRIMARY KEY, invoice_ids INVOICEID[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 TEXT );
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2010,99)']::INVOICEID[], 'Product A');
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,1)','(2011,2)']::INVOICEID[], 'Product B');
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,2)']::INVOICEID[], 'Product C');
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,99)']::INVOICEID[], 'Product A');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_invoice_ids_fkey"
+DETAIL:  Key (invoice_ids)=({"(2011,99)"}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,1)','(2010,1)']::INVOICEID[], 'Product B');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_invoice_ids_fkey"
+DETAIL:  Key (invoice_ids)=({"(2011,1)","(2010,1)"}) is not present in table "pktableforarray".
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+ id |       invoice_ids       |  ftest2   
+----+-------------------------+-----------
+  1 | {"(2010,99)"}           | Product A
+  2 | {"(2011,1)","(2011,2)"} | Product B
+  3 | {"(2011,2)"}            | Product C
+(3 rows)
+
+-- Delete a row from PK TABLE
+DELETE FROM PKTABLEFORARRAY WHERE id=ROW(2010,99);
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_invoice_ids_fkey" on table "fktableforarray"
+DETAIL:  Key (id)=((2010,99)) is still referenced from table "fktableforarray".
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+ id |       invoice_ids       |  ftest2   
+----+-------------------------+-----------
+  1 | {"(2010,99)"}           | Product A
+  2 | {"(2011,1)","(2011,2)"} | Product B
+  3 | {"(2011,2)"}            | Product C
+(3 rows)
+
+-- Update a row from PK TABLE
+UPDATE PKTABLEFORARRAY SET id=ROW(2011,99) WHERE id=ROW(2011,1);
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_invoice_ids_fkey" on table "fktableforarray"
+DETAIL:  Key (id)=((2011,1)) is still referenced from table "fktableforarray".
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+ id |       invoice_ids       |  ftest2   
+----+-------------------------+-----------
+  1 | {"(2010,99)"}           | Product A
+  2 | {"(2011,1)","(2011,2)"} | Product B
+  3 | {"(2011,2)"}            | Product C
+(3 rows)
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+DROP TYPE INVOICEID;
+-- Check FK with cast
+CREATE TABLE PKTABLEFORARRAY (c smallint PRIMARY KEY);
+CREATE TABLE FKTABLEFORARRAY  (c int[] ELEMENT REFERENCES PKTABLEFORARRAY);
+INSERT INTO PKTABLEFORARRAY VALUES (1), (2);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1,2}');
+UPDATE PKTABLEFORARRAY SET c = 3 WHERE c = 2;
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_c_fkey" on table "fktableforarray"
+DETAIL:  Key (c)=(2) is still referenced from table "fktableforarray".
+DELETE FROM PKTABLEFORARRAY WHERE c = 1;
+ERROR:  update or delete on table "pktableforarray" violates foreign key constraint "fktableforarray_c_fkey" on table "fktableforarray"
+DETAIL:  Key (c)=(1) is still referenced from table "fktableforarray".
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- Check for an array column referencing another array column (NOT ELEMENT FOREIGN KEY)
+-- Create primary table with an array primary key
+CREATE TABLE PKTABLEFORARRAY ( id INT[] PRIMARY KEY,  ptest2 text);
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( id SERIAL PRIMARY KEY, fids INT[] REFERENCES PKTABLEFORARRAY, ftest2 TEXT );
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('{1,1}', 'A');
+INSERT INTO PKTABLEFORARRAY VALUES ('{1,2}', 'B');
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{1,1}', 'Product A');
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{1,2}', 'Product B');
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{0,1}', 'Product C');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_fids_fkey"
+DETAIL:  Key (fids)=({0,1}) is not present in table "pktableforarray".
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{2,1}', 'Product D');
+ERROR:  insert or update on table "fktableforarray" violates foreign key constraint "fktableforarray_fids_fkey"
+DETAIL:  Key (fids)=({2,1}) is not present in table "pktableforarray".
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+-- ---------------------------------------
+-- Multi-column "ELEMENT" foreign key tests
+-- ---------------------------------------
+-- Create DIM1 table with two-column primary key
+CREATE TABLE DIM1 (X INTEGER NOT NULL, Y INTEGER NOT NULL, PRIMARY KEY (X, Y));
+-- Populate DIM1 table pairs
+INSERT INTO DIM1 SELECT x.t, x.t * y.t
+	FROM (SELECT generate_series(1, 10) AS t) x,
+	(SELECT generate_series(0, 10) AS t) y;
+-- Test with TABLE declaration of an element foreign key constraint (NO ACTION)
+CREATE TABLE F1 (
+	x INTEGER PRIMARY KEY, y INTEGER[],
+	FOREIGN KEY (x, ELEMENT y) REFERENCES DIM1(x, y)
+);
+-- Insert facts
+INSERT INTO F1 VALUES (1, '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES (2, '{0,2,4,6}'); -- OK
+INSERT INTO F1 VALUES (3, '{0,3,6,9,0,3,6,9,0,0,0,0,9,9}'); -- OK (multiple occurrences)
+INSERT INTO F1 VALUES (4, '{0,2,4}'); -- FAILS (2 is not present)
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_x_fkey"
+DETAIL:  Key (x, y)=(4, {0,2,4}) is not present in table "dim1".
+INSERT INTO F1 VALUES (4, '{0,NULL,4}'); -- OK
+INSERT INTO F1 VALUES (5, '{0,NULL,5}'); -- OK
+-- Try updates
+UPDATE F1 SET y = '{0,2,4,6}' WHERE x = 2; -- OK
+UPDATE F1 SET y = '{0,2,3,4,6}' WHERE x = 2; -- FAILS
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_x_fkey"
+DETAIL:  Key (x, y)=(2, {0,2,3,4,6}) is not present in table "dim1".
+UPDATE F1 SET x = 20, y = '{0,2,3,4,6}' WHERE x = 2; -- FAILS (20 does not exist)
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_x_fkey"
+DETAIL:  Key (x, y)=(20, {0,2,3,4,6}) is not present in table "dim1".
+UPDATE F1 SET y = '{0,4,8}' WHERE x = 4; -- OK
+UPDATE F1 SET y = '{0,5,NULL,10}' WHERE x = 5; -- OK
+DROP TABLE F1;
+-- Test with FOREIGN KEY after TABLE population
+CREATE TABLE F1 (
+	x INTEGER PRIMARY KEY, y INTEGER[]
+);
+-- Insert facts
+INSERT INTO F1 VALUES (1, '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES (2, '{0,2,4,6}'); -- OK
+INSERT INTO F1 VALUES (3, '{0,3,6,9,0,3,6,9,0,0,0,0,9,9}'); -- OK (multiple occurrences)
+INSERT INTO F1 VALUES (4, '{0,2,4}'); -- OK (2 is not present)
+INSERT INTO F1 VALUES (5, '{0,NULL,5}'); -- OK
+-- Add foreign key (FAILS)
+ALTER TABLE F1 ADD FOREIGN KEY (x, ELEMENT y) REFERENCES DIM1(x, y);
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_x_fkey"
+DETAIL:  Key (x, y)=(4, {0,2,4}) is not present in table "dim1".
+DROP TABLE F1;
+-- Test with TABLE declaration of a two-dim ELEMENT foreign key constraint (FAILS)
+CREATE TABLE F1 (
+	x INTEGER[] PRIMARY KEY, y INTEGER[],
+	FOREIGN KEY (ELEMENT x, ELEMENT y) REFERENCES DIM1(x, y)
+);
+ERROR:  array ELEMENT foreign keys support only one ELEMENT column
+-- Test with two-dim ELEMENT foreign key after TABLE population
+CREATE TABLE F1 (
+	x INTEGER[] PRIMARY KEY, y INTEGER[]
+);
+INSERT INTO F1 VALUES ('{1}', '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES ('{1,2}', '{0,2,4,6}'); -- OK
+-- Add foreign key (FAILS)
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT x, ELEMENT y) REFERENCES DIM1(x, y);
+ERROR:  array ELEMENT foreign keys support only one ELEMENT column
+DROP TABLE F1;
+-- Cleanup
+DROP TABLE DIM1;
+-- Check for potential name conflicts (with internal integrity checks)
+CREATE TABLE x1(x1 int, x2 int, PRIMARY KEY(x1,x2));
+INSERT INTO x1 VALUES
+       (1,4),
+       (1,5),
+       (2,4),
+       (2,5),
+       (3,6),
+       (3,7)
+;
+CREATE TABLE x2(x1 int[], x2 int, FOREIGN KEY(ELEMENT x1, x2) REFERENCES x1);
+INSERT INTO x2 VALUES ('{1,2}',4);
+INSERT INTO x2 VALUES ('{1,3}',6); -- FAILS
+ERROR:  insert or update on table "x2" violates foreign key constraint "x2_x1_fkey"
+DETAIL:  Key (x1, x2)=({1,3}, 6) is not present in table "x1".
+DROP TABLE x2;
+CREATE TABLE x2(x1 int[], x2 int);
+INSERT INTO x2 VALUES ('{1,2}',4);
+INSERT INTO x2 VALUES ('{1,3}',6);
+ALTER TABLE x2 ADD CONSTRAINT fk_const FOREIGN KEY(ELEMENT x1, x2) REFERENCES x1;  -- FAILS
+ERROR:  insert or update on table "x2" violates foreign key constraint "fk_const"
+DETAIL:  Key (x1, x2)=({1,3}, 6) is not present in table "x1".
+DROP TABLE x2;
+DROP TABLE x1;
+-- ---------------------------------------
+-- Multi-dimensional "ELEMENT" foreign key tests
+-- ---------------------------------------
+-- Create DIM1 table with two-column primary key
+CREATE TABLE DIM1 (X INTEGER NOT NULL PRIMARY KEY,
+	CODE TEXT NOT NULL UNIQUE);
+-- Populate DIM1 table pairs
+INSERT INTO DIM1 SELECT t, 'DIM1-' || lpad(t::TEXT, 2, '0')
+	FROM (SELECT generate_series(1, 10)) x(t);
+-- Test with TABLE declaration of an element foreign key constraint (NO ACTION)
+CREATE TABLE F1 (
+	ID SERIAL PRIMARY KEY,
+	SLOTS INTEGER[3][3] ELEMENT REFERENCES DIM1
+);
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 3}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- FAILS
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_slots_fkey"
+DETAIL:  Key (slots)=({{NULL,1,NULL},{NULL,NULL,11},{NULL,NULL,6}}) is not present in table "dim1".
+INSERT INTO F1(SLOTS) VALUES ('{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{1, 2, 3, 4, 5, 6, 7, 8, 9}'); -- OK
+UPDATE F1 SET SLOTS = '{{NULL, 1, NULL}, {NULL, NULL, 3}, {7, 8, 10}}' WHERE ID = 1; -- OK
+UPDATE F1 SET SLOTS = '{{100, 100, 100}, {NULL, NULL, 20}, {7, 8, 10}}' WHERE ID = 1; -- FAILS
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_slots_fkey"
+DETAIL:  Key (slots)=({{100,100,100},{NULL,NULL,20},{7,8,10}}) is not present in table "dim1".
+DROP TABLE F1;
+-- Test with postponed foreign key
+CREATE TABLE F1 (
+	ID SERIAL PRIMARY KEY,
+	SLOTS INTEGER[3][3]
+);
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 3}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{1, 2, 3, 4, 5, 6, 7, 8, 9}'); -- OK
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT SLOTS) REFERENCES DIM1; -- FAILS
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_slots_fkey"
+DETAIL:  Key (slots)=({{NULL,1,NULL},{NULL,NULL,11},{NULL,NULL,6}}) is not present in table "dim1".
+DELETE FROM F1 WHERE ID = 2; -- REMOVE ISSUE
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT SLOTS) REFERENCES DIM1; -- NOW OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- FAILS
+ERROR:  insert or update on table "f1" violates foreign key constraint "f1_slots_fkey"
+DETAIL:  Key (slots)=({{NULL,1,NULL},{NULL,NULL,11},{NULL,NULL,6}}) is not present in table "dim1".
+DROP TABLE F1;
+-- Leave tables in the database
+CREATE TABLE PKTABLEFORELEMENTFK ( ptest1 int PRIMARY KEY, ptest2 text );
+CREATE TABLE FKTABLEFORELEMENTFK ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORELEMENTFK, ftest2 int );
+-- Check ALTER TABLE ALTER TYPE
+ALTER TABLE FKTABLEFORELEMENTFK ALTER FTEST1 TYPE INT[];
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 23692615f9..72674fc3f2 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -103,7 +103,7 @@ test: publication subscription
 # ----------
 # Another group of parallel tests
 # ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb json_encoding indirect_toast equivclass
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb json_encoding indirect_toast equivclass element_foreign_key
 # ----------
 # Another group of parallel tests
 # NB: temp.sql does a reconnect which transiently uses 2 connections,
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 5e8b7e94c4..e56038579a 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -141,6 +141,7 @@ test: amutils
 test: select_views
 test: portals_p2
 test: foreign_key
+test: element_foreign_key
 test: cluster
 test: dependency
 test: guc
diff --git a/src/test/regress/sql/element_foreign_key.sql b/src/test/regress/sql/element_foreign_key.sql
new file mode 100644
index 0000000000..103a25b197
--- /dev/null
+++ b/src/test/regress/sql/element_foreign_key.sql
@@ -0,0 +1,452 @@
+-- ELEMENT FK CONSTRAINTS
+--
+CREATE TABLE PKTABLEFORARRAY ( ptest1 int PRIMARY KEY, ptest2 text );
+
+-- Insert test data into PKTABLEFORARRAY
+INSERT INTO PKTABLEFORARRAY VALUES (1, 'Test1');
+INSERT INTO PKTABLEFORARRAY VALUES (2, 'Test2');
+INSERT INTO PKTABLEFORARRAY VALUES (3, 'Test3');
+INSERT INTO PKTABLEFORARRAY VALUES (4, 'Test4');
+INSERT INTO PKTABLEFORARRAY VALUES (5, 'Test5');
+
+-- Check alter table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAY;
+
+-- Check alter table with rows
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 1);
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAY;
+
+-- Check alter table with failing rows
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[], ftest2 int );
+INSERT INTO FKTABLEFORARRAY VALUES ('{10,1}', 2);
+ALTER TABLE FKTABLEFORARRAY ADD CONSTRAINT FKARRAY FOREIGN KEY (ELEMENT ftest1) REFERENCES PKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAY;
+
+-- Check create table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+CREATE TABLE FKTABLEFORARRAYMDIM ( ftest1 int[][] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+CREATE TABLE FKTABLEFORARRAYNOTNULL ( ftest1 int[] NOT NULL ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+
+-- Insert successful rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 3);
+INSERT INTO FKTABLEFORARRAY VALUES ('{2}', 4);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 5);
+INSERT INTO FKTABLEFORARRAY VALUES ('{3}', 6);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1}', 7);
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,5}', 8);
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,4}', 9);
+INSERT INTO FKTABLEFORARRAY VALUES (NULL, 10);
+INSERT INTO FKTABLEFORARRAY VALUES ('{}', 11);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1,NULL}', 12);
+INSERT INTO FKTABLEFORARRAY VALUES ('{NULL}', 13);
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{4,5},{1,2},{1,3}}', 14);
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{4,5},{NULL,2},{NULL,3}}', 15);
+
+-- Insert failed rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{6}', 16);
+INSERT INTO FKTABLEFORARRAY VALUES ('{4,6}', 17);
+INSERT INTO FKTABLEFORARRAY VALUES ('{6,NULL}', 18);
+INSERT INTO FKTABLEFORARRAY VALUES ('{6,NULL,4,NULL}', 19);
+INSERT INTO FKTABLEFORARRAYMDIM VALUES ('{{1,2},{6,NULL}}', 20);
+INSERT INTO FKTABLEFORARRAYNOTNULL VALUES (NULL, 21);
+
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Delete a row from PK TABLE (must fail due to ON DELETE NO ACTION)
+DELETE FROM PKTABLEFORARRAY WHERE ptest1=1;
+
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Update a row from PK TABLE (must fail due to ON UPDATE NO ACTION)
+UPDATE PKTABLEFORARRAY SET ptest1=7 WHERE ptest1=1;
+
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Check UPDATE on FKTABLE
+UPDATE FKTABLEFORARRAY SET ftest1=ARRAY[1] WHERE ftest2=4;
+
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE FKTABLEFORARRAYNOTNULL;
+DROP TABLE FKTABLEFORARRAYMDIM;
+
+-- Allowed references with actions (NO ACTION, RESTRICT)
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+-- Not allowed references (SET NULL, SET DEFAULT, CASCADE)
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE SET DEFAULT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE SET NULL, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE SET DEFAULT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE SET NULL, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE SET DEFAULT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE SET NULL, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE SET DEFAULT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE SET NULL, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE NO ACTION, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE RESTRICT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE SET DEFAULT, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE SET NULL, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE NO ACTION ON UPDATE CASCADE, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE RESTRICT ON UPDATE CASCADE, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE CASCADE ON UPDATE CASCADE, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET DEFAULT ON UPDATE CASCADE, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY ON DELETE SET NULL ON UPDATE CASCADE, ftest2 int );
+DROP TABLE FKTABLEFORARRAY;
+
+-- Cleanup
+DROP TABLE PKTABLEFORARRAY;
+
+-- Check reference on empty table
+CREATE TABLE PKTABLEFORARRAY (ptest1 int PRIMARY KEY);
+CREATE TABLE FKTABLEFORARRAY  (ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY);
+INSERT INTO FKTABLEFORARRAY VALUES ('{}');
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- Repeat a similar test using CHAR(1) keys rather than INTEGER
+CREATE TABLE PKTABLEFORARRAY ( ptest1 CHAR(1) PRIMARY KEY, ptest2 text );
+
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'Test A');
+INSERT INTO PKTABLEFORARRAY VALUES ('B', 'Test B');
+INSERT INTO PKTABLEFORARRAY VALUES ('C', 'Test C');
+
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 char(1)[] ELEMENT REFERENCES PKTABLEFORARRAY ON UPDATE RESTRICT ON DELETE RESTRICT, ftest2 int );
+
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A"}', 1);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"B"}', 2);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"C"}', 3);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A","B","C"}', 4);
+
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('{"D"}', 5);
+INSERT INTO FKTABLEFORARRAY VALUES ('{"A","B","D"}', 6);
+
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Delete a row from PK TABLE (must fail due to ON DELETE RESTRICT)
+DELETE FROM PKTABLEFORARRAY WHERE ptest1='A';
+
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Update a row from PK TABLE (must fail due to ON UPDATE RESTRICT)
+UPDATE PKTABLEFORARRAY SET ptest1='D' WHERE ptest1='B';
+
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- Repeat a similar test using INT4 keys coerced from INT2
+CREATE TABLE PKTABLEFORARRAY ( ptest1 int4 PRIMARY KEY, ptest2 text );
+
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES (1, 'Test 1');
+INSERT INTO PKTABLEFORARRAY VALUES (2, 'Test 2');
+INSERT INTO PKTABLEFORARRAY VALUES (3, 'Test 3');
+
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int2[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1], 1);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[2], 2);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[3], 3);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1,2,3], 4);
+
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[4], 5);
+INSERT INTO FKTABLEFORARRAY VALUES (ARRAY[1,2,5], 6);
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- Repeat a similar test using FLOAT keys coerced from INTEGER
+CREATE TABLE PKTABLEFORARRAY ( ptest1 float PRIMARY KEY, ptest2 text );
+-- FAILS because equality operator are incompatible
+CREATE TABLE FKTABLEFORARRAY ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 int );
+
+-- Cleanup
+DROP TABLE PKTABLEFORARRAY;
+
+-- Composite primary keys
+CREATE TABLE PKTABLEFORARRAY ( id1 CHAR(1), id2 CHAR(1), ptest2 text, PRIMARY KEY (id1, id2) );
+
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'A', 'Test A');
+INSERT INTO PKTABLEFORARRAY VALUES ('A', 'B', 'Test B');
+INSERT INTO PKTABLEFORARRAY VALUES ('B', 'C', 'Test B');
+
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( fid1 CHAR(1), fid2 CHAR(1)[], ftest2 text, FOREIGN KEY (fid1, ELEMENT fid2) REFERENCES PKTABLEFORARRAY);
+
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('A', ARRAY['A','B'], '1');
+INSERT INTO FKTABLEFORARRAY VALUES ('B', ARRAY['C'], '2');
+
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY VALUES ('A', ARRAY['A','B', 'C'], '3');
+INSERT INTO FKTABLEFORARRAY VALUES ('B', ARRAY['A'], '4');
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- Test ELEMENT foreign keys with composite type
+CREATE TYPE INVOICEID AS (year_part INTEGER, progressive_part INTEGER);
+CREATE TABLE PKTABLEFORARRAY ( id INVOICEID PRIMARY KEY,  ptest2 text);
+
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2010, 99), 'Last invoice for 2010');
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2011, 1), 'First invoice for 2011');
+INSERT INTO PKTABLEFORARRAY VALUES (ROW(2011, 2), 'Second invoice for 2011');
+
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( id SERIAL PRIMARY KEY, invoice_ids INVOICEID[] ELEMENT REFERENCES PKTABLEFORARRAY, ftest2 TEXT );
+
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2010,99)']::INVOICEID[], 'Product A');
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,1)','(2011,2)']::INVOICEID[], 'Product B');
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,2)']::INVOICEID[], 'Product C');
+
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,99)']::INVOICEID[], 'Product A');
+INSERT INTO FKTABLEFORARRAY(invoice_ids, ftest2) VALUES (ARRAY['(2011,1)','(2010,1)']::INVOICEID[], 'Product B');
+
+-- Check FKTABLE
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Delete a row from PK TABLE
+DELETE FROM PKTABLEFORARRAY WHERE id=ROW(2010,99);
+
+-- Check FKTABLE for removal of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Update a row from PK TABLE
+UPDATE PKTABLEFORARRAY SET id=ROW(2011,99) WHERE id=ROW(2011,1);
+
+-- Check FKTABLE for update of matched row
+SELECT * FROM FKTABLEFORARRAY;
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+DROP TYPE INVOICEID;
+
+-- Check FK with cast
+CREATE TABLE PKTABLEFORARRAY (c smallint PRIMARY KEY);
+CREATE TABLE FKTABLEFORARRAY  (c int[] ELEMENT REFERENCES PKTABLEFORARRAY);
+INSERT INTO PKTABLEFORARRAY VALUES (1), (2);
+INSERT INTO FKTABLEFORARRAY VALUES ('{1,2}');
+UPDATE PKTABLEFORARRAY SET c = 3 WHERE c = 2;
+DELETE FROM PKTABLEFORARRAY WHERE c = 1;
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- Check for an array column referencing another array column (NOT ELEMENT FOREIGN KEY)
+-- Create primary table with an array primary key
+CREATE TABLE PKTABLEFORARRAY ( id INT[] PRIMARY KEY,  ptest2 text);
+
+-- Create the foreign table
+CREATE TABLE FKTABLEFORARRAY ( id SERIAL PRIMARY KEY, fids INT[] REFERENCES PKTABLEFORARRAY, ftest2 TEXT );
+
+-- Populate the primary table
+INSERT INTO PKTABLEFORARRAY VALUES ('{1,1}', 'A');
+INSERT INTO PKTABLEFORARRAY VALUES ('{1,2}', 'B');
+
+-- Insert valid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{1,1}', 'Product A');
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{1,2}', 'Product B');
+
+-- Insert invalid rows into FK TABLE
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{0,1}', 'Product C');
+INSERT INTO FKTABLEFORARRAY (fids, ftest2) VALUES ('{2,1}', 'Product D');
+
+-- Cleanup
+DROP TABLE FKTABLEFORARRAY;
+DROP TABLE PKTABLEFORARRAY;
+
+-- ---------------------------------------
+-- Multi-column "ELEMENT" foreign key tests
+-- ---------------------------------------
+
+-- Create DIM1 table with two-column primary key
+CREATE TABLE DIM1 (X INTEGER NOT NULL, Y INTEGER NOT NULL, PRIMARY KEY (X, Y));
+-- Populate DIM1 table pairs
+INSERT INTO DIM1 SELECT x.t, x.t * y.t
+	FROM (SELECT generate_series(1, 10) AS t) x,
+	(SELECT generate_series(0, 10) AS t) y;
+
+
+-- Test with TABLE declaration of an element foreign key constraint (NO ACTION)
+CREATE TABLE F1 (
+	x INTEGER PRIMARY KEY, y INTEGER[],
+	FOREIGN KEY (x, ELEMENT y) REFERENCES DIM1(x, y)
+);
+-- Insert facts
+INSERT INTO F1 VALUES (1, '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES (2, '{0,2,4,6}'); -- OK
+INSERT INTO F1 VALUES (3, '{0,3,6,9,0,3,6,9,0,0,0,0,9,9}'); -- OK (multiple occurrences)
+INSERT INTO F1 VALUES (4, '{0,2,4}'); -- FAILS (2 is not present)
+INSERT INTO F1 VALUES (4, '{0,NULL,4}'); -- OK
+INSERT INTO F1 VALUES (5, '{0,NULL,5}'); -- OK
+-- Try updates
+UPDATE F1 SET y = '{0,2,4,6}' WHERE x = 2; -- OK
+UPDATE F1 SET y = '{0,2,3,4,6}' WHERE x = 2; -- FAILS
+UPDATE F1 SET x = 20, y = '{0,2,3,4,6}' WHERE x = 2; -- FAILS (20 does not exist)
+UPDATE F1 SET y = '{0,4,8}' WHERE x = 4; -- OK
+UPDATE F1 SET y = '{0,5,NULL,10}' WHERE x = 5; -- OK
+DROP TABLE F1;
+
+
+-- Test with FOREIGN KEY after TABLE population
+CREATE TABLE F1 (
+	x INTEGER PRIMARY KEY, y INTEGER[]
+);
+-- Insert facts
+INSERT INTO F1 VALUES (1, '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES (2, '{0,2,4,6}'); -- OK
+INSERT INTO F1 VALUES (3, '{0,3,6,9,0,3,6,9,0,0,0,0,9,9}'); -- OK (multiple occurrences)
+INSERT INTO F1 VALUES (4, '{0,2,4}'); -- OK (2 is not present)
+INSERT INTO F1 VALUES (5, '{0,NULL,5}'); -- OK
+-- Add foreign key (FAILS)
+ALTER TABLE F1 ADD FOREIGN KEY (x, ELEMENT y) REFERENCES DIM1(x, y);
+DROP TABLE F1;
+
+
+-- Test with TABLE declaration of a two-dim ELEMENT foreign key constraint (FAILS)
+CREATE TABLE F1 (
+	x INTEGER[] PRIMARY KEY, y INTEGER[],
+	FOREIGN KEY (ELEMENT x, ELEMENT y) REFERENCES DIM1(x, y)
+);
+
+
+-- Test with two-dim ELEMENT foreign key after TABLE population
+CREATE TABLE F1 (
+	x INTEGER[] PRIMARY KEY, y INTEGER[]
+);
+INSERT INTO F1 VALUES ('{1}', '{0,1,2,3,4,5}'); -- OK
+INSERT INTO F1 VALUES ('{1,2}', '{0,2,4,6}'); -- OK
+-- Add foreign key (FAILS)
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT x, ELEMENT y) REFERENCES DIM1(x, y);
+DROP TABLE F1;
+
+-- Cleanup
+DROP TABLE DIM1;
+
+
+-- Check for potential name conflicts (with internal integrity checks)
+CREATE TABLE x1(x1 int, x2 int, PRIMARY KEY(x1,x2));
+INSERT INTO x1 VALUES
+       (1,4),
+       (1,5),
+       (2,4),
+       (2,5),
+       (3,6),
+       (3,7)
+;
+CREATE TABLE x2(x1 int[], x2 int, FOREIGN KEY(ELEMENT x1, x2) REFERENCES x1);
+INSERT INTO x2 VALUES ('{1,2}',4);
+INSERT INTO x2 VALUES ('{1,3}',6); -- FAILS
+DROP TABLE x2;
+CREATE TABLE x2(x1 int[], x2 int);
+INSERT INTO x2 VALUES ('{1,2}',4);
+INSERT INTO x2 VALUES ('{1,3}',6);
+ALTER TABLE x2 ADD CONSTRAINT fk_const FOREIGN KEY(ELEMENT x1, x2) REFERENCES x1;  -- FAILS
+DROP TABLE x2;
+DROP TABLE x1;
+
+
+-- ---------------------------------------
+-- Multi-dimensional "ELEMENT" foreign key tests
+-- ---------------------------------------
+
+-- Create DIM1 table with two-column primary key
+CREATE TABLE DIM1 (X INTEGER NOT NULL PRIMARY KEY,
+	CODE TEXT NOT NULL UNIQUE);
+-- Populate DIM1 table pairs
+INSERT INTO DIM1 SELECT t, 'DIM1-' || lpad(t::TEXT, 2, '0')
+	FROM (SELECT generate_series(1, 10)) x(t);
+
+-- Test with TABLE declaration of an element foreign key constraint (NO ACTION)
+CREATE TABLE F1 (
+	ID SERIAL PRIMARY KEY,
+	SLOTS INTEGER[3][3] ELEMENT REFERENCES DIM1
+);
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 3}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- FAILS
+INSERT INTO F1(SLOTS) VALUES ('{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{1, 2, 3, 4, 5, 6, 7, 8, 9}'); -- OK
+UPDATE F1 SET SLOTS = '{{NULL, 1, NULL}, {NULL, NULL, 3}, {7, 8, 10}}' WHERE ID = 1; -- OK
+UPDATE F1 SET SLOTS = '{{100, 100, 100}, {NULL, NULL, 20}, {7, 8, 10}}' WHERE ID = 1; -- FAILS
+DROP TABLE F1;
+
+-- Test with postponed foreign key
+CREATE TABLE F1 (
+	ID SERIAL PRIMARY KEY,
+	SLOTS INTEGER[3][3]
+);
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 3}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}'); -- OK
+INSERT INTO F1(SLOTS) VALUES ('{1, 2, 3, 4, 5, 6, 7, 8, 9}'); -- OK
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT SLOTS) REFERENCES DIM1; -- FAILS
+DELETE FROM F1 WHERE ID = 2; -- REMOVE ISSUE
+ALTER TABLE F1 ADD FOREIGN KEY (ELEMENT SLOTS) REFERENCES DIM1; -- NOW OK
+INSERT INTO F1(SLOTS) VALUES ('{{NULL, 1, NULL}, {NULL, NULL, 11}, {NULL, NULL, 6}}'); -- FAILS
+DROP TABLE F1;
+
+-- Leave tables in the database
+CREATE TABLE PKTABLEFORELEMENTFK ( ptest1 int PRIMARY KEY, ptest2 text );
+CREATE TABLE FKTABLEFORELEMENTFK ( ftest1 int[] ELEMENT REFERENCES PKTABLEFORELEMENTFK, ftest2 int );
+
+-- Check ALTER TABLE ALTER TYPE
+ALTER TABLE FKTABLEFORELEMENTFK ALTER FTEST1 TYPE INT[];
\ No newline at end of file
