diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index a7a05762de3cb50e25f615856f02a2c3c89281a4..985a92f7fa1b31b58e9ea413865fbc437881820b 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/array.sgml,v 1.26 2003/06/24 23:14:42 momjian Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/array.sgml,v 1.27 2003/06/25 21:30:25 momjian Exp $ -->
 
 <sect1 id="arrays">
  <title>Arrays</title>
@@ -60,74 +60,14 @@ INSERT INTO sal_emp
 </programlisting>
  </para>
 
- <para>
-  A limitation of the present array implementation is that individual
-  elements of an array cannot be SQL null values.  The entire array can be set
-  to null, but you can't have an array with some elements null and some
-  not.
- </para>
- <para>
-  This can lead to surprising results. For example, the result of the
-  previous two inserts looks like this:
-<programlisting>
-SELECT * FROM sal_emp;
- name  |      pay_by_quarter       |      schedule
--------+---------------------------+--------------------
- Bill  | {10000,10000,10000,10000} | {{meeting},{""}}
- Carol | {20000,25000,25000,25000} | {{talk},{meeting}}
-(2 rows)
-</programlisting>
-  Because the <literal>[2][2]</literal> element of
-  <structfield>schedule</structfield> is missing in each of the
-  <command>INSERT</command> statements, the <literal>[1][2]</literal>
-  element is discarded.
- </para>
-
  <note>
   <para>
-   Fixing this is on the to-do list.
+   A limitation of the present array implementation is that individual
+   elements of an array cannot be SQL null values.  The entire array can be set
+   to null, but you can't have an array with some elements null and some
+   not.  Fixing this is on the to-do list.
   </para>
  </note>
-
- <para>
-  The <command>ARRAY</command> expression syntax may also be used:
-<programlisting>
-INSERT INTO sal_emp
-    VALUES ('Bill',
-    ARRAY[10000, 10000, 10000, 10000],
-    ARRAY[['meeting', 'lunch'], ['','']]);
-
-INSERT INTO sal_emp
-    VALUES ('Carol',
-    ARRAY[20000, 25000, 25000, 25000],
-    ARRAY[['talk', 'consult'], ['meeting', '']]);
-SELECT * FROM sal_emp;
- name  |      pay_by_quarter       |           schedule
--------+---------------------------+-------------------------------
- Bill  | {10000,10000,10000,10000} | {{meeting,lunch},{"",""}}
- Carol | {20000,25000,25000,25000} | {{talk,consult},{meeting,""}}
-(2 rows)
-</programlisting>
-  Note that with this syntax, multidimensional arrays must have matching
-  extents for each dimension. This eliminates the missing-array-elements
-  problem above. For example:
-<programlisting>
-INSERT INTO sal_emp
-    VALUES ('Carol',
-    ARRAY[20000, 25000, 25000, 25000],
-    ARRAY[['talk', 'consult'], ['meeting']]);
-ERROR:  Multidimensional arrays must have array expressions with matching dimensions
-</programlisting>
-  Also notice that string literals are single quoted instead of double quoted.
- </para>
-
- <note>
-  <para>
-   The examples in the rest of this section are based on the
-   <command>ARRAY</command> expression syntax <command>INSERT</command>s.
-  </para>
- </note>
-
  </sect2>
 
  <sect2>
@@ -192,30 +132,11 @@ SELECT schedule[1:2][1] FROM sal_emp WHERE name = 'Bill';
 </programlisting>
 
   with the same result.  An array subscripting operation is always taken to
-  represent an array slice if any of the subscripts are written in the form
+  represent an array slice if any of the subscripts are written in the
+  form
   <literal><replaceable>lower</replaceable>:<replaceable>upper</replaceable></literal>.
   A lower bound of 1 is assumed for any subscript where only one value
-  is specified; another example follows:
-<programlisting>
-SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';
-         schedule
----------------------------
- {{meeting,lunch},{"",""}}
-(1 row)
-</programlisting>
- </para>
-
- <para>
-  Additionally, we can also access a single arbitrary array element of 
-  a one-dimensional array with the <function>array_subscript</function>
-  function:
-<programlisting>
-SELECT array_subscript(pay_by_quarter, 2) FROM sal_emp WHERE name = 'Bill';
- array_subscript
------------------
-           10000
-(1 row)
-</programlisting>
+  is specified.
  </para>
 
  <para>
@@ -226,23 +147,7 @@ UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
     WHERE name = 'Carol';
 </programlisting>
 
-  or using the <command>ARRAY</command> expression syntax:
-
-<programlisting>
-UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
-    WHERE name = 'Carol';
-</programlisting>
-
-  <note>
-   <para>
-    Anywhere you can use the <quote>curly braces</quote> array syntax,
-    you can also use the <command>ARRAY</command> expression syntax. The
-    remainder of this section will illustrate only one or the other, but
-    not both.
-   </para>
-  </note>
-
-  An array may also be updated at a single element:
+  or updated at a single element:
 
 <programlisting>
 UPDATE sal_emp SET pay_by_quarter[4] = 15000
@@ -255,14 +160,6 @@ UPDATE sal_emp SET pay_by_quarter[4] = 15000
 UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
     WHERE name = 'Carol';
 </programlisting>
-
-  A one-dimensional array may also be updated with the
-  <function>array_assign</function> function:
-
-<programlisting>
-UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000)
-    WHERE name = 'Bill';
-</programListing>
  </para>
 
  <para>
@@ -281,88 +178,6 @@ UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000)
   create an array with subscript values running from -2 to 7.
  </para>
 
- <para>
-  An array can also be enlarged by using the concatenation operator,
-  <command>||</command>.
-<programlisting>
-SELECT ARRAY[1,2] || ARRAY[3,4];
-   ?column?
----------------
- {{1,2},{3,4}}
-(1 row)
-
-SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]];
-      ?column?
----------------------
- {{5,6},{1,2},{3,4}}
-(1 row)
-</programlisting>
-
-  The concatenation operator allows a single element to be pushed on to the
-  beginning or end of a one-dimensional array. It also allows two
-  <replaceable>N</>-dimensional arrays, or an <replaceable>N</>-dimensional
-  and an <replaceable>N+1</>-dimensional array. In the former case, the two
-  <replaceable>N</>-dimension arrays become outer elements of an
-  <replaceable>N+1</>-dimensional array. In the latter, the
-  <replaceable>N</>-dimensional array is added as either the first or last
-  outer element of the <replaceable>N+1</>-dimensional array.
-
-  The array is extended in the direction of the push. Hence, by pushing
-  onto the beginning of an array with a one-based subscript, a zero-based
-  subscript array is created:
-
-<programlisting>
-SELECT array_dims(t.f) FROM (SELECT 1 || ARRAY[2,3] AS f) AS t;
- array_dims
-------------
- [0:2]
-(1 row)
-</programlisting>
- </para>
-
- <para>
-  An array can also be enlarged by using the functions
-  <function>array_prepend</function>, <function>array_append</function>,
-  or <function>array_cat</function>. The first two only support one-dimensional
-  arrays, but <function>array_cat</function> supports multidimensional arrays.
-
-  Note that the concatenation operator discussed above is preferred over
-  direct use of these functions. In fact, the functions are primarily for use
-  in implementing the concatenation operator. However, they may be directly
-  useful in the creation of user-defined aggregates. Some examples:
-
-<programlisting>
-SELECT array_prepend(1, ARRAY[2,3]);
- array_prepend
----------------
- {1,2,3}
-(1 row)
-
-SELECT array_append(ARRAY[1,2], 3);
- array_append
---------------
- {1,2,3}
-(1 row)
-
-SELECT array_cat(ARRAY[1,2], ARRAY[3,4]);
-   array_cat
----------------
- {{1,2},{3,4}}
-(1 row)
-
-SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
-      array_cat
----------------------
- {{1,2},{3,4},{5,6}}
-(1 row)
-
-SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]);
-      array_cat
----------------------
- {{5,6},{1,2},{3,4}}
-</programlisting>
- </para>
-
  <para>
   The syntax for <command>CREATE TABLE</command> allows fixed-length
   arrays to be defined:
@@ -378,16 +193,6 @@ CREATE TABLE tictactoe (
   length.
  </para>
 
- <para>
-  An alternative syntax for one-dimensional arrays may be used.
-  <structfield>pay_by_quarter</structfield> could have been defined as:
-<programlisting>
-    pay_by_quarter  integer ARRAY[4],
-</programlisting>
-  This syntax may <emphasis>only</emphasis> be used with the integer
-  constant to denote the array size.
- </para>
-
  <para>
   Actually, the current implementation does not enforce the declared
   number of dimensions either.  Arrays of a particular element type are
@@ -495,72 +300,6 @@ SELECT * FROM sal_emp WHERE pay_by_quarter **= 10000;
    is not ignored, however: after skipping leading whitespace, everything
    up to the next right brace or delimiter is taken as the item value.
   </para>
-
-  <para>
-   As illustrated earlier in this chapter, arrays may also be represented
-   using the <command>ARRAY</command> expression syntax. This representation
-   of an array value consists of items that are interpreted according to the
-   I/O conversion rules for the array's element type, plus decoration that
-   indicates the array structure. The decoration consists of the keyword
-   <command>ARRAY</command> and square brackets (<literal>[</> and
-   <literal>]</>) around the array values, plus delimiter characters between
-   adjacent items. The delimiter character is always a comma (<literal>,</>).
-   When representing multidimensional arrays, the keyword
-   <command>ARRAY</command> is only necessary for the outer level. For example,
-   <literal>'{{"hello world", "happy birthday"}}'</literal> could be written as:
-<programlisting>
-SELECT ARRAY[['hello world', 'happy birthday']];
-               array
-------------------------------------
- {{"hello world","happy birthday"}}
-(1 row)
-</programlisting>
-  or it also could be written as:
-<programlisting>
-SELECT ARRAY[ARRAY['hello world', 'happy birthday']];
-               array
-------------------------------------
- {{"hello world","happy birthday"}}
-(1 row)
-</programlisting>
-  </para>
-
-  <para>
-   A final method to represent an array, is through an
-   <command>ARRAY</command> sub-select expression. For example:
-<programlisting>
-SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
-                          ?column?
--------------------------------------------------------------
- {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
-(1 row)
-</programlisting>
-  The sub-select may <emphasis>only</emphasis> return a single column. The
-  resulting one-dimensional array will have an element for each row in the
-  sub-select result, with an element type matching that of the sub-select's
-  target column.
-  </para>
-
-  <para>
-   Arrays may be cast from one type to another in similar fashion to other
-   data types:
-
-<programlisting>
-SELECT ARRAY[1,2,3]::oid[];
-  array
----------
- {1,2,3}
-(1 row)
-
-SELECT CAST(ARRAY[1,2,3] AS float8[]);
-  array
----------
- {1,2,3}
-(1 row)
-</programlisting>
-
-  </para>
-
  </sect2>
 
  <sect2>
@@ -578,14 +317,6 @@ SELECT CAST(ARRAY[1,2,3] AS float8[]);
    that would otherwise be taken as array syntax or ignorable white space.
   </para>
 
- <note>
-  <para>
-   The discussion in the preceding paragraph with respect to double quoting does
-   not pertain to the <command>ARRAY</command> expression syntax. In that case,
-   each element is quoted exactly as any other literal value of the element type.
-  </para>
- </note>
-
   <para>
    The array output routine will put double quotes around element values
    if they are empty strings or contain curly braces, delimiter characters,
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index d092cafa2da475ccc527cfb5e2bd9ff2f109faff..3db3ab34e83a84193b129235212d9e0e9b7782ad 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.155 2003/06/24 23:14:42 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.156 2003/06/25 21:30:25 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -6962,203 +6962,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
 
   </sect1>
 
- <sect1 id="functions-array">
-  <title>Array Functions</title>
-
-  <para>
-   <xref linkend="array-operators-table"> shows the operators
-   available for the <type>array</type> types.
-  </para>
-
-    <table id="array-operators-table">
-     <title><type>array</type> Operators</title>
-     <tgroup cols="4">
-      <thead>
-       <row>
-	<entry>Operator</entry>
-	<entry>Description</entry>
-	<entry>Example</entry>
-	<entry>Result</entry>
-       </row>
-      </thead>
-      <tbody>
-       <row>
-	<entry> <literal>=</literal> </entry>
-	<entry>equals</entry>
-	<entry><literal>ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]</literal></entry>
-	<entry><literal>t</literal></entry>
-       </row>
-       <row>
-	<entry> <literal>||</literal> </entry>
-	<entry>array-to-array concatenation</entry>
-	<entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry>
-	<entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
-       </row>
-       <row>
-	<entry> <literal>||</literal> </entry>
-	<entry>array-to-array concatenation</entry>
-	<entry><literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]</literal></entry>
-	<entry><literal>{{1,2,3},{4,5,6},{7,8,9}}</literal></entry>
-       </row>
-       <row>
-	<entry> <literal>||</literal> </entry>
-	<entry>element-to-array concatenation</entry>
-	<entry><literal>3 || ARRAY[4,5,6]</literal></entry>
-	<entry><literal>{3,4,5,6}</literal></entry>
-       </row>
-       <row>
-	<entry> <literal>||</literal> </entry>
-	<entry>array-to-element concatenation</entry>
-	<entry><literal>ARRAY[4,5,6] || 7</literal></entry>
-	<entry><literal>{4,5,6,7}</literal></entry>
-       </row>
-      </tbody>
-     </tgroup>
-    </table>
-
-  <para>
-   <xref linkend="array-functions-table"> shows the functions
-   available for use with array types. See <xref linkend="arrays">
-   for more discussion and examples for the use of these functions.
-  </para>
-
-    <table id="array-functions-table">
-     <title><type>array</type> Functions</title>
-     <tgroup cols="5">
-      <thead>
-       <row>
-	<entry>Function</entry>
-	<entry>Return Type</entry>
-	<entry>Description</entry>
-	<entry>Example</entry>
-	<entry>Result</entry>
-       </row>
-      </thead>
-      <tbody>
-       <row>
-	<entry>
-     <literal>
-      <function>array_append</function>
-      (<type>anyarray</type>, <type>anyelement</type>)
-     </literal>
-    </entry>
-	<entry><type>anyarray</type></entry>
-	<entry>
-     append an element to the end of an array, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_append(ARRAY[1,2], 3)</literal></entry>
-	<entry><literal>{1,2,3}</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_cat</function>
-      (<type>anyarray</type>, <type>anyarray</type>)
-     </literal>
-    </entry>
-	<entry><type>anyarray</type></entry>
-	<entry>
-     concatenate two arrays, returning <literal>NULL</literal>
-     for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_cat(ARRAY[1,2,3], ARRAY[4,5,6])</literal></entry>
-	<entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_dims</function>
-      (<type>anyarray</type>)
-     </literal>
-    </entry>
-	<entry><type>text</type></entry>
-	<entry>
-     returns a text representation of array dimension lower and upper bounds,
-     generating an ERROR for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_dims(array[[1,2,3],[4,5,6]])</literal></entry>
-	<entry><literal>[1:2][1:3]</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_lower</function>
-      (<type>anyarray</type>, <type>integer</type>)
-     </literal>
-    </entry>
-	<entry><type>integer</type></entry>
-	<entry>
-     returns lower bound of the requested array dimension, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_lower(array_prepend(0, ARRAY[1,2,3]), 1)</literal></entry>
-	<entry><literal>0</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_prepend</function>
-      (<type>anyelement</type>, <type>anyarray</type>)
-     </literal>
-    </entry>
-	<entry><type>anyarray</type></entry>
-	<entry>
-     append an element to the beginning of an array, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_prepend(1, ARRAY[2,3])</literal></entry>
-	<entry><literal>{1,2,3}</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_to_string</function>
-      (<type>anyarray</type>, <type>text</type>)
-     </literal>
-    </entry>
-	<entry><type>text</type></entry>
-	<entry>
-     concatenates array elements using provided delimiter, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_to_string(array[1.1,2.2,3.3]::numeric(4,2)[],'~^~')</literal></entry>
-	<entry><literal>1.10~^~2.20~^~3.30</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>array_upper</function>
-      (<type>anyarray</type>, <type>integer</type>)
-     </literal>
-    </entry>
-	<entry><type>integer</type></entry>
-	<entry>
-     returns upper bound of the requested array dimension, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>array_upper(array_append(ARRAY[1,2,3], 4), 1)</literal></entry>
-	<entry><literal>4</literal></entry>
-       </row>
-       <row>
-	<entry>
-     <literal>
-      <function>string_to_array</function>
-      (<type>text</type>, <type>text</type>)
-     </literal>
-    </entry>
-	<entry><type>text[]</type></entry>
-	<entry>
-     splits string into array elements using provided delimiter, returning
-     <literal>NULL</literal> for <literal>NULL</literal> inputs
-    </entry>
-	<entry><literal>string_to_array('1.10~^~2.20~^~3.30','~^~')::float8[]</literal></entry>
-	<entry><literal>{1.1,2.2,3.3}</literal></entry>
-       </row>
-      </tbody>
-     </tgroup>
-    </table>
-  </sect1>
 
  <sect1 id="functions-aggregate">
   <title>Aggregate Functions</title>
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 9025862be123f6734e65b537207ea2cfd1117ae9..a2160fa0251b0615c460a08071753bf39c4530e3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.57 2003/06/24 23:14:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,16 +50,10 @@ AggregateCreate(const char *aggName,
 	Oid			finalfn = InvalidOid;	/* can be omitted */
 	Oid			finaltype;
 	Oid			fnArgs[FUNC_MAX_ARGS];
-	int			nargs_transfn;
-	int			nargs_finalfn;
+	int			nargs;
 	Oid			procOid;
 	TupleDesc	tupDesc;
 	int			i;
-	Oid			rettype;
-	Oid		   *true_oid_array_transfn;
-	Oid		   *true_oid_array_finalfn;
-	bool		retset;
-	FuncDetailCode fdresult;
 	ObjectAddress myself,
 				referenced;
 
@@ -74,49 +68,24 @@ AggregateCreate(const char *aggName,
 	MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
 	fnArgs[0] = aggTransType;
 	if (aggBaseType == ANYOID)
-		nargs_transfn = 1;
+		nargs = 1;
 	else
 	{
 		fnArgs[1] = aggBaseType;
-		nargs_transfn = 2;
+		nargs = 2;
 	}
-
-	/*
-	 * func_get_detail looks up the function in the catalogs, does
-	 * disambiguation for polymorphic functions, handles inheritance, and
-	 * returns the funcid and type and set or singleton status of the
-	 * function's return value.  it also returns the true argument types
-	 * to the function.
-	 */
-	fdresult = func_get_detail(aggtransfnName, NIL, nargs_transfn, fnArgs,
-							   &transfn, &rettype, &retset,
-							   &true_oid_array_transfn);
-
-	/* only valid case is a normal function */
-	if (fdresult != FUNCDETAIL_NORMAL)
-		func_error("AggregateCreate", aggtransfnName, nargs_transfn, fnArgs, NULL);
-
+	transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
 	if (!OidIsValid(transfn))
-		func_error("AggregateCreate", aggtransfnName, nargs_transfn, fnArgs, NULL);
-
-	/*
-	 * enforce consistency with ANYARRAY and ANYELEMENT argument
-	 * and return types, possibly modifying return type along the way
-	 */
-	rettype = enforce_generic_type_consistency(fnArgs, true_oid_array_transfn,
-													   nargs_transfn, rettype);
-
-	if (rettype != aggTransType)
-		elog(ERROR, "return type of transition function %s is not %s",
-		 NameListToString(aggtransfnName), format_type_be(aggTransType));
-
+		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
 	tup = SearchSysCache(PROCOID,
 						 ObjectIdGetDatum(transfn),
 						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-		func_error("AggregateCreate", aggtransfnName,
-						nargs_transfn, fnArgs, NULL);
+		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
 	proc = (Form_pg_proc) GETSTRUCT(tup);
+	if (proc->prorettype != aggTransType)
+		elog(ERROR, "return type of transition function %s is not %s",
+		 NameListToString(aggtransfnName), format_type_be(aggTransType));
 
 	/*
 	 * If the transfn is strict and the initval is NULL, make sure input
@@ -136,26 +105,17 @@ AggregateCreate(const char *aggName,
 	{
 		MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
 		fnArgs[0] = aggTransType;
-		nargs_finalfn = 1;
-
-		fdresult = func_get_detail(aggfinalfnName, NIL, 1, fnArgs,
-								   &finalfn, &rettype, &retset,
-								   &true_oid_array_finalfn);
-
-		/* only valid case is a normal function */
-		if (fdresult != FUNCDETAIL_NORMAL)
-			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
-
+		finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
 		if (!OidIsValid(finalfn))
 			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
-
-		/*
-		 * enforce consistency with ANYARRAY and ANYELEMENT argument
-		 * and return types, possibly modifying return type along the way
-		 */
-		finaltype = enforce_generic_type_consistency(fnArgs,
-													 true_oid_array_finalfn,
-													 nargs_finalfn, rettype);
+		tup = SearchSysCache(PROCOID,
+							 ObjectIdGetDatum(finalfn),
+							 0, 0, 0);
+		if (!HeapTupleIsValid(tup))
+			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
+		proc = (Form_pg_proc) GETSTRUCT(tup);
+		finaltype = proc->prorettype;
+		ReleaseSysCache(tup);
 	}
 	else
 	{
@@ -166,27 +126,6 @@ AggregateCreate(const char *aggName,
 	}
 	Assert(OidIsValid(finaltype));
 
-	/*
-	 * special disallowed cases:
-	 * 1)	if finaltype is polymorphic, basetype cannot be ANY
-	 * 2)	if finaltype is polymorphic, both args to transfn must be
-	 *		polymorphic
-	 */
-	if (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)
-	{
-		if (aggBaseType == ANYOID)
-			elog(ERROR, "aggregate with base type ANY must have a " \
-						"non-polymorphic return type");
-
-		if (nargs_transfn > 1 && (
-			(true_oid_array_transfn[0] != ANYARRAYOID &&
-			 true_oid_array_transfn[0] != ANYELEMENTOID) ||
-			(true_oid_array_transfn[1] != ANYARRAYOID &&
-			 true_oid_array_transfn[1] != ANYELEMENTOID)))
-			elog(ERROR, "aggregate with polymorphic return type requires " \
-						"state function with both arguments polymorphic");
-	}
-
 	/*
 	 * Everything looks okay.  Try to create the pg_proc entry for the
 	 * aggregate.  (This could fail if there's already a conflicting
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 07b9862e41a56d56deb1e24927c081003600dd24..bee50e686f0446475d7488a2cc66d277264da6d0 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.6 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.7 2003/06/25 21:30:26 momjian Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -119,9 +119,7 @@ DefineAggregate(List *names, List *parameters)
 		baseTypeId = typenameTypeId(baseType);
 
 	transTypeId = typenameTypeId(transType);
-	if (get_typtype(transTypeId) == 'p' &&
-		transTypeId != ANYARRAYOID &&
-		transTypeId != ANYELEMENTOID)
+	if (get_typtype(transTypeId) == 'p')
 		elog(ERROR, "Aggregate transition datatype cannot be %s",
 			 format_type_be(transTypeId));
 
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index e729344060e363c31254c8aaed9467b7208b86cf..6e0a46e0e7fbf696f91a469a5ad7a45b44db00cd 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.131 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.132 2003/06/25 21:30:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1528,17 +1528,17 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 			{
 				/* Check other sub-arrays are compatible */
 				if (elem_ndims != ARR_NDIM(array))
-					elog(ERROR, "Multidimensional arrays must have array "
+					elog(ERROR, "Multiple dimension arrays must have array "
 						 "expressions with matching number of dimensions");
 
 				if (memcmp(elem_dims, ARR_DIMS(array),
 						   elem_ndims * sizeof(int)) != 0)
-					elog(ERROR, "Multidimensional arrays must have array "
+					elog(ERROR, "Multiple dimension arrays must have array "
 						 "expressions with matching dimensions");
 
 				if (memcmp(elem_lbs, ARR_LBOUND(array),
 						   elem_ndims * sizeof(int)) != 0)
-					elog(ERROR, "Multidimensional arrays must have array "
+					elog(ERROR, "Multiple dimension arrays must have array "
 						 "expressions with matching dimensions");
 			}
 
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index dc8c1554bb0f5e3d725352ca015ce718e4ac680c..04d656f05a93b1f034ac73a252a05bec146c5047 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.108 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.109 2003/06/25 21:30:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,7 +58,6 @@
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
-#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
@@ -213,7 +212,7 @@ static TupleTableSlot *agg_retrieve_direct(AggState *aggstate);
 static void agg_fill_hash_table(AggState *aggstate);
 static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
 static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
-static Oid resolve_type(Oid type_to_resolve, Oid context_type);
+
 
 /*
  * Initialize all aggregates for a new group of input values.
@@ -352,12 +351,14 @@ advance_transition_function(AggState *aggstate,
 	fcinfo.context = NULL;
 	fcinfo.resultinfo = NULL;
 	fcinfo.isnull = false;
+
 	fcinfo.flinfo = &peraggstate->transfn;
 	fcinfo.nargs = 2;
 	fcinfo.arg[0] = pergroupstate->transValue;
 	fcinfo.argnull[0] = pergroupstate->transValueIsNull;
 	fcinfo.arg[1] = newVal;
 	fcinfo.argnull[1] = isNull;
+
 	newVal = FunctionCallInvoke(&fcinfo);
 
 	/*
@@ -1186,21 +1187,7 @@ ExecInitAgg(Agg *node, EState *estate)
 		AclResult	aclresult;
 		Oid			transfn_oid,
 					finalfn_oid;
-		FuncExpr   *transfnexpr,
-				   *finalfnexpr;
 		Datum		textInitVal;
-		List	   *fargs;
-		Oid			agg_rt_type;
-		Oid		   *transfn_arg_types;
-		List	   *transfn_args = NIL;
-		int			transfn_nargs;
-		Oid			transfn_ret_type;
-		Oid		   *finalfn_arg_types = NULL;
-		List	   *finalfn_args = NIL;
-		Oid			finalfn_ret_type = InvalidOid;
-		int			finalfn_nargs = 0;
-		Node	   *arg0;
-		Node	   *arg1;
 		int			i;
 
 		/* Planner should have assigned aggregate to correct level */
@@ -1251,166 +1238,6 @@ ExecInitAgg(Agg *node, EState *estate)
 						&peraggstate->transtypeLen,
 						&peraggstate->transtypeByVal);
 
-		peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
-		peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
-
-		/* get the runtime aggregate argument type */
-		fargs = aggref->args;
-		agg_rt_type = exprType((Node *) nth(0, fargs));
-
-		/* get the transition function argument and return types */
-		transfn_ret_type = get_func_rettype(transfn_oid);
-		transfn_arg_types = get_func_argtypes(transfn_oid, &transfn_nargs);
-
-		/* resolve any polymorphic types */
-		if (transfn_nargs == 2)
-		/* base type was not ANY */
-		{
-			if (transfn_arg_types[1] == ANYARRAYOID ||
-				transfn_arg_types[1] == ANYELEMENTOID)
-				transfn_arg_types[1] = agg_rt_type;
-
-			transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
-														agg_rt_type);
-
-			/*
-			 * Build arg list to use on the transfn FuncExpr node. We really
-			 * only care that the node type is correct so that the transfn
-			 * can discover the actual argument types at runtime using 
-			 * get_fn_expr_argtype()
-			 */
-			arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
-															-1, COERCE_DONTCARE);
-			arg1 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[1],
-															-1, COERCE_DONTCARE);
-			transfn_args = makeList2(arg0, arg1);
-
-			/*
-			 * the state transition function always returns the same type
-			 * as its first argument
-			 */
-			if (transfn_ret_type == ANYARRAYOID ||
-				transfn_ret_type == ANYELEMENTOID)
-				transfn_ret_type = transfn_arg_types[0];
-		}
-		else if (transfn_nargs == 1)
-		/*
-		 * base type was ANY, therefore the aggregate return type should
-		 * be non-polymorphic
-		 */
-		{
-			Oid	finaltype = get_func_rettype(aggref->aggfnoid);
-
-			/*
-			 * this should have been prevented in AggregateCreate,
-			 * but check anyway
-			 */
-			if (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)
-				elog(ERROR, "aggregate with base type ANY must have a " \
-							"non-polymorphic return type");
-
-			/* see if we have a final function */
-			if (OidIsValid(finalfn_oid))
-			{
-				finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
-				if (finalfn_nargs != 1)
-					elog(ERROR, "final function takes unexpected number " \
-								"of arguments: %d", finalfn_nargs);
-
-				/*
-				 * final function argument is always the same as the state
-				 * function return type
-				 */
-				if (finalfn_arg_types[0] != ANYARRAYOID &&
-					finalfn_arg_types[0] != ANYELEMENTOID)
-				{
-					/* if it is not ambiguous, use it */
-					transfn_ret_type = finalfn_arg_types[0];
-				}
-				else
-				{
-					/* if it is ambiguous, try to derive it */
-					finalfn_ret_type = finaltype;
-					finalfn_arg_types[0] = resolve_type(finalfn_arg_types[0],
-															finalfn_ret_type);
-					transfn_ret_type = finalfn_arg_types[0];
-				}
-			}
-			else
-				transfn_ret_type = finaltype;
-
-			transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
-														transfn_ret_type);
-
-			/*
-			 * Build arg list to use on the transfn FuncExpr node. We really
-			 * only care that the node type is correct so that the transfn
-			 * can discover the actual argument types at runtime using 
-			 * get_fn_expr_argtype()
-			 */
-			arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
-															-1, COERCE_DONTCARE);
-			transfn_args = makeList1(arg0);
-		}
-		else
-			elog(ERROR, "state transition function takes unexpected number " \
-						"of arguments: %d", transfn_nargs);
-
-		if (OidIsValid(finalfn_oid))
-		{
-			/* get the final function argument and return types */
-			if (finalfn_ret_type == InvalidOid)
-				finalfn_ret_type = get_func_rettype(finalfn_oid);
-
-			if (!finalfn_arg_types)
-			{
-				finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
-				if (finalfn_nargs != 1)
-					elog(ERROR, "final function takes unexpected number " \
-								"of arguments: %d", finalfn_nargs);
-			}
-
-			/*
-			 * final function argument is always the same as the state
-			 * function return type, which by now should have been resolved
-			 */
-			if (finalfn_arg_types[0] == ANYARRAYOID ||
-				finalfn_arg_types[0] == ANYELEMENTOID)
-				finalfn_arg_types[0] = transfn_ret_type;
-
-			/*
-			 * Build arg list to use on the finalfn FuncExpr node. We really
-			 * only care that the node type is correct so that the finalfn
-			 * can discover the actual argument type at runtime using 
-			 * get_fn_expr_argtype()
-			 */
-			arg0 = (Node *) makeRelabelType((Expr *) NULL, finalfn_arg_types[0],
-															-1, COERCE_DONTCARE);
-			finalfn_args = makeList1(arg0);
-
-			finalfn_ret_type = resolve_type(finalfn_ret_type,
-												finalfn_arg_types[0]);
-		}
-
-		fmgr_info(transfn_oid, &peraggstate->transfn);
-		transfnexpr = (FuncExpr *) make_funcclause(transfn_oid,
-						  transfn_ret_type,
-						  false,			/* cannot be a set */
-						  COERCE_DONTCARE,	/* to match any user expr */
-						  transfn_args);
-		peraggstate->transfn.fn_expr = (Node *) transfnexpr;
-
-		if (OidIsValid(finalfn_oid))
-		{
-			fmgr_info(finalfn_oid, &peraggstate->finalfn);
-			finalfnexpr = (FuncExpr *) make_funcclause(finalfn_oid,
-						  finalfn_ret_type,
-						  false,			/* cannot be a set */
-						  COERCE_DONTCARE,	/* to match any user expr */
-						  finalfn_args);
-			peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
-		}
-
 		/*
 		 * initval is potentially null, so don't try to access it as a
 		 * struct field. Must do it the hard way with SysCacheGetAttr.
@@ -1423,7 +1250,14 @@ ExecInitAgg(Agg *node, EState *estate)
 			peraggstate->initValue = (Datum) 0;
 		else
 			peraggstate->initValue = GetAggInitVal(textInitVal,
-												   transfn_arg_types[0]);
+												   aggform->aggtranstype);
+
+		peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
+		peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
+
+		fmgr_info(transfn_oid, &peraggstate->transfn);
+		if (OidIsValid(finalfn_oid))
+			fmgr_info(finalfn_oid, &peraggstate->finalfn);
 
 		/*
 		 * If the transfn is strict and the initval is NULL, make sure
@@ -1635,36 +1469,3 @@ aggregate_dummy(PG_FUNCTION_ARGS)
 		 fcinfo->flinfo->fn_oid);
 	return (Datum) 0;			/* keep compiler quiet */
 }
-
-static Oid
-resolve_type(Oid type_to_resolve, Oid context_type)
-{
-	Oid		resolved_type;
-
-	if (context_type == ANYARRAYOID || context_type == ANYELEMENTOID)
-		resolved_type = type_to_resolve;
-	else if (type_to_resolve == ANYARRAYOID)
-	/* any array */
-	{
-		Oid		context_type_arraytype = get_array_type(context_type);
-
-		if (context_type_arraytype != InvalidOid)
-			resolved_type = context_type_arraytype;
-		else
-			resolved_type = context_type;
-	}
-	else if (type_to_resolve == ANYELEMENTOID)
-	/* any element */
-	{
-		Oid		context_type_elemtype = get_element_type(context_type);
-
-		if (context_type_elemtype != InvalidOid)
-			resolved_type = context_type_elemtype;
-		else
-			resolved_type = context_type;
-	}
-	else
-		resolved_type = type_to_resolve;
-
-	return resolved_type;
-}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 62aaa7e8d439cdd3eee4cd9f1ef010a00b5bbe37..645673776841b340b941dcc4bf8a49b1063daca3 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.48 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.49 2003/06/25 21:30:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,23 @@
 #include "utils/datum.h"
 #include "utils/lsyscache.h"
 
+
+typedef struct ArrayBuildState
+{
+	MemoryContext mcontext;		/* where all the temp stuff is kept */
+	Datum	   *dvalues;		/* array of accumulated Datums */
+	/*
+	 * The allocated size of dvalues[] is always a multiple of
+	 * ARRAY_ELEMS_CHUNKSIZE
+	 */
+#define ARRAY_ELEMS_CHUNKSIZE	64
+	int			nelems;			/* number of valid Datums in dvalues[] */
+	Oid			element_type;	/* data type of the Datums */
+	int16		typlen;			/* needed info about datatype */
+	bool		typbyval;
+	char		typalign;
+} ArrayBuildState;
+
 static Datum ExecHashSubPlan(SubPlanState *node,
 							 ExprContext *econtext,
 							 bool *isNull);
@@ -37,6 +54,13 @@ static Datum ExecScanSubPlan(SubPlanState *node,
 static void buildSubPlanHash(SubPlanState *node);
 static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
 static bool tupleAllNulls(HeapTuple tuple);
+static ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
+										 Datum dvalue, bool disnull,
+										 Oid element_type,
+										 MemoryContext rcontext);
+static Datum makeArrayResult(ArrayBuildState *astate,
+							 MemoryContext rcontext);
+
 
 /* ----------------------------------------------------------------
  *		ExecSubPlan
@@ -200,7 +224,6 @@ ExecScanSubPlan(SubPlanState *node,
 	PlanState  *planstate = node->planstate;
 	SubLinkType subLinkType = subplan->subLinkType;
 	bool		useOr = subplan->useOr;
-	bool		isExpr = subplan->isExpr;
 	MemoryContext oldcontext;
 	TupleTableSlot *slot;
 	Datum		result;
@@ -271,11 +294,6 @@ ExecScanSubPlan(SubPlanState *node,
 		bool		rownull = false;
 		int			col = 1;
 		List	   *plst;
-		int			numelems;
-		int			elemnum;
-		Datum		dvalue;
-		Datum	   *dvalues = NULL;
-		bool		disnull;
 
 		if (subLinkType == EXISTS_SUBLINK)
 		{
@@ -313,6 +331,9 @@ ExecScanSubPlan(SubPlanState *node,
 
 		if (subLinkType == ARRAY_SUBLINK)
 		{
+			Datum	dvalue;
+			bool	disnull;
+
 			found = true;
 			/* stash away current value */
 			dvalue = heap_getattr(tup, 1, tdesc, &disnull);
@@ -330,164 +351,99 @@ ExecScanSubPlan(SubPlanState *node,
 		found = true;
 
 		/*
-		 * When isExpr is true, we have either a scalar expression or an
-		 * array. In the former case, this is no different than the !isExpr
-		 * case. In the latter case, iterate over the elements as if they
-		 * were from multiple input tuples.
+		 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
+		 * operators for columns of tuple.
 		 */
-		if (!isExpr)
-			numelems = 1;
-		else
+		plst = subplan->paramIds;
+		foreach(lst, node->exprs)
 		{
-			Oid		expr_typeid = tdesc->attrs[0]->atttypid;
+			ExprState  *exprstate = (ExprState *) lfirst(lst);
+			int			paramid = lfirsti(plst);
+			ParamExecData *prmdata;
+			Datum		expresult;
+			bool		expnull;
 
-			if (expr_typeid != subplan->exprtype)
-			{
-				subplan->exprtype = expr_typeid;
-				subplan->elemtype = get_element_type(expr_typeid);
-
-				if (subplan->elemtype != InvalidOid)
-					get_typlenbyvalalign(subplan->elemtype,
-										 &subplan->elmlen,
-										 &subplan->elmbyval,
-										 &subplan->elmalign);
-			}
+			/*
+			 * Load up the Param representing this column of the sub-select.
+			 */
+			prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
+			Assert(prmdata->execPlan == NULL);
+			prmdata->value = heap_getattr(tup, col, tdesc,
+										  &(prmdata->isnull));
 
-			/* get current value */
-			dvalue = heap_getattr(tup, 1, tdesc, &disnull);
+			/*
+			 * Now we can eval the combining operator for this column.
+			 */
+			expresult = ExecEvalExprSwitchContext(exprstate, econtext,
+												  &expnull, NULL);
 
-			/* XXX this will need work if/when arrays support NULL elements */
-			if (!disnull)
+			/*
+			 * Combine the result into the row result as appropriate.
+			 */
+			if (col == 1)
 			{
-				if (subplan->elemtype != InvalidOid)
-				{
-					ArrayType   *v = DatumGetArrayTypeP(dvalue);
-
-					deconstruct_array(v, subplan->elemtype, subplan->elmlen,
-									  subplan->elmbyval, subplan->elmalign,
-					  				  &dvalues, &numelems);
-				}
-				else
+				rowresult = expresult;
+				rownull = expnull;
+			}
+			else if (useOr)
+			{
+				/* combine within row per OR semantics */
+				if (expnull)
+					rownull = true;
+				else if (DatumGetBool(expresult))
 				{
-					numelems = 1;
-					dvalues = (Datum *) palloc(numelems * sizeof(Datum));
-					dvalues[0] = dvalue;
+					rowresult = BoolGetDatum(true);
+					rownull = false;
+					break;		/* needn't look at any more columns */
 				}
 			}
 			else
 			{
-				numelems = 1;
-				dvalues = (Datum *) palloc(numelems * sizeof(Datum));
-				dvalues[0] = (Datum) 0;
+				/* combine within row per AND semantics */
+				if (expnull)
+					rownull = true;
+				else if (!DatumGetBool(expresult))
+				{
+					rowresult = BoolGetDatum(false);
+					rownull = false;
+					break;		/* needn't look at any more columns */
+				}
 			}
 
+			plst = lnext(plst);
+			col++;
 		}
 
-		for (elemnum = 0; elemnum < numelems; elemnum++)
+		if (subLinkType == ANY_SUBLINK)
 		{
-			/*
-			 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
-			 * operators for columns of tuple.
-			 */
-			col = 1;
-			plst = subplan->paramIds;
-			foreach(lst, node->exprs)
+			/* combine across rows per OR semantics */
+			if (rownull)
+				*isNull = true;
+			else if (DatumGetBool(rowresult))
 			{
-				ExprState  *exprstate = (ExprState *) lfirst(lst);
-				int			paramid = lfirsti(plst);
-				ParamExecData *prmdata;
-				Datum		expresult;
-				bool		expnull;
-
-				/*
-				 * Load up the Param representing this column of the sub-select.
-				 */
-				prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
-				Assert(prmdata->execPlan == NULL);
-
-				if (!isExpr)
-					prmdata->value = heap_getattr(tup, col, tdesc,
-												  &(prmdata->isnull));
-				else
-				{
-					prmdata->value = dvalues[elemnum];
-					prmdata->isnull = disnull;
-				}
-
-				/*
-				 * Now we can eval the combining operator for this column.
-				 */
-				expresult = ExecEvalExprSwitchContext(exprstate, econtext,
-													  &expnull, NULL);
-
-				/*
-				 * Combine the result into the row result as appropriate.
-				 */
-				if (col == 1)
-				{
-					rowresult = expresult;
-					rownull = expnull;
-				}
-				else if (useOr)
-				{
-					/* combine within row per OR semantics */
-					if (expnull)
-						rownull = true;
-					else if (DatumGetBool(expresult))
-					{
-						rowresult = BoolGetDatum(true);
-						rownull = false;
-						break;		/* needn't look at any more columns */
-					}
-				}
-				else
-				{
-					/* combine within row per AND semantics */
-					if (expnull)
-						rownull = true;
-					else if (!DatumGetBool(expresult))
-					{
-						rowresult = BoolGetDatum(false);
-						rownull = false;
-						break;		/* needn't look at any more columns */
-					}
-				}
-
-				plst = lnext(plst);
-				col++;
-			}
-
-			if (subLinkType == ANY_SUBLINK)
-			{
-				/* combine across rows per OR semantics */
-				if (rownull)
-					*isNull = true;
-				else if (DatumGetBool(rowresult))
-				{
-					result = BoolGetDatum(true);
-					*isNull = false;
-					break;			/* needn't look at any more rows */
-				}
-			}
-			else if (subLinkType == ALL_SUBLINK)
-			{
-				/* combine across rows per AND semantics */
-				if (rownull)
-					*isNull = true;
-				else if (!DatumGetBool(rowresult))
-				{
-					result = BoolGetDatum(false);
-					*isNull = false;
-					break;			/* needn't look at any more rows */
-				}
+				result = BoolGetDatum(true);
+				*isNull = false;
+				break;			/* needn't look at any more rows */
 			}
-			else
+		}
+		else if (subLinkType == ALL_SUBLINK)
+		{
+			/* combine across rows per AND semantics */
+			if (rownull)
+				*isNull = true;
+			else if (!DatumGetBool(rowresult))
 			{
-				/* must be MULTIEXPR_SUBLINK */
-				result = rowresult;
-				*isNull = rownull;
+				result = BoolGetDatum(false);
+				*isNull = false;
+				break;			/* needn't look at any more rows */
 			}
 		}
+		else
+		{
+			/* must be MULTIEXPR_SUBLINK */
+			result = rowresult;
+			*isNull = rownull;
+		}
 	}
 
 	if (!found)
@@ -524,7 +480,6 @@ static void
 buildSubPlanHash(SubPlanState *node)
 {
 	SubPlan	   *subplan = (SubPlan *) node->xprstate.expr;
-	bool		isExpr = subplan->isExpr;
 	PlanState  *planstate = node->planstate;
 	int			ncols = length(node->exprs);
 	ExprContext *innerecontext = node->innerecontext;
@@ -532,7 +487,6 @@ buildSubPlanHash(SubPlanState *node)
 	MemoryContext oldcontext;
 	int			nbuckets;
 	TupleTableSlot *slot;
-	TupleTableSlot *arrslot = NULL;
 
 	Assert(subplan->subLinkType == ANY_SUBLINK);
 	Assert(!subplan->useOr);
@@ -612,139 +566,43 @@ buildSubPlanHash(SubPlanState *node)
 	{
 		HeapTuple	tup = slot->val;
 		TupleDesc	tdesc = slot->ttc_tupleDescriptor;
-		TupleDesc	arrtdesc = NULL;
+		int			col = 1;
 		List	   *plst;
 		bool		isnew;
-		int			numelems;
-		int			elemnum;
-		Datum		dvalue;
-		Datum	   *dvalues = NULL;
-		bool		disnull;
 
 		/*
-		 * When isExpr is true, we have either a scalar expression or an
-		 * array. In the former case, this is no different than the !isExpr
-		 * case. In the latter case, iterate over the elements as if they
-		 * were from multiple input tuples.
+		 * Load up the Params representing the raw sub-select outputs,
+		 * then form the projection tuple to store in the hashtable.
 		 */
-		if (!isExpr)
-			numelems = 1;
-		else
+		foreach(plst, subplan->paramIds)
 		{
-			Oid		expr_typeid = tdesc->attrs[0]->atttypid;
-
-			if (expr_typeid != subplan->exprtype)
-			{
-				subplan->exprtype = expr_typeid;
-				subplan->elemtype = get_element_type(expr_typeid);
-
-				if (subplan->elemtype != InvalidOid)
-					get_typlenbyvalalign(subplan->elemtype,
-										 &subplan->elmlen,
-										 &subplan->elmbyval,
-										 &subplan->elmalign);
-			}
-
-			/* get current value */
-			dvalue = heap_getattr(tup, 1, tdesc, &disnull);
-
-			if (subplan->elemtype != InvalidOid)
-			{
-				TupleTable	tupleTable;
-				ArrayType   *v = DatumGetArrayTypeP(dvalue);
-
-				arrtdesc = CreateTemplateTupleDesc(1, false);
-				TupleDescInitEntry(arrtdesc, 1, "elem", subplan->elemtype,
-															-1, 0, false);
-
-				tupleTable = ExecCreateTupleTable(1);
-				arrslot = ExecAllocTableSlot(tupleTable);
-				ExecSetSlotDescriptor(arrslot, arrtdesc, true);
-
-				/* XXX this will need work if/when arrays support NULL elements */
-				if (!disnull)
-				{
-					deconstruct_array(v, subplan->elemtype, subplan->elmlen,
-									  subplan->elmbyval, subplan->elmalign,
-					  				  &dvalues, &numelems);
-				}
-				else
-				{
-					numelems = 1;
-					dvalues = (Datum *) palloc(numelems * sizeof(Datum));
-					dvalues[0] = (Datum) 0;
-				}
-			}
-			else
-			{
-				numelems = 1;
-				dvalues = (Datum *) palloc(numelems * sizeof(Datum));
-				dvalues[0] = dvalue;
-			}
-
+			int			paramid = lfirsti(plst);
+			ParamExecData *prmdata;
+
+			prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
+			Assert(prmdata->execPlan == NULL);
+			prmdata->value = heap_getattr(tup, col, tdesc,
+										  &(prmdata->isnull));
+			col++;
 		}
+		slot = ExecProject(node->projRight, NULL);
+		tup = slot->val;
 
-		for (elemnum = 0; elemnum < numelems; elemnum++)
+		/*
+		 * If result contains any nulls, store separately or not at all.
+		 * (Since we know the projection tuple has no junk columns, we
+		 * can just look at the overall hasnull info bit, instead of
+		 * groveling through the columns.)
+		 */
+		if (HeapTupleNoNulls(tup))
 		{
-			int	col = 1;
-
-			if (!isExpr || subplan->elemtype == InvalidOid)
-			{
-				/*
-				 * Load up the Params representing the raw sub-select outputs,
-				 * then form the projection tuple to store in the hashtable.
-				 */
-				foreach(plst, subplan->paramIds)
-				{
-					int			paramid = lfirsti(plst);
-					ParamExecData *prmdata;
-
-					prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
-					Assert(prmdata->execPlan == NULL);
-
-					prmdata->value = heap_getattr(tup, col, tdesc,
-												  &(prmdata->isnull));
-
-					col++;
-				}
-				slot = ExecProject(node->projRight, NULL);
-				tup = slot->val;
-			}
-			else
-			{
-				/*
-				 * For array type expressions, we need to build up our own
-				 * tuple and slot
-				 */
-				char		nullflag;
-
-				nullflag = disnull ? 'n' : ' ';
-				tup = heap_formtuple(arrtdesc, &dvalues[elemnum], &nullflag);
-				arrslot = ExecStoreTuple(tup, arrslot, InvalidBuffer, true);
-			}
-
-			/*
-			 * If result contains any nulls, store separately or not at all.
-			 * (Since we know the projection tuple has no junk columns, we
-			 * can just look at the overall hasnull info bit, instead of
-			 * groveling through the columns.)
-			 */
-			if (HeapTupleNoNulls(tup))
-			{
-				if (!isExpr)
-					(void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
-				else
-					(void) LookupTupleHashEntry(node->hashtable, arrslot, &isnew);
-				node->havehashrows = true;
-			}
-			else if (node->hashnulls)
-			{
-				if (!isExpr)
-					(void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
-				else
-					(void) LookupTupleHashEntry(node->hashnulls, arrslot, &isnew);
-				node->havenullrows = true;
-			}
+			(void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
+			node->havehashrows = true;
+		}
+		else if (node->hashnulls)
+		{
+			(void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
+			node->havenullrows = true;
 		}
 
 		/*
@@ -761,8 +619,6 @@ buildSubPlanHash(SubPlanState *node)
 	 * have the potential for a double free attempt.
 	 */
 	ExecClearTuple(node->projRight->pi_slot);
-	if (arrslot)
-		ExecClearTuple(arrslot);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -1243,3 +1099,101 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
 		parent->chgParam = bms_add_member(parent->chgParam, paramid);
 	}
 }
+
+/*
+ * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
+ *
+ *	astate is working state (NULL on first call)
+ *	rcontext is where to keep working state
+ */
+static ArrayBuildState *
+accumArrayResult(ArrayBuildState *astate,
+				 Datum dvalue, bool disnull,
+				 Oid element_type,
+				 MemoryContext rcontext)
+{
+	MemoryContext arr_context,
+				  oldcontext;
+
+	if (astate == NULL)
+	{
+		/* First time through --- initialize */
+
+		/* Make a temporary context to hold all the junk */
+		arr_context = AllocSetContextCreate(rcontext,
+											"ARRAY_SUBLINK Result",
+											ALLOCSET_DEFAULT_MINSIZE,
+											ALLOCSET_DEFAULT_INITSIZE,
+											ALLOCSET_DEFAULT_MAXSIZE);
+		oldcontext = MemoryContextSwitchTo(arr_context);
+		astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
+		astate->mcontext = arr_context;
+		astate->dvalues = (Datum *)
+			palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
+		astate->nelems = 0;
+		astate->element_type = element_type;
+		get_typlenbyvalalign(element_type,
+							 &astate->typlen,
+							 &astate->typbyval,
+							 &astate->typalign);
+	}
+	else
+	{
+		oldcontext = MemoryContextSwitchTo(astate->mcontext);
+		Assert(astate->element_type == element_type);
+		/* enlarge dvalues[] if needed */
+		if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
+			astate->dvalues = (Datum *)
+				repalloc(astate->dvalues,
+						 (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
+	}
+
+	if (disnull)
+		elog(ERROR, "NULL elements not allowed in Arrays");
+
+	/* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
+	astate->dvalues[astate->nelems++] =
+		datumCopy(dvalue, astate->typbyval, astate->typlen);
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return astate;
+}
+
+/*
+ * makeArrayResult - produce final result of ARRAY_SUBLINK
+ *
+ *	astate is working state (not NULL)
+ *	rcontext is where to construct result
+ */
+static Datum
+makeArrayResult(ArrayBuildState *astate,
+				MemoryContext rcontext)
+{
+	ArrayType  *result;
+	int			dims[1];
+	int			lbs[1];
+	MemoryContext oldcontext;
+
+	/* Build the final array result in rcontext */
+	oldcontext = MemoryContextSwitchTo(rcontext);
+
+	dims[0] = astate->nelems;
+	lbs[0] = 1;
+
+	result = construct_md_array(astate->dvalues,
+								1,
+								dims,
+								lbs,
+								astate->element_type,
+								astate->typlen,
+								astate->typbyval,
+								astate->typalign);
+
+	MemoryContextSwitchTo(oldcontext);
+
+	/* Clean up all the junk */
+	MemoryContextDelete(astate->mcontext);
+
+	return PointerGetDatum(result);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 0cd199656c029ff44882db3e6dc4b6f5311aa04d..8f81f1953c7dc786eba9c5bddd172b9edd6e6aed 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.255 2003/06/25 04:19:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.256 2003/06/25 21:30:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -728,7 +728,6 @@ _copyAggref(Aggref *from)
 	COPY_SCALAR_FIELD(agglevelsup);
 	COPY_SCALAR_FIELD(aggstar);
 	COPY_SCALAR_FIELD(aggdistinct);
-	COPY_NODE_FIELD(args);
 
 	return newnode;
 }
@@ -827,7 +826,6 @@ _copySubLink(SubLink *from)
 
 	COPY_SCALAR_FIELD(subLinkType);
 	COPY_SCALAR_FIELD(useOr);
-	COPY_SCALAR_FIELD(isExpr);
 	COPY_NODE_FIELD(lefthand);
 	COPY_NODE_FIELD(operName);
 	COPY_OIDLIST_FIELD(operOids);
@@ -846,12 +844,6 @@ _copySubPlan(SubPlan *from)
 
 	COPY_SCALAR_FIELD(subLinkType);
 	COPY_SCALAR_FIELD(useOr);
-	COPY_SCALAR_FIELD(isExpr);
-	COPY_SCALAR_FIELD(exprtype);
-	COPY_SCALAR_FIELD(elemtype);
-	COPY_SCALAR_FIELD(elmlen);
-	COPY_SCALAR_FIELD(elmbyval);
-	COPY_SCALAR_FIELD(elmalign);
 	COPY_NODE_FIELD(exprs);
 	COPY_INTLIST_FIELD(paramIds);
 	COPY_NODE_FIELD(plan);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 93f63c586c662b7c317c76efbdfa6b2ac8ff2a30..a56b01429e001b6e56f3a4736f1a84b4b77242d2 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.198 2003/06/25 04:19:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.199 2003/06/25 21:30:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -205,7 +205,6 @@ _equalAggref(Aggref *a, Aggref *b)
 	COMPARE_SCALAR_FIELD(agglevelsup);
 	COMPARE_SCALAR_FIELD(aggstar);
 	COMPARE_SCALAR_FIELD(aggdistinct);
-	COMPARE_NODE_FIELD(args);
 
 	return true;
 }
@@ -302,7 +301,6 @@ _equalSubLink(SubLink *a, SubLink *b)
 {
 	COMPARE_SCALAR_FIELD(subLinkType);
 	COMPARE_SCALAR_FIELD(useOr);
-	COMPARE_SCALAR_FIELD(isExpr);
 	COMPARE_NODE_FIELD(lefthand);
 	COMPARE_NODE_FIELD(operName);
 	COMPARE_OIDLIST_FIELD(operOids);
@@ -316,12 +314,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
 {
 	COMPARE_SCALAR_FIELD(subLinkType);
 	COMPARE_SCALAR_FIELD(useOr);
-	COMPARE_SCALAR_FIELD(isExpr);
-	COMPARE_SCALAR_FIELD(exprtype);
-	COMPARE_SCALAR_FIELD(elemtype);
-	COMPARE_SCALAR_FIELD(elmlen);
-	COMPARE_SCALAR_FIELD(elmbyval);
-	COMPARE_SCALAR_FIELD(elmalign);
 	COMPARE_NODE_FIELD(exprs);
 	COMPARE_INTLIST_FIELD(paramIds);
 	/* should compare plans, but have to settle for comparing plan IDs */
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index cbd5784f563e92ba8c16c0aea00fb8ccb0f1cd8a..e2b8cb789d95f1320e9cb7c5933bd1acf1558beb 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.209 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.210 2003/06/25 21:30:29 momjian Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -616,7 +616,6 @@ _outAggref(StringInfo str, Aggref *node)
 	WRITE_UINT_FIELD(agglevelsup);
 	WRITE_BOOL_FIELD(aggstar);
 	WRITE_BOOL_FIELD(aggdistinct);
-	WRITE_NODE_FIELD(args);
 }
 
 static void
@@ -702,7 +701,6 @@ _outSubLink(StringInfo str, SubLink *node)
 
 	WRITE_ENUM_FIELD(subLinkType, SubLinkType);
 	WRITE_BOOL_FIELD(useOr);
-	WRITE_BOOL_FIELD(isExpr);
 	WRITE_NODE_FIELD(lefthand);
 	WRITE_NODE_FIELD(operName);
 	WRITE_OIDLIST_FIELD(operOids);
@@ -716,12 +714,6 @@ _outSubPlan(StringInfo str, SubPlan *node)
 
 	WRITE_ENUM_FIELD(subLinkType, SubLinkType);
 	WRITE_BOOL_FIELD(useOr);
-	WRITE_BOOL_FIELD(isExpr);
-	WRITE_OID_FIELD(exprtype);
-	WRITE_OID_FIELD(elemtype);
-	WRITE_INT_FIELD(elmlen);
-	WRITE_BOOL_FIELD(elmbyval);
-	WRITE_CHAR_FIELD(elmalign);
 	WRITE_NODE_FIELD(exprs);
 	WRITE_INTLIST_FIELD(paramIds);
 	WRITE_NODE_FIELD(plan);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index a661f9e8ad1776bf9d99ad7a3d0b6f2cef533bd1..1d2db3b37a9d3672e0bd16a3d0f68d07df9ad44b 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.155 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.156 2003/06/25 21:30:30 momjian Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -416,7 +416,6 @@ _readAggref(void)
 	READ_UINT_FIELD(agglevelsup);
 	READ_BOOL_FIELD(aggstar);
 	READ_BOOL_FIELD(aggdistinct);
-	READ_NODE_FIELD(args);
 
 	READ_DONE();
 }
@@ -546,7 +545,6 @@ _readSubLink(void)
 
 	READ_ENUM_FIELD(subLinkType, SubLinkType);
 	READ_BOOL_FIELD(useOr);
-	READ_BOOL_FIELD(isExpr);
 	READ_NODE_FIELD(lefthand);
 	READ_NODE_FIELD(operName);
 	READ_OIDLIST_FIELD(operOids);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 138e7d80638ce1d80c7bfaa2ac5fb5d96fc931d8..aee5f4a1a145ef4ddcf4a18d87babece8a6b1ec6 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.77 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.78 2003/06/25 21:30:30 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,7 +83,7 @@ typedef struct finalize_primnode_context
 
 static List *convert_sublink_opers(List *lefthand, List *operOids,
 								   List *targetlist, int rtindex,
-								   bool isExpr, List **righthandIds);
+								   List **righthandIds);
 static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
 static Node *replace_correlation_vars_mutator(Node *node, void *context);
 static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
@@ -299,12 +299,6 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 	 */
 	node->subLinkType = slink->subLinkType;
 	node->useOr = slink->useOr;
-	node->isExpr = slink->isExpr;
-	node->exprtype = InvalidOid;
-	node->elemtype = InvalidOid;
-	node->elmlen = 0;
-	node->elmbyval = false;
-	node->elmalign = '\0';
 	node->exprs = NIL;
 	node->paramIds = NIL;
 	node->useHashTable = false;
@@ -380,7 +374,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 		exprs = convert_sublink_opers(lefthand,
 									  slink->operOids,
 									  plan->targetlist,
-									  0, node->isExpr,
+									  0,
 									  &node->paramIds);
 		node->setParam = listCopy(node->paramIds);
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
@@ -463,7 +457,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 		node->exprs = convert_sublink_opers(lefthand,
 											slink->operOids,
 											plan->targetlist,
-											0, node->isExpr,
+											0,
 											&node->paramIds);
 
 		/*
@@ -505,7 +499,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 static List *
 convert_sublink_opers(List *lefthand, List *operOids,
 					  List *targetlist, int rtindex,
-					  bool isExpr, List **righthandIds)
+					  List **righthandIds)
 {
 	List	   *result = NIL;
 	List	   *lst;
@@ -560,38 +554,13 @@ convert_sublink_opers(List *lefthand, List *operOids,
 		 * are not expecting to have to resolve unknown Params, so
 		 * it's okay to pass a null pstate.)
 		 */
-		if (!isExpr)
-		{
-			result = lappend(result,
-							 make_op_expr(NULL,
-										  tup,
-										  leftop,
-										  rightop,
-										  exprType(leftop),
-										  te->resdom->restype));
-		}
-		else
-		{
-			Oid		exprtype = te->resdom->restype;
-			Oid		elemtype = get_element_type(exprtype);
-
-			if (elemtype != InvalidOid)
-				result = lappend(result,
-								 make_op_expr(NULL,
-											  tup,
-											  leftop,
-											  rightop,
-											  exprType(leftop),
-											  elemtype));
-			else
-				result = lappend(result,
-								 make_op_expr(NULL,
-											  tup,
-											  leftop,
-											  rightop,
-											  exprType(leftop),
-											  exprtype));
-		}
+		result = lappend(result,
+						 make_op_expr(NULL,
+									  tup,
+									  leftop,
+									  rightop,
+									  exprType(leftop),
+									  te->resdom->restype));
 
 		ReleaseSysCache(tup);
 
@@ -702,17 +671,13 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
 	/*
 	 * The sublink type must be "= ANY" --- that is, an IN operator.
 	 * (We require the operator name to be unqualified, which may be
-	 * overly paranoid, or may not be.) It must not be an Expression
-	 * sublink.
+	 * overly paranoid, or may not be.)
 	 */
 	if (sublink->subLinkType != ANY_SUBLINK)
 		return NULL;
 	if (length(sublink->operName) != 1 ||
 		strcmp(strVal(lfirst(sublink->operName)), "=") != 0)
 		return NULL;
-	if (sublink->isExpr)
-		return NULL;
-
 	/*
 	 * The sub-select must not refer to any Vars of the parent query.
 	 * (Vars of higher levels should be okay, though.)
@@ -765,7 +730,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
 	exprs = convert_sublink_opers(sublink->lefthand,
 								  sublink->operOids,
 								  subselect->targetList,
-								  rtindex, sublink->isExpr,
+								  rtindex,
 								  &ininfo->sub_targetlist);
 	return (Node *) make_ands_explicit(exprs);
 }
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 6b5014f90e1b630d693000dabe1cb3bb29bdfa0d..8b04066133c6eb7a86db4dad1ab613caac4d10ab 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.140 2003/06/24 23:14:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.141 2003/06/25 21:30:30 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -132,28 +132,6 @@ get_rightop(Expr *clause)
 		return NULL;
 }
 
-/*****************************************************************************
- *              FUNCTION clause functions
- *****************************************************************************/
-
-/*
- * make_funcclause
- *		Creates a function clause given its function info and argument list.
- */
-Expr *
-make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
-							CoercionForm funcformat, List *funcargs)
-{
-	FuncExpr   *expr = makeNode(FuncExpr);
-
-	expr->funcid = funcid;
-	expr->funcresulttype = funcresulttype;
-	expr->funcretset = funcretset;
-	expr->funcformat = funcformat;
-	expr->args = funcargs;
-	return (Expr *) expr;
-}
-
 /*****************************************************************************
  *		NOT clause functions
  *****************************************************************************/
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ed409c917155cdee97c8aee075ea803399e7262b..b24e00b9a54ffb9364e85427851a3adf444641c5 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.420 2003/06/25 04:19:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.421 2003/06/25 21:30:30 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -5505,7 +5505,6 @@ r_expr:  row IN_P select_with_parens
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = ANY_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = $1;
 					n->operName = makeList1(makeString("="));
 					n->subselect = $3;
@@ -5516,7 +5515,6 @@ r_expr:  row IN_P select_with_parens
 					/* Make an IN node */
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = ANY_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = $1;
 					n->operName = makeList1(makeString("="));
 					n->subselect = $4;
@@ -5528,7 +5526,6 @@ r_expr:  row IN_P select_with_parens
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = $3;
-					n->isExpr = false;
 					n->lefthand = $1;
 					n->operName = $2;
 					n->subselect = $4;
@@ -5539,7 +5536,6 @@ r_expr:  row IN_P select_with_parens
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = MULTIEXPR_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = $1;
 					n->operName = $2;
 					n->subselect = $3;
@@ -5923,7 +5919,6 @@ a_expr:		c_expr									{ $$ = $1; }
 					{
 							SubLink *n = (SubLink *)$3;
 							n->subLinkType = ANY_SUBLINK;
-							n->isExpr = false;
 							n->lefthand = makeList1($1);
 							n->operName = makeList1(makeString("="));
 							$$ = (Node *)n;
@@ -5951,7 +5946,6 @@ a_expr:		c_expr									{ $$ = $1; }
 					{
 						/* Make an IN node */
 						SubLink *n = (SubLink *)$4;
-						n->isExpr = false;
 						n->subLinkType = ANY_SUBLINK;
 						n->lefthand = makeList1($1);
 						n->operName = makeList1(makeString("="));
@@ -5978,38 +5972,11 @@ a_expr:		c_expr									{ $$ = $1; }
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = $3;
-					n->isExpr = false;
 					n->lefthand = makeList1($1);
 					n->operName = $2;
 					n->subselect = $4;
 					$$ = (Node *)n;
 				}
-			| a_expr qual_all_Op sub_type '(' a_expr ')' %prec Op
-				{
-					SubLink *n = makeNode(SubLink);
-					SelectStmt *s = makeNode(SelectStmt);
-					ResTarget *r = makeNode(ResTarget);
-
-					r->name = NULL;
-					r->indirection = NIL;
-					r->val = (Node *)$5;
-
-					s->distinctClause = NIL;
-					s->targetList = makeList1(r);
-					s->into = NULL;
-					s->intoColNames = NIL;
-					s->fromClause = NIL;
-					s->whereClause = NULL;
-					s->groupClause = NIL;
-					s->havingClause = NULL;
-
-					n->subLinkType = $3;
-					n->isExpr = true;
-					n->lefthand = makeList1($1);
-					n->operName = $2;
-					n->subselect = (Node *) s;
-					$$ = (Node *)n;
-				}
 			| UNIQUE select_with_parens %prec Op
 				{
 					/* Not sure how to get rid of the parentheses
@@ -6586,7 +6553,6 @@ c_expr:		columnref								{ $$ = (Node *) $1; }
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = EXPR_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = NIL;
 					n->operName = NIL;
 					n->subselect = $1;
@@ -6596,7 +6562,6 @@ c_expr:		columnref								{ $$ = (Node *) $1; }
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = EXISTS_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = NIL;
 					n->operName = NIL;
 					n->subselect = $2;
@@ -6606,7 +6571,6 @@ c_expr:		columnref								{ $$ = (Node *) $1; }
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = ARRAY_SUBLINK;
-					n->isExpr = false;
 					n->lefthand = NIL;
 					n->operName = NIL;
 					n->subselect = $2;
@@ -6781,7 +6745,6 @@ trim_list:	a_expr FROM expr_list					{ $$ = lappend($3, $1); }
 in_expr:	select_with_parens
 				{
 					SubLink *n = makeNode(SubLink);
-					n->isExpr = false;
 					n->subselect = $1;
 					/* other fields will be filled later */
 					$$ = (Node *)n;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 7fd831ca91648c694b07b34f746937f2ee4ee2ec..987d129027fc68602685a7774270b80ff38ce578 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.99 2003/06/25 04:32:03 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.100 2003/06/25 21:30:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -859,11 +859,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	/* Get the element type based on the array type, if we have one */
 	if (OidIsValid(array_typeid))
 	{
-		if (array_typeid != ANYARRAYOID)
-			array_typelem = get_element_type(array_typeid);
-		else
-			array_typelem = ANYELEMENTOID;
-
+		array_typelem = get_element_type(array_typeid);
 		if (!OidIsValid(array_typelem))
 			elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
 				 format_type_be(array_typeid));
@@ -923,11 +919,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	{
 		if (!OidIsValid(array_typeid))
 		{
-			if (elem_typeid != ANYELEMENTOID)
-				array_typeid = get_array_type(elem_typeid);
-			else
-				array_typeid = ANYARRAYOID;
-
+			array_typeid = get_array_type(elem_typeid);
 			if (!OidIsValid(array_typeid))
 				elog(ERROR, "Cannot find array type for datatype %s",
 					 format_type_be(elem_typeid));
@@ -1178,11 +1170,6 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
 	if (srctype == targettype)
 		return true;
 
-	/* Last of the fast-paths: check for matching polymorphic arrays */
-	if (targettype == ANYARRAYOID)
-		if (get_element_type(srctype) != InvalidOid)
-			return true;
-
 	/* Else look in pg_cast */
 	tuple = SearchSysCache(CASTSOURCETARGET,
 						   ObjectIdGetDatum(srctype),
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 5234c22e4fbf8e15dee6a4e399c50bf7c4b524ab..1e655217103a0fe79e294c994940277315fc73b5 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.149 2003/06/24 23:14:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.150 2003/06/25 21:30:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -436,7 +436,6 @@ transformExpr(ParseState *pstate, Node *expr)
 					sublink->operName = NIL;
 					sublink->operOids = NIL;
 					sublink->useOr = FALSE;
-					sublink->isExpr = FALSE;
 				}
 				else if (sublink->subLinkType == EXPR_SUBLINK ||
 						 sublink->subLinkType == ARRAY_SUBLINK)
@@ -464,7 +463,6 @@ transformExpr(ParseState *pstate, Node *expr)
 					sublink->operName = NIL;
 					sublink->operOids = NIL;
 					sublink->useOr = FALSE;
-					sublink->isExpr = FALSE;
 				}
 				else
 				{
@@ -540,30 +538,10 @@ transformExpr(ParseState *pstate, Node *expr)
 						 * here, because make_subplan() will insert type
 						 * coercion calls if needed.
 						 */
-						if (!sublink->isExpr)
-						{
-							optup = oper(op,
-										 exprType(lexpr),
-										 exprType((Node *) tent->expr),
-										 false);
-						}
-						else
-						{
-							Oid		exprtype = exprType((Node *) tent->expr);
-							Oid		elemtype = get_element_type(exprtype);
-
-							if (elemtype != InvalidOid)
-								optup = oper(op,
-											 exprType(lexpr),
-											 elemtype,
-											 false);
-							else
-								optup = oper(op,
-											 exprType(lexpr),
-											 exprtype,
-											 false);
-						}
-
+						optup = oper(op,
+									 exprType(lexpr),
+									 exprType((Node *) tent->expr),
+									 false);
 						opform = (Form_pg_operator) GETSTRUCT(optup);
 
 						if (opform->oprresult != BOOLOID)
@@ -765,7 +743,7 @@ transformExpr(ParseState *pstate, Node *expr)
 						ArrayExpr  *e = (ArrayExpr *) lfirst(element);
 
 						if (!IsA(e, ArrayExpr))
-							elog(ERROR, "Multidimensional ARRAY[] must be built from nested array expressions");
+							elog(ERROR, "Multi-dimensional ARRAY[] must be built from nested array expressions");
 						if (ndims == 0)
 							ndims = e->ndims;
 						else if (e->ndims != ndims)
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 2b0e10e4ca1ff08680e6bd042508bd9d549f0ee6..806138a25a5201510dceb0911afc792a3361d734 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.151 2003/06/25 20:07:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.152 2003/06/25 21:30:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -336,7 +336,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 		aggref->target = lfirst(fargs);
 		aggref->aggstar = agg_star;
 		aggref->aggdistinct = agg_distinct;
-		aggref->args = fargs;
 
 		/* parse_agg.c does additional aggregate-specific processing */
 		transformAggregateCall(pstate, aggref);
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index a6b66625be203e53ce2373e6b33131158664eed8..69edb4b85bd0ba144292070730dd7d44d3084141 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.65 2003/06/24 23:14:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.66 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -137,33 +137,6 @@ Operator
 equality_oper(Oid argtype, bool noError)
 {
 	Operator	optup;
-	Oid			elem_type = get_element_type(argtype);
-
-	if (OidIsValid(elem_type))
-	{
-		bool	found = false;
-		/*
-		 * If the datatype is an array, look for an "=" operator for the
-		 * element datatype.  We require it to be an exact or binary-compatible
-		 * match, since most callers are not prepared to cope with adding any
-		 * run-time type coercion steps.
-		 */
-		optup = equality_oper(elem_type, true);
-		if (optup != NULL)
-		{
-			found = true;
-			ReleaseSysCache(optup);
-		}
-
-		if (!found)
-		{
-			if (!noError)
-				elog(ERROR, "Unable to identify an equality operator for " \
-							"array type's element type %s",
-							 format_type_be(elem_type));
-			return NULL;
-		}
-	}
 
 	/*
 	 * Look for an "=" operator for the datatype.  We require it to be
@@ -202,33 +175,6 @@ Operator
 ordering_oper(Oid argtype, bool noError)
 {
 	Operator	optup;
-	Oid			elem_type = get_element_type(argtype);
-
-	if (OidIsValid(elem_type))
-	{
-		bool	found = false;
-		/*
-		 * If the datatype is an array, find the array element type's equality
-		 * operator, and use its lsortop (it *must* be mergejoinable).  We use
-		 * this definition because for sorting and grouping purposes, it's
-		 * important that the equality and ordering operators are consistent.
-		 */
-		optup = ordering_oper(elem_type, true);
-		if (optup != NULL)
-		{
-			found = true;
-			ReleaseSysCache(optup);
-		}
-
-		if (!found)
-		{
-			if (!noError)
-				elog(ERROR, "Unable to identify an ordering operator for " \
-							"array type's element type %s",
-							 format_type_be(elem_type));
-			return NULL;
-		}
-	}
 
 	/*
 	 * Find the type's equality operator, and use its lsortop (it *must*
@@ -274,21 +220,6 @@ equality_oper_funcid(Oid argtype)
 	return result;
 }
 
-/*
- * ordering_oper_funcid - convenience routine for oprfuncid(ordering_oper())
- */
-Oid
-ordering_oper_funcid(Oid argtype)
-{
-	Operator	optup;
-	Oid			result;
-
-	optup = ordering_oper(argtype, false);
-	result = oprfuncid(optup);
-	ReleaseSysCache(optup);
-	return result;
-}
-
 /*
  * ordering_oper_opid - convenience routine for oprid(ordering_oper())
  *
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index cfef2db349d21c9b76fdaa5264e5a583b3297194..415a086b7dd180458322db64d97e18dbb422aa62 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.89 2003/06/24 23:14:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.90 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -427,15 +427,6 @@ aclitemeq(const AclItem *a1, const AclItem *a2)
 		a1->ai_grantor == a2->ai_grantor;
 }
 
-/*
- * user-facing version of aclitemeq() for use as the
- * aclitem equality operator
- */
-Datum
-aclitem_eq(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(aclitemeq(PG_GETARG_ACLITEM_P(0), PG_GETARG_ACLITEM_P(1)));
-}
 
 /*
  * acldefault()  --- create an ACL describing default access permissions
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index f5e50771b1337aae7dab378367da51fd2696a05d..519ac8d1885a6e06de0cbfc36147107418771803 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.2 2003/06/24 23:14:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.3 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,35 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+
+/*-----------------------------------------------------------------------------
+ * singleton_array :
+ *		Form a multi-dimensional array given one starting element.
+ *
+ * - first argument is the datum with which to build the array
+ * - second argument is the number of dimensions the array should have;
+ *     defaults to 1 if no second argument is provided
+ *----------------------------------------------------------------------------
+ */
+Datum
+singleton_array(PG_FUNCTION_ARGS)
+{
+	Oid			elem_type = get_fn_expr_argtype(fcinfo, 0);
+	int			ndims;
+
+	if (elem_type == InvalidOid)
+		elog(ERROR, "Cannot determine input datatype");
+
+	if (PG_NARGS() == 2)
+		ndims = PG_GETARG_INT32(1);
+	else
+		ndims = 1;
+
+	PG_RETURN_ARRAYTYPE_P(create_singleton_array(elem_type,
+												 PG_GETARG_DATUM(0),
+												 ndims));
+}
+
 /*-----------------------------------------------------------------------------
  * array_push :
  *		push an element onto either end of a one-dimensional array
@@ -41,7 +70,6 @@ array_push(PG_FUNCTION_ARGS)
 	Oid			arg1_typeid = get_fn_expr_argtype(fcinfo, 1);
 	Oid			arg0_elemid;
 	Oid			arg1_elemid;
-	ArrayMetaState *my_extra;
 
 	if (arg0_typeid == InvalidOid || arg1_typeid == InvalidOid)
 		elog(ERROR, "array_push: cannot determine input data types");
@@ -67,61 +95,28 @@ array_push(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();		/* keep compiler quiet */
 	}
 
-	if (ARR_NDIM(v) == 1)
-	{
-		lb = ARR_LBOUND(v);
-		dimv = ARR_DIMS(v);
-
-		if (arg0_elemid != InvalidOid)
-		{
-			/* append newelem */
-			int	ub = dimv[0] + lb[0] - 1;
-			indx = ub + 1;
-		}
-		else
-		{
-			/* prepend newelem */
-			indx = lb[0] - 1;
-		}
-	}
-	else if (ARR_NDIM(v) == 0)
-		indx = 1;
-	else
-		elog(ERROR, "only empty and one-dimensional arrays are supported");
-
-
-	/*
-	 * We arrange to look up info about element type only once per series
-	 * of calls, assuming the element type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
+	/* Sanity check: do we have a one-dimensional array */
+	if (ARR_NDIM(v) != 1)
+		elog(ERROR, "Arrays greater than one-dimension are not supported");
 
-	if (my_extra->element_type != element_type)
+	lb = ARR_LBOUND(v);
+	dimv = ARR_DIMS(v);
+	if (arg0_elemid != InvalidOid)
 	{
-		/* Get info about element type */
-		get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typalign = typalign;
+		/* append newelem */
+		int	ub = dimv[0] + lb[0] - 1;
+		indx = ub + 1;
 	}
 	else
 	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typalign = my_extra->typalign;
+		/* prepend newelem */
+		indx = lb[0] - 1;
 	}
 
-	result = array_set(v, 1, &indx, newelem, -1, typlen, typbyval,
-												 typalign, &isNull);
+	get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
+
+	result = array_set(v, 1, &indx, newelem, -1,
+					   typlen, typbyval, typalign, &isNull);
 
 	PG_RETURN_ARRAYTYPE_P(result);
 }
@@ -150,28 +145,13 @@ array_cat(PG_FUNCTION_ARGS)
 
 	/*
 	 * We must have one of the following combinations of inputs:
-	 * 1) one empty array, and one non-empty array
-	 * 2) both arrays empty
-	 * 3) two arrays with ndims1 == ndims2
-	 * 4) ndims1 == ndims2 - 1
-	 * 5) ndims1 == ndims2 + 1
+	 * 1) two arrays with ndims1 == ndims2
+	 * 2) ndims1 == ndims2 - 1
+	 * 3) ndims1 == ndims2 + 1
 	 */
 	ndims1 = ARR_NDIM(v1);
 	ndims2 = ARR_NDIM(v2);
 
-	/*
-	 * short circuit - if one input array is empty, and the other is not,
-	 * we return the non-empty one as the result
-	 *
-	 * if both are empty, return the first one
-	 */
-	if (ndims1 == 0 && ndims2 > 0)
-		PG_RETURN_ARRAYTYPE_P(v2);
-
-	if (ndims2 == 0)
-		PG_RETURN_ARRAYTYPE_P(v1);
-
-	/* the rest fall into combo 2, 3, or 4 */
 	if (ndims1 != ndims2 && ndims1 != ndims2 - 1 && ndims1 != ndims2 + 1)
 		elog(ERROR, "Cannot concatenate incompatible arrays of %d and "
 					"%d dimensions", ndims1, ndims2);
@@ -286,15 +266,147 @@ array_cat(PG_FUNCTION_ARGS)
 	PG_RETURN_ARRAYTYPE_P(result);
 }
 
+/*----------------------------------------------------------------------------
+ * array_accum :
+ *		accumulator to build a 1-D array from input values -- this can be used
+ *		to create custom aggregates.
+ *
+ * This function is not marked strict, so we have to be careful about nulls.
+ *----------------------------------------------------------------------------
+ */
+Datum
+array_accum(PG_FUNCTION_ARGS)
+{
+	/* return NULL if both arguments are NULL */
+	if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
+		PG_RETURN_NULL();
+
+	/* create a new 1-D array from the new element if the array is NULL */
+	if (PG_ARGISNULL(0))
+	{
+		Oid			tgt_type = get_fn_expr_rettype(fcinfo);
+		Oid			tgt_elem_type;
+
+		if (tgt_type == InvalidOid)
+			elog(ERROR, "Cannot determine target array type");
+		tgt_elem_type = get_element_type(tgt_type);
+		if (tgt_elem_type == InvalidOid)
+			elog(ERROR, "Target type is not an array");
+
+		PG_RETURN_ARRAYTYPE_P(create_singleton_array(tgt_elem_type,
+													 PG_GETARG_DATUM(1),
+													 1));
+	}
+
+	/* return the array if the new element is NULL */
+	if (PG_ARGISNULL(1))
+		PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P_COPY(0));
+
+	/*
+	 * Otherwise this is equivalent to array_push.  We hack the call a little
+	 * so that array_push can see the fn_expr information.
+	 */
+	return array_push(fcinfo);
+}
+
+/*-----------------------------------------------------------------------------
+ * array_assign :
+ *		assign an element of an array to a new value and return the
+ *		redefined array
+ *----------------------------------------------------------------------------
+ */
+Datum
+array_assign(PG_FUNCTION_ARGS)
+{
+	ArrayType  *v;
+	int			idx_to_chg;
+	Datum		newelem;
+	int		   *dimv,
+			   *lb, ub;
+	ArrayType  *result;
+	bool		isNull;
+	Oid			element_type;
+	int16		typlen;
+	bool		typbyval;
+	char		typalign;
+
+	v = PG_GETARG_ARRAYTYPE_P(0);
+	idx_to_chg = PG_GETARG_INT32(1);
+	newelem = PG_GETARG_DATUM(2);
+
+	/* Sanity check: do we have a one-dimensional array */
+	if (ARR_NDIM(v) != 1)
+		elog(ERROR, "Arrays greater than one-dimension are not supported");
+
+	lb = ARR_LBOUND(v);
+	dimv = ARR_DIMS(v);
+	ub = dimv[0] + lb[0] - 1;
+	if (idx_to_chg < lb[0] || idx_to_chg > ub)
+		elog(ERROR, "Cannot alter nonexistent array element: %d", idx_to_chg);
+
+	element_type = ARR_ELEMTYPE(v);
+	/* Sanity check: do we have a non-zero element type */
+	if (element_type == 0)
+		elog(ERROR, "Invalid array element type: %u", element_type);
+
+	get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
+
+	result = array_set(v, 1, &idx_to_chg, newelem, -1,
+					   typlen, typbyval, typalign, &isNull);
+
+	PG_RETURN_ARRAYTYPE_P(result);
+}
+
+/*-----------------------------------------------------------------------------
+ * array_subscript :
+ *		return specific element of an array
+ *----------------------------------------------------------------------------
+ */
+Datum
+array_subscript(PG_FUNCTION_ARGS)
+{
+	ArrayType  *v;
+	int			idx;
+	int		   *dimv,
+			   *lb, ub;
+	Datum		result;
+	bool		isNull;
+	Oid			element_type;
+	int16		typlen;
+	bool		typbyval;
+	char		typalign;
+
+	v = PG_GETARG_ARRAYTYPE_P(0);
+	idx = PG_GETARG_INT32(1);
+
+	/* Sanity check: do we have a one-dimensional array */
+	if (ARR_NDIM(v) != 1)
+		elog(ERROR, "Arrays greater than one-dimension are not supported");
+
+	lb = ARR_LBOUND(v);
+	dimv = ARR_DIMS(v);
+	ub = dimv[0] + lb[0] - 1;
+	if (idx < lb[0] || idx > ub)
+		elog(ERROR, "Cannot return nonexistent array element: %d", idx);
+
+	element_type = ARR_ELEMTYPE(v);
+	/* Sanity check: do we have a non-zero element type */
+	if (element_type == 0)
+		elog(ERROR, "Invalid array element type: %u", element_type);
+
+	get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
+
+	result = array_ref(v, 1, &idx, -1, typlen, typbyval, typalign, &isNull);
+
+	PG_RETURN_DATUM(result);
+}
 
 /*
- * used by text_to_array() in varlena.c
+ * actually does the work for singleton_array(), and array_accum() if it is
+ * given a null input array.
  */
 ArrayType *
-create_singleton_array(FunctionCallInfo fcinfo,
-					   Oid element_type,
-					   Datum element,
-					   int ndims)
+create_singleton_array(Oid element_type, Datum element, int ndims)
 {
 	Datum	dvalues[1];
 	int16	typlen;
@@ -303,7 +415,6 @@ create_singleton_array(FunctionCallInfo fcinfo,
 	int		dims[MAXDIM];
 	int		lbs[MAXDIM];
 	int		i;
-	ArrayMetaState *my_extra;
 
 	if (element_type == 0)
 		elog(ERROR, "Invalid array element type: %u", element_type);
@@ -318,35 +429,7 @@ create_singleton_array(FunctionCallInfo fcinfo,
 		lbs[i] = 1;
 	}
 
-	/*
-	 * We arrange to look up info about element type only once per series
-	 * of calls, assuming the element type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type */
-		get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typalign = typalign;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typalign = my_extra->typalign;
-	}
+	get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
 
 	return construct_md_array(dvalues, ndims, dims, lbs, element_type,
 							  typlen, typbyval, typalign);
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 27a805d9b28dd6e3af4456a4589113a3ddb75821..c03d8c861d13fb64c82ae4d762ed9efc84361121 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.90 2003/06/24 23:14:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.91 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,10 +21,8 @@
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "parser/parse_coerce.h"
-#include "parser/parse_oper.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
-#include "utils/datum.h"
 #include "utils/memutils.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
@@ -72,6 +70,16 @@
 
 #define RETURN_NULL(type)  do { *isNull = true; return (type) 0; } while (0)
 
+/* I/O function selector for system_cache_lookup */
+typedef enum IOFuncSelector
+{
+	IOFunc_input,
+	IOFunc_output,
+	IOFunc_receive,
+	IOFunc_send
+} IOFuncSelector;
+
+
 static int	ArrayCount(char *str, int *dim, char typdelim);
 static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
 			 FmgrInfo *inputproc, Oid typelem, int32 typmod,
@@ -85,6 +93,10 @@ static Datum *ReadArrayBinary(StringInfo buf, int nitems,
 static void CopyArrayEls(char *p, Datum *values, int nitems,
 			 int typlen, bool typbyval, char typalign,
 			 bool freedata);
+static void system_cache_lookup(Oid element_type, IOFuncSelector which_func,
+								int *typlen, bool *typbyval,
+								char *typdelim, Oid *typelem,
+								Oid *proc, char *typalign);
 static Datum ArrayCast(char *value, bool byval, int len);
 static int ArrayCastAndSet(Datum src,
 				int typlen, bool typbyval, char typalign,
@@ -107,7 +119,7 @@ static void array_insert_slice(int ndim, int *dim, int *lb,
 				   char *destPtr,
 				   int *st, int *endp, char *srcPtr,
 				   int typlen, bool typbyval, char typalign);
-static int array_cmp(FunctionCallInfo fcinfo);
+
 
 /*---------------------------------------------------------------------
  * array_in :
@@ -142,49 +154,12 @@ array_in(PG_FUNCTION_ARGS)
 				dim[MAXDIM],
 				lBound[MAXDIM];
 	char		typalign;
-	ArrayMetaState *my_extra;
-
-	/*
-	 * We arrange to look up info about element type, including its input
-	 * conversion proc only once per series of calls, assuming the element
-	 * type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
 
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type, including its input conversion proc */
-		get_type_metadata(element_type, IOFunc_input,
-							&typlen, &typbyval, &typdelim,
-							&typelem, &typinput, &typalign);
-		fmgr_info(typinput, &inputproc);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = typinput;
-		my_extra->typalign = typalign;
-		my_extra->proc = inputproc;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typdelim = my_extra->typdelim;
-		typelem = my_extra->typelem;
-		typinput = my_extra->typiofunc;
-		typalign = my_extra->typalign;
-		inputproc = my_extra->proc;
-	}
+	/* Get info about element type, including its input conversion proc */
+	system_cache_lookup(element_type, IOFunc_input,
+						&typlen, &typbyval, &typdelim,
+						&typelem, &typinput, &typalign);
+	fmgr_info(typinput, &inputproc);
 
 	/* Make a modifiable copy of the input */
 	/* XXX why are we allocating an extra 2 bytes here? */
@@ -661,51 +636,12 @@ array_out(PG_FUNCTION_ARGS)
 				indx[MAXDIM];
 	int			ndim,
 			   *dim;
-	ArrayMetaState *my_extra;
 
 	element_type = ARR_ELEMTYPE(v);
-
-	/*
-	 * We arrange to look up info about element type, including its input
-	 * conversion proc only once per series of calls, assuming the element
-	 * type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type, including its output conversion proc */
-		get_type_metadata(element_type, IOFunc_output,
-							&typlen, &typbyval, &typdelim,
-							&typelem, &typoutput, &typalign);
-		fmgr_info(typoutput, &outputproc);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = typoutput;
-		my_extra->typalign = typalign;
-		my_extra->proc = outputproc;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typdelim = my_extra->typdelim;
-		typelem = my_extra->typelem;
-		typoutput = my_extra->typiofunc;
-		typalign = my_extra->typalign;
-		outputproc = my_extra->proc;
-	}
+	system_cache_lookup(element_type, IOFunc_output,
+						&typlen, &typbyval, &typdelim,
+						&typelem, &typoutput, &typalign);
+	fmgr_info(typoutput, &outputproc);
 
 	ndim = ARR_NDIM(v);
 	dim = ARR_DIMS(v);
@@ -864,7 +800,6 @@ array_recv(PG_FUNCTION_ARGS)
 				dim[MAXDIM],
 				lBound[MAXDIM];
 	char		typalign;
-	ArrayMetaState *my_extra;
 
 	/* Get the array header information */
 	ndim = pq_getmsgint(buf, 4);
@@ -896,50 +831,14 @@ array_recv(PG_FUNCTION_ARGS)
 		PG_RETURN_ARRAYTYPE_P(retval);
 	}
 
-	/*
-	 * We arrange to look up info about element type, including its receive
-	 * conversion proc only once per series of calls, assuming the element
-	 * type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type, including its receive conversion proc */
-		get_type_metadata(element_type, IOFunc_receive,
-							&typlen, &typbyval, &typdelim,
-							&typelem, &typreceive, &typalign);
-		if (!OidIsValid(typreceive))
-			elog(ERROR, "No binary input function available for type %s",
-				 format_type_be(element_type));
-		fmgr_info(typreceive, &receiveproc);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = typreceive;
-		my_extra->typalign = typalign;
-		my_extra->proc = receiveproc;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typdelim = my_extra->typdelim;
-		typelem = my_extra->typelem;
-		typreceive = my_extra->typiofunc;
-		typalign = my_extra->typalign;
-		receiveproc = my_extra->proc;
-	}
+	/* Get info about element type, including its receive conversion proc */
+	system_cache_lookup(element_type, IOFunc_receive,
+						&typlen, &typbyval, &typdelim,
+						&typelem, &typreceive, &typalign);
+	if (!OidIsValid(typreceive))
+		elog(ERROR, "No binary input function available for type %s",
+			 format_type_be(element_type));
+	fmgr_info(typreceive, &receiveproc);
 
 	dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
 							  typlen, typbyval, typalign,
@@ -1077,54 +976,15 @@ array_send(PG_FUNCTION_ARGS)
 	int			ndim,
 			   *dim;
 	StringInfoData buf;
-	ArrayMetaState *my_extra;
 
 	/* Get information about the element type and the array dimensions */
 	element_type = ARR_ELEMTYPE(v);
-
-	/*
-	 * We arrange to look up info about element type, including its send
-	 * proc only once per series of calls, assuming the element
-	 * type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type, including its send proc */
-		get_type_metadata(element_type, IOFunc_send, &typlen, &typbyval,
-							&typdelim, &typelem, &typsend, &typalign);
-		if (!OidIsValid(typsend))
-			elog(ERROR, "No binary output function available for type %s",
-				 format_type_be(element_type));
-		fmgr_info(typsend, &sendproc);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = typsend;
-		my_extra->typalign = typalign;
-		my_extra->proc = sendproc;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typdelim = my_extra->typdelim;
-		typelem = my_extra->typelem;
-		typsend = my_extra->typiofunc;
-		typalign = my_extra->typalign;
-		sendproc = my_extra->proc;
-	}
+	system_cache_lookup(element_type, IOFunc_send, &typlen, &typbyval,
+						&typdelim, &typelem, &typsend, &typalign);
+	if (!OidIsValid(typsend))
+		elog(ERROR, "No binary output function available for type %s",
+			 format_type_be(element_type));
+	fmgr_info(typsend, &sendproc);
 
 	ndim = ARR_NDIM(v);
 	dim = ARR_DIMS(v);
@@ -1616,26 +1476,6 @@ array_set(ArrayType *array,
 	array = DatumGetArrayTypeP(PointerGetDatum(array));
 
 	ndim = ARR_NDIM(array);
-
-	/*
-	 * if number of dims is zero, i.e. an empty array, create an array
-	 * with nSubscripts dimensions, and set the lower bounds to the supplied
-	 * subscripts
-	 */
-	if (ndim == 0)
-	{
-		Oid		elmtype = ARR_ELEMTYPE(array);
-
-		for (i = 0; i < nSubscripts; i++)
-		{
-			dim[i] = 1;
-			lb[i] = indx[i];
-		}
-
-		return construct_md_array(&dataValue, nSubscripts, dim, lb, elmtype,
-												elmlen, elmbyval, elmalign);
-	}
-
 	if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
 		elog(ERROR, "Invalid array subscripts");
 
@@ -1792,31 +1632,6 @@ array_set_slice(ArrayType *array,
 	/* note: we assume srcArray contains no toasted elements */
 
 	ndim = ARR_NDIM(array);
-
-	/*
-	 * if number of dims is zero, i.e. an empty array, create an array
-	 * with nSubscripts dimensions, and set the upper and lower bounds
-	 * to the supplied subscripts
-	 */
-	if (ndim == 0)
-	{
-		Datum  *dvalues;
-		int		nelems;
-		Oid		elmtype = ARR_ELEMTYPE(array);
-
-		deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
-														&dvalues, &nelems);
-
-		for (i = 0; i < nSubscripts; i++)
-		{
-			dim[i] = 1 + upperIndx[i] - lowerIndx[i];
-			lb[i] = lowerIndx[i];
-		}
-
-		return construct_md_array(dvalues, nSubscripts, dim, lb, elmtype,
-												 elmlen, elmbyval, elmalign);
-	}
-
 	if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
 		elog(ERROR, "Invalid array subscripts");
 
@@ -1996,13 +1811,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
 	Oid			typelem;
 	Oid			proc;
 	char	   *s;
-	typedef struct {
-		ArrayMetaState *inp_extra;
-		ArrayMetaState *ret_extra;
-	} am_extra;
-	am_extra  *my_extra;
-	ArrayMetaState *inp_extra;
-	ArrayMetaState *ret_extra;
 
 	/* Get input array */
 	if (fcinfo->nargs < 1)
@@ -2021,81 +1829,11 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
 	if (nitems <= 0)
 		PG_RETURN_ARRAYTYPE_P(v);
 
-	/*
-	 * We arrange to look up info about input and return element types only
-	 * once per series of calls, assuming the element type doesn't change
-	 * underneath us.
-	 */
-	my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(am_extra));
-		my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
-
-		my_extra->inp_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		inp_extra = my_extra->inp_extra;
-		inp_extra->element_type = InvalidOid;
-
-		my_extra->ret_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		ret_extra = my_extra->ret_extra;
-		ret_extra->element_type = InvalidOid;
-	}
-	else
-	{
-		inp_extra = my_extra->inp_extra;
-		ret_extra = my_extra->ret_extra;
-	}
-
-	if (inp_extra->element_type != inpType)
-	{
-		/* Lookup source and result types. Unneeded variables are reused. */
-		get_type_metadata(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
-							&typdelim, &typelem, &proc, &inp_typalign);
-
-		inp_extra->element_type = inpType;
-		inp_extra->typlen = inp_typlen;
-		inp_extra->typbyval = inp_typbyval;
-		inp_extra->typdelim = typdelim;
-		inp_extra->typelem = typelem;
-		inp_extra->typiofunc = proc;
-		inp_extra->typalign = inp_typalign;
-	}
-	else
-	{
-		inp_typlen = inp_extra->typlen;
-		inp_typbyval = inp_extra->typbyval;
-		typdelim = inp_extra->typdelim;
-		typelem = inp_extra->typelem;
-		proc = inp_extra->typiofunc;
-		inp_typalign = inp_extra->typalign;
-	}
-
-	if (ret_extra->element_type != retType)
-	{
-		/* Lookup source and result types. Unneeded variables are reused. */
-		get_type_metadata(retType, IOFunc_input, &typlen, &typbyval,
-							&typdelim, &typelem, &proc, &typalign);
-
-		ret_extra->element_type = retType;
-		ret_extra->typlen = typlen;
-		ret_extra->typbyval = typbyval;
-		ret_extra->typdelim = typdelim;
-		ret_extra->typelem = typelem;
-		ret_extra->typiofunc = proc;
-		ret_extra->typalign = typalign;
-	}
-	else
-	{
-		typlen = ret_extra->typlen;
-		typbyval = ret_extra->typbyval;
-		typdelim = ret_extra->typdelim;
-		typelem = ret_extra->typelem;
-		proc = ret_extra->typiofunc;
-		typalign = ret_extra->typalign;
-	}
+	/* Lookup source and result types. Unneeded variables are reused. */
+	system_cache_lookup(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
+						&typdelim, &typelem, &proc, &inp_typalign);
+	system_cache_lookup(retType, IOFunc_input, &typlen, &typbyval,
+						&typdelim, &typelem, &proc, &typalign);
 
 	/* Allocate temporary array for new values */
 	values = (Datum *) palloc(nitems * sizeof(Datum));
@@ -2311,6 +2049,8 @@ deconstruct_array(ArrayType *array,
  *		  compares two arrays for equality
  * result :
  *		  returns true if the arrays are equal, false otherwise.
+ *
+ * XXX bitwise equality is pretty bogus ...
  *-----------------------------------------------------------------------------
  */
 Datum
@@ -2318,118 +2058,12 @@ array_eq(PG_FUNCTION_ARGS)
 {
 	ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
 	ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
-	char	   *p1 = (char *) ARR_DATA_PTR(array1);
-	char	   *p2 = (char *) ARR_DATA_PTR(array2);
-	int			ndims1 = ARR_NDIM(array1);
-	int			ndims2 = ARR_NDIM(array2);
-	int		   *dims1 = ARR_DIMS(array1);
-	int		   *dims2 = ARR_DIMS(array2);
-	int			nitems1 = ArrayGetNItems(ndims1, dims1);
-	int			nitems2 = ArrayGetNItems(ndims2, dims2);
-	Oid			element_type = ARR_ELEMTYPE(array1);
-	FmgrInfo   *ae_fmgr_info = fcinfo->flinfo;
 	bool		result = true;
-	int			typlen;
-	bool		typbyval;
-	char		typdelim;
-	Oid			typelem;
-	char		typalign;
-	Oid			typiofunc;
-	int			i;
-	ArrayMetaState *my_extra;
-	FunctionCallInfoData locfcinfo;
 
-	/* fast path if the arrays do not have the same number of elements */
-	if (nitems1 != nitems2)
+	if (ARR_SIZE(array1) != ARR_SIZE(array2))
+		result = false;
+	else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0)
 		result = false;
-	else
-	{
-		/*
-		 * We arrange to look up the equality function only once per series of
-		 * calls, assuming the element type doesn't change underneath us.
-		 */
-		my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
-		if (my_extra == NULL)
-		{
-			ae_fmgr_info->fn_extra = MemoryContextAlloc(ae_fmgr_info->fn_mcxt,
-													 sizeof(ArrayMetaState));
-			my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
-			my_extra->element_type = InvalidOid;
-		}
-
-		if (my_extra->element_type != element_type)
-		{
-			Oid		opfuncid = equality_oper_funcid(element_type);
-
-			if (OidIsValid(opfuncid))
-				fmgr_info_cxt(opfuncid, &my_extra->proc, ae_fmgr_info->fn_mcxt);
-			else
-				elog(ERROR,
-					 "array_eq: cannot find equality operator for type: %u",
-					 element_type);
-
-			get_type_metadata(element_type, IOFunc_output,
-							  &typlen, &typbyval, &typdelim,
-							  &typelem, &typiofunc, &typalign);
-			
-			my_extra->element_type = element_type;
-			my_extra->typlen = typlen;
-			my_extra->typbyval = typbyval;
-			my_extra->typdelim = typdelim;
-			my_extra->typelem = typelem;
-			my_extra->typiofunc = typiofunc;
-			my_extra->typalign = typalign;
-		}
-		else
-		{
-			typlen = my_extra->typlen;
-			typbyval = my_extra->typbyval;
-			typdelim = my_extra->typdelim;
-			typelem = my_extra->typelem;
-			typiofunc = my_extra->typiofunc;
-			typalign = my_extra->typalign;
-		}
-
-		/*
-		 * apply the operator to each pair of array elements.
-		 */
-		MemSet(&locfcinfo, 0, sizeof(locfcinfo));
-		locfcinfo.flinfo = &my_extra->proc;
-		locfcinfo.nargs = 2;
-
-		/* Loop over source data */
-		for (i = 0; i < nitems1; i++)
-		{
-			Datum	elt1;
-			Datum	elt2;
-			bool	oprresult;
-
-			/* Get element pair */
-			elt1 = fetch_att(p1, typbyval, typlen);
-			elt2 = fetch_att(p2, typbyval, typlen);
-
-			p1 = att_addlength(p1, typlen, PointerGetDatum(p1));
-			p1 = (char *) att_align(p1, typalign);
-
-			p2 = att_addlength(p2, typlen, PointerGetDatum(p2));
-			p2 = (char *) att_align(p2, typalign);
-
-			/*
-			 * Apply the operator to the element pair
-			 */
-			locfcinfo.arg[0] = elt1;
-			locfcinfo.arg[1] = elt2;
-			locfcinfo.argnull[0] = false;
-			locfcinfo.argnull[1] = false;
-			locfcinfo.isnull = false;
-			oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
-			if (!oprresult)
-			{
-				result = false;
-				break;
-			}
-		}
-	}
 
 	/* Avoid leaking memory when handed toasted input. */
 	PG_FREE_IF_COPY(array1, 0);
@@ -2439,190 +2073,53 @@ array_eq(PG_FUNCTION_ARGS)
 }
 
 
-/*-----------------------------------------------------------------------------
- * array-array bool operators:
- *		Given two arrays, iterate comparison operators
- *		over the array. Uses logic similar to text comparison
- *		functions, except element-by-element instead of
- *		character-by-character.
- *----------------------------------------------------------------------------
- */
-Datum
-array_ne(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(!DatumGetBool(array_eq(fcinfo)));
-}
-
-Datum
-array_lt(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
-}
-
-Datum
-array_gt(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
-}
-
-Datum
-array_le(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
-}
-
-Datum
-array_ge(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
-}
-
-Datum
-btarraycmp(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT32(array_cmp(fcinfo));
-}
-
-/*
- * array_cmp()
- * Internal comparison function for arrays.
- *
- * Returns -1, 0 or 1
- */
-static int
-array_cmp(FunctionCallInfo fcinfo)
-{
-	ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
-	ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
-	FmgrInfo   *ac_fmgr_info = fcinfo->flinfo;
-	Datum		opresult;
-	int			result = 0;
-	Oid			element_type = InvalidOid;
-	int			typlen;
-	bool		typbyval;
-	char		typdelim;
-	Oid			typelem;
-	char		typalign;
-	Oid			typiofunc;
-	Datum	   *dvalues1;
-	int			nelems1;
-	Datum	   *dvalues2;
-	int			nelems2;
-	int			min_nelems;
-	int			i;
-	typedef struct
-	{
-		Oid				element_type;
-		int				typlen;
-		bool			typbyval;
-		char			typdelim;
-		Oid				typelem;
-		Oid				typiofunc;
-		char			typalign;
-		FmgrInfo		eqproc;
-		FmgrInfo		ordproc;
-	} ac_extra;
-	ac_extra *my_extra;
-
-	element_type = ARR_ELEMTYPE(array1);
-
-	/*
-	 * We arrange to look up the element type operator function only once
-	 * per series of calls, assuming the element type and opname don't
-	 * change underneath us.
-	 */
-	my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
-	if (my_extra == NULL)
-	{
-		ac_fmgr_info->fn_extra = MemoryContextAlloc(ac_fmgr_info->fn_mcxt,
-														 sizeof(ac_extra));
-		my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		Oid		eqfuncid = equality_oper_funcid(element_type);
-		Oid		ordfuncid = ordering_oper_funcid(element_type);
-
-		fmgr_info_cxt(eqfuncid, &my_extra->eqproc, ac_fmgr_info->fn_mcxt);
-		fmgr_info_cxt(ordfuncid, &my_extra->ordproc, ac_fmgr_info->fn_mcxt);
-
-		if (my_extra->eqproc.fn_nargs != 2)
-			elog(ERROR, "Equality operator does not take 2 arguments: %u",
-																 eqfuncid);
-		if (my_extra->ordproc.fn_nargs != 2)
-			elog(ERROR, "Ordering operator does not take 2 arguments: %u",
-																 ordfuncid);
-
-		get_type_metadata(element_type, IOFunc_output,
-						  &typlen, &typbyval, &typdelim,
-						  &typelem, &typiofunc, &typalign);
-		
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = InvalidOid;
-		my_extra->typalign = typalign;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typalign = my_extra->typalign;
-	}
-
-	/* extract a C array of arg array datums */
-	deconstruct_array(array1, element_type, typlen, typbyval, typalign,
-													&dvalues1, &nelems1);
-
-	deconstruct_array(array2, element_type, typlen, typbyval, typalign,
-													&dvalues2, &nelems2);
-
-	min_nelems = Min(nelems1, nelems2);
-	for (i = 0; i < min_nelems; i++)
-	{
-		/* are they equal */
-		opresult = FunctionCall2(&my_extra->eqproc,
-								 dvalues1[i], dvalues2[i]);
-
-		if (!DatumGetBool(opresult))
-		{
-			/* nope, see if arg1 is less than arg2 */
-			opresult = FunctionCall2(&my_extra->ordproc,
-									 dvalues1[i], dvalues2[i]);
-			if (DatumGetBool(opresult))
-			{
-				/* arg1 is less than arg2 */
-				result = -1;
-				break;
-			}
-			else
-			{
-				/* arg1 is greater than arg2 */
-				result = 1;
-				break;
-			}
-		}
-	}
-
-	if ((result == 0) && (nelems1 != nelems2))
-		result = (nelems1 < nelems2) ? -1 : 1;
-
-	/* Avoid leaking memory when handed toasted input. */
-	PG_FREE_IF_COPY(array1, 0);
-	PG_FREE_IF_COPY(array2, 1);
-
-	return result;
-}
-
-
 /***************************************************************************/
 /******************|		  Support  Routines			  |*****************/
 /***************************************************************************/
 
+static void
+system_cache_lookup(Oid element_type,
+					IOFuncSelector which_func,
+					int *typlen,
+					bool *typbyval,
+					char *typdelim,
+					Oid *typelem,
+					Oid *proc,
+					char *typalign)
+{
+	HeapTuple	typeTuple;
+	Form_pg_type typeStruct;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(element_type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "cache lookup failed for type %u", element_type);
+	typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+	*typlen = typeStruct->typlen;
+	*typbyval = typeStruct->typbyval;
+	*typdelim = typeStruct->typdelim;
+	*typelem = typeStruct->typelem;
+	*typalign = typeStruct->typalign;
+	switch (which_func)
+	{
+		case IOFunc_input:
+			*proc = typeStruct->typinput;
+			break;
+		case IOFunc_output:
+			*proc = typeStruct->typoutput;
+			break;
+		case IOFunc_receive:
+			*proc = typeStruct->typreceive;
+			break;
+		case IOFunc_send:
+			*proc = typeStruct->typsend;
+			break;
+	}
+	ReleaseSysCache(typeTuple);
+}
+
 /*
  * Fetch array element at pointer, converted correctly to a Datum
  */
@@ -2926,18 +2423,6 @@ array_type_coerce(PG_FUNCTION_ARGS)
 		if (tgt_elem_type == InvalidOid)
 			elog(ERROR, "Target type is not an array");
 
-		/*
-		 * We don't deal with domain constraints yet, so bail out.
-		 * This isn't currently a problem, because we also don't
-		 * support arrays of domain type elements either. But in the
-		 * future we might. At that point consideration should be given
-		 * to removing the check below and adding a domain constraints
-		 * check to the coercion.
-		 */
-		if (getBaseType(tgt_elem_type) != tgt_elem_type)
-			elog(ERROR, "array coercion to domain type elements not " \
-						"currently supported");
-
 		if (!find_coercion_pathway(tgt_elem_type, src_elem_type,
 								   COERCION_EXPLICIT, &funcId))
 		{
@@ -2954,16 +2439,10 @@ array_type_coerce(PG_FUNCTION_ARGS)
 	}
 
 	/*
-	 * If it's binary-compatible, modify the element type in the array header,
-	 * but otherwise leave the array as we received it.
+	 * If it's binary-compatible, return the array unmodified.
 	 */
 	if (my_extra->coerce_finfo.fn_oid == InvalidOid)
-	{
-		ArrayType  *result = DatumGetArrayTypePCopy(PG_GETARG_DATUM(0));
-		
-		ARR_ELEMTYPE(result) = my_extra->desttype;
-		PG_RETURN_ARRAYTYPE_P(result);
-	}
+		PG_RETURN_ARRAYTYPE_P(src);
 
 	/*
 	 * Use array_map to apply the function to each array element.
@@ -2975,118 +2454,3 @@ array_type_coerce(PG_FUNCTION_ARGS)
 
 	return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype);
 }
-
-/*
- * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
- *
- *	astate is working state (NULL on first call)
- *	rcontext is where to keep working state
- */
-ArrayBuildState *
-accumArrayResult(ArrayBuildState *astate,
-				 Datum dvalue, bool disnull,
-				 Oid element_type,
-				 MemoryContext rcontext)
-{
-	MemoryContext arr_context,
-				  oldcontext;
-
-	if (astate == NULL)
-	{
-		/* First time through --- initialize */
-
-		/* Make a temporary context to hold all the junk */
-		arr_context = AllocSetContextCreate(rcontext,
-											"accumArrayResult",
-											ALLOCSET_DEFAULT_MINSIZE,
-											ALLOCSET_DEFAULT_INITSIZE,
-											ALLOCSET_DEFAULT_MAXSIZE);
-		oldcontext = MemoryContextSwitchTo(arr_context);
-		astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
-		astate->mcontext = arr_context;
-		astate->dvalues = (Datum *)
-			palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
-		astate->nelems = 0;
-		astate->element_type = element_type;
-		get_typlenbyvalalign(element_type,
-							 &astate->typlen,
-							 &astate->typbyval,
-							 &astate->typalign);
-	}
-	else
-	{
-		oldcontext = MemoryContextSwitchTo(astate->mcontext);
-		Assert(astate->element_type == element_type);
-		/* enlarge dvalues[] if needed */
-		if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
-			astate->dvalues = (Datum *)
-				repalloc(astate->dvalues,
-						 (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
-	}
-
-	if (disnull)
-		elog(ERROR, "NULL elements not allowed in Arrays");
-
-	/* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
-	astate->dvalues[astate->nelems++] =
-		datumCopy(dvalue, astate->typbyval, astate->typlen);
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return astate;
-}
-
-/*
- * makeArrayResult - produce final result of accumArrayResult
- *
- *	astate is working state (not NULL)
- *	rcontext is where to construct result
- */
-Datum
-makeArrayResult(ArrayBuildState *astate,
-				MemoryContext rcontext)
-{
-	int			dims[1];
-	int			lbs[1];
-
-	dims[0] = astate->nelems;
-	lbs[0] = 1;
-
-	return makeMdArrayResult(astate, 1, dims, lbs, rcontext);
-}
-
-/*
- * makeMdArrayResult - produce md final result of accumArrayResult
- *
- *	astate is working state (not NULL)
- *	rcontext is where to construct result
- */
-Datum
-makeMdArrayResult(ArrayBuildState *astate,
-				int ndims,
-				int *dims,
-				int *lbs,
-				MemoryContext rcontext)
-{
-	ArrayType  *result;
-	MemoryContext oldcontext;
-
-	/* Build the final array result in rcontext */
-	oldcontext = MemoryContextSwitchTo(rcontext);
-
-	result = construct_md_array(astate->dvalues,
-								ndims,
-								dims,
-								lbs,
-								astate->element_type,
-								astate->typlen,
-								astate->typbyval,
-								astate->typalign);
-
-	MemoryContextSwitchTo(oldcontext);
-
-	/* Clean up all the junk */
-	MemoryContextDelete(astate->mcontext);
-
-	return PointerGetDatum(result);
-}
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index aca19d17e89feea74746848e413f2755b85187e4..ce6443647e2240c5df6cd666c4e2781796a4b718 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.99 2003/06/24 23:14:46 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.100 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,14 +19,11 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "access/tuptoaster.h"
-#include "catalog/pg_type.h"
 #include "lib/stringinfo.h"
 #include "libpq/crypt.h"
 #include "libpq/pqformat.h"
-#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/pg_locale.h"
-#include "utils/lsyscache.h"
 
 
 typedef struct varlena unknown;
@@ -1986,7 +1983,8 @@ split_text(PG_FUNCTION_ARGS)
 		if (fldnum == 1)		/* first field - just return the input
 								 * string */
 			PG_RETURN_TEXT_P(inputstring);
-		else					/* otherwise return an empty string */
+		else
+/* otherwise return an empty string */
 			PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
 	}
 
@@ -2006,7 +2004,8 @@ split_text(PG_FUNCTION_ARGS)
 		if (fldnum == 1)		/* first field - just return the input
 								 * string */
 			PG_RETURN_TEXT_P(inputstring);
-		else					/* otherwise return an empty string */
+		else
+/* otherwise return an empty string */
 			PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
 	}
 	else if ((start_posn != 0) && (end_posn == 0))
@@ -2029,191 +2028,6 @@ split_text(PG_FUNCTION_ARGS)
 	}
 }
 
-/*
- * text_to_array
- * parse input string
- * return text array of elements
- * based on provided field separator
- */
-Datum
-text_to_array(PG_FUNCTION_ARGS)
-{
-	text	   *inputstring = PG_GETARG_TEXT_P(0);
-	int			inputstring_len = TEXTLEN(inputstring);
-	text	   *fldsep = PG_GETARG_TEXT_P(1);
-	int			fldsep_len = TEXTLEN(fldsep);
-	int			fldnum;
-	int			start_posn = 0;
-	int			end_posn = 0;
-	text	   *result_text = NULL;
-	ArrayBuildState *astate = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	/* return NULL for empty input string */
-	if (inputstring_len < 1)
-		PG_RETURN_NULL();
-
-	/* empty field separator
-	 * return one element, 1D, array using the input string */
-	if (fldsep_len < 1)
-		PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
-							  CStringGetDatum(inputstring), 1));
-
-	/* start with end position holding the initial start position */
-	end_posn = 0;
-	for (fldnum=1;;fldnum++)	/* field number is 1 based */
-	{
-		Datum	dvalue;
-		bool	disnull = false;
-
-		start_posn = end_posn;
-		end_posn = text_position(PointerGetDatum(inputstring),
-								 PointerGetDatum(fldsep),
-								 fldnum);
-
-		if ((start_posn == 0) && (end_posn == 0))	/* fldsep not found */
-		{
-			if (fldnum == 1)
-			{
-				/* first element
-				 * return one element, 1D, array using the input string */
-				PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
-									  CStringGetDatum(inputstring), 1));
-			}
-			else
-			{
-				/* otherwise create array and exit */
-				PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, oldcontext));
-			}
-		}
-		else if ((start_posn != 0) && (end_posn == 0))
-		{
-			/* last field requested */
-			result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, -1, true);
-		}
-		else if ((start_posn == 0) && (end_posn != 0))
-		{
-			/* first field requested */
-			result_text = LEFT(inputstring, fldsep);
-		}
-		else
-		{
-			/* prior to last field requested */
-			result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false);
-		}
-
-		/* stash away current value */
-		dvalue = PointerGetDatum(result_text);
-		astate = accumArrayResult(astate, dvalue,
-								  disnull, TEXTOID, oldcontext);
-
-	}
-
-	/* never reached -- keep compiler quiet */
-	PG_RETURN_NULL();
-}
-
-/*
- * array_to_text
- * concatenate Cstring representation of input array elements
- * using provided field separator
- */
-Datum
-array_to_text(PG_FUNCTION_ARGS)
-{
-	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
-	char	   *fldsep = PG_TEXTARG_GET_STR(1);
-	int			nitems, *dims, ndims;
-	char	   *p;
-	Oid			element_type;
-	int			typlen;
-	bool		typbyval;
-	char		typdelim;
-	Oid			typoutput,
-				typelem;
-	FmgrInfo	outputproc;
-	char		typalign;
-	StringInfo	result_str = makeStringInfo();
-	int			i;
-	ArrayMetaState *my_extra;
-
-	p = ARR_DATA_PTR(v);
-	ndims = ARR_NDIM(v);
-	dims = ARR_DIMS(v);
-	nitems = ArrayGetNItems(ndims, dims);
-
-	/* if there are no elements, return an empty string */
-	if (nitems == 0)
-		PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
-
-	element_type = ARR_ELEMTYPE(v);
-
-	/*
-	 * We arrange to look up info about element type, including its output
-	 * conversion proc only once per series of calls, assuming the element
-	 * type doesn't change underneath us.
-	 */
-	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-	if (my_extra == NULL)
-	{
-		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
-													 sizeof(ArrayMetaState));
-		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
-		my_extra->element_type = InvalidOid;
-	}
-
-	if (my_extra->element_type != element_type)
-	{
-		/* Get info about element type, including its output conversion proc */
-		get_type_metadata(element_type, IOFunc_output,
-							&typlen, &typbyval, &typdelim,
-							&typelem, &typoutput, &typalign);
-		fmgr_info(typoutput, &outputproc);
-
-		my_extra->element_type = element_type;
-		my_extra->typlen = typlen;
-		my_extra->typbyval = typbyval;
-		my_extra->typdelim = typdelim;
-		my_extra->typelem = typelem;
-		my_extra->typiofunc = typoutput;
-		my_extra->typalign = typalign;
-		my_extra->proc = outputproc;
-	}
-	else
-	{
-		typlen = my_extra->typlen;
-		typbyval = my_extra->typbyval;
-		typdelim = my_extra->typdelim;
-		typelem = my_extra->typelem;
-		typoutput = my_extra->typiofunc;
-		typalign = my_extra->typalign;
-		outputproc = my_extra->proc;
-	}
-
-	for (i = 0; i < nitems; i++)
-	{
-		Datum		itemvalue;
-		char	   *value;
-
-		itemvalue = fetch_att(p, typbyval, typlen);
-
-		value = DatumGetCString(FunctionCall3(&outputproc,
-											  itemvalue,
-											  ObjectIdGetDatum(typelem),
-											  Int32GetDatum(-1)));
-
-		if (i > 0)
-			appendStringInfo(result_str, "%s%s", fldsep, value);
-		else
-			appendStringInfo(result_str, "%s", value);
-
-		p = att_addlength(p, typlen, PointerGetDatum(p));
-		p = (char *) att_align(p, typalign);
-	}
-
-	PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data));
-}
-
 #define HEXBASE 16
 /*
  * Convert a int32 to a string containing a base 16 (hex) representation of
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 2c0c6457918ab1a8dda1da4bf883ff8b72d05dbd..479f23090fb7ecd20896ef1e60343b20d243b214 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.98 2003/06/25 03:56:31 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.99 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -718,40 +718,6 @@ get_func_rettype(Oid funcid)
 	return result;
 }
 
-/*
- * get_func_argtypes
- *		Given procedure id, return the function's argument types.
- *		Also pass back the number of arguments.
- */
-Oid *
-get_func_argtypes(Oid funcid, int *nargs)
-{
-	HeapTuple		tp;
-	Form_pg_proc	procstruct;
-	Oid			   *result = NULL;
-	int				i;
-
-	tp = SearchSysCache(PROCOID,
-						ObjectIdGetDatum(funcid),
-						0, 0, 0);
-	if (!HeapTupleIsValid(tp))
-		elog(ERROR, "Function OID %u does not exist", funcid);
-
-	procstruct = (Form_pg_proc) GETSTRUCT(tp);
-	*nargs = (int) procstruct->pronargs;
-
-	if (*nargs > 0)
-	{
-		result = (Oid *) palloc(*nargs * sizeof(Oid));
-
-		for (i = 0; i < *nargs; i++)
-			result[i] = procstruct->proargtypes[i];
-	}
-
-	ReleaseSysCache(tp);
-	return result;
-}
-
 /*
  * get_func_retset
  *		Given procedure id, return the function's proretset flag.
@@ -1124,56 +1090,6 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
 	ReleaseSysCache(tp);
 }
 
-/*
- * get_type_metadata
- *
- *		A six-fer:	given the type OID, return typlen, typbyval, typalign,
- *					typdelim, typelem, IO function Oid. The IO function
- *					returned is controlled by IOFuncSelector
- */
-void
-get_type_metadata(Oid element_type,
-					IOFuncSelector which_func,
-					int *typlen,
-					bool *typbyval,
-					char *typdelim,
-					Oid *typelem,
-					Oid *proc,
-					char *typalign)
-{
-	HeapTuple	typeTuple;
-	Form_pg_type typeStruct;
-
-	typeTuple = SearchSysCache(TYPEOID,
-							   ObjectIdGetDatum(element_type),
-							   0, 0, 0);
-	if (!HeapTupleIsValid(typeTuple))
-		elog(ERROR, "cache lookup failed for type %u", element_type);
-	typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
-
-	*typlen = typeStruct->typlen;
-	*typbyval = typeStruct->typbyval;
-	*typdelim = typeStruct->typdelim;
-	*typelem = typeStruct->typelem;
-	*typalign = typeStruct->typalign;
-	switch (which_func)
-	{
-		case IOFunc_input:
-			*proc = typeStruct->typinput;
-			break;
-		case IOFunc_output:
-			*proc = typeStruct->typoutput;
-			break;
-		case IOFunc_receive:
-			*proc = typeStruct->typreceive;
-			break;
-		case IOFunc_send:
-			*proc = typeStruct->typsend;
-			break;
-	}
-	ReleaseSysCache(typeTuple);
-}
-
 #ifdef NOT_USED
 char
 get_typalign(Oid typid)
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index d772a0a06cedf6aa2efa60c0c06c456061e53a6e..e161bd1e59365f2292d0ac14d2085ee8e5d91c08 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.69 2003/06/24 23:14:46 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.70 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1673,29 +1673,3 @@ get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum)
 
 	return exprType((Node *) nth(argnum, args));
 }
-
-/*
- * Get the OID of the function or operator
- *
- * Returns InvalidOid if information is not available
- */
-Oid
-get_fn_expr_functype(FunctionCallInfo fcinfo)
-{
-	Node   *expr;
-
-	/*
-	 * can't return anything useful if we have no FmgrInfo or if
-	 * its fn_expr node has not been initialized
-	 */
-	if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
-		return InvalidOid;
-
-	expr = fcinfo->flinfo->fn_expr;
-	if (IsA(expr, FuncExpr))
-		return ((FuncExpr *) expr)->funcid;
-	else if (IsA(expr, OpExpr))
-		return ((OpExpr *) expr)->opno;
-	else
-		return InvalidOid;
-}
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 43672f716f2d41ed4c78e9b9a310dfc69a9b8b46..4b6107ce53e89c86f862e78afca2732ab29b56a3 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -16,7 +16,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_amop.h,v 1.51 2003/06/24 23:14:46 momjian Exp $
+ * $Id: pg_amop.h,v 1.52 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	 the genbki.sh script reads this file and generates .bki
@@ -418,15 +418,6 @@ DATA(insert (	2098 3 f 2334 ));
 DATA(insert (	2098 4 f 2335 ));
 DATA(insert (	2098 5 f 2336 ));
 
-/*
- *	btree array_ops
- */
-
-DATA(insert (	 397 1 f 1072 ));
-DATA(insert (	 397 2 f 1074 ));
-DATA(insert (	 397 3 f 1070 ));
-DATA(insert (	 397 4 f 1075 ));
-DATA(insert (	 397 5 f 1073 ));
 
 /*
  *	hash index _ops
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 87553a49807cd3a197c084149b692d491182f3b4..6febdecffcd62d6b7510c6708687f8abbf047ff9 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -14,7 +14,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_amproc.h,v 1.39 2003/06/24 23:14:46 momjian Exp $
+ * $Id: pg_amproc.h,v 1.40 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -78,7 +78,6 @@ DATA(insert (	1993 3	199 ));
 
 
 /* btree */
-DATA(insert (	 397 1  382 ));
 DATA(insert (	 421 1	357 ));
 DATA(insert (	 423 1 1596 ));
 DATA(insert (	 424 1 1693 ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 828afe5aa8c4000a1efb3ff423ab76361174b1a8..88d2aac1a7da4abfdc57d55a41d01bc63c82961e 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -26,7 +26,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_opclass.h,v 1.52 2003/06/24 23:14:46 momjian Exp $
+ * $Id: pg_opclass.h,v 1.53 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -87,8 +87,6 @@ typedef FormData_pg_opclass *Form_pg_opclass;
  */
 
 DATA(insert OID =  421 (	403		abstime_ops		PGNSP PGUID  702 t 0 ));
-DATA(insert OID =  397 (	403		array_ops		PGNSP PGUID 2277 t 0 ));
-#define ARRAY_BTREE_OPS_OID 397
 DATA(insert OID =  422 (	402		bigbox_ops		PGNSP PGUID  603 f 0 ));
 DATA(insert OID =  423 (	403		bit_ops			PGNSP PGUID 1560 t 0 ));
 DATA(insert OID =  424 (	403		bool_ops		PGNSP PGUID   16 t 0 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 3a7b143c9f59eb8b174ea1918b4f77215f40a4d2..2bbef276c00f938cc143a53647e6d0b14f3c57ae 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_operator.h,v 1.116 2003/06/24 23:14:46 momjian Exp $
+ * $Id: pg_operator.h,v 1.117 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -116,15 +116,10 @@ DATA(insert OID =  96 ( "="		   PGNSP PGUID b t	23	23	16	96 518	97	97	97 521 int
 DATA(insert OID =  97 ( "<"		   PGNSP PGUID b f	23	23	16 521 525	 0	 0	 0	 0 int4lt scalarltsel scalarltjoinsel ));
 DATA(insert OID =  98 ( "="		   PGNSP PGUID b t	25	25	16	98 531 664 664 664 666 texteq eqsel eqjoinsel ));
 
-DATA(insert OID = 1070 (  "="	   PGNSP PGUID b f 2277 2277 16 1070 1071  1072 1072 1072 1073 array_eq eqsel eqjoinsel ));
-DATA(insert OID = 1071 (  "<>"	   PGNSP PGUID b f 2277 2277 16 1071 1070  0 0 0 0 array_ne neqsel neqjoinsel ));
-DATA(insert OID = 1072 (  "<"	   PGNSP PGUID b f 2277 2277 16 1073 1075  0 0 0 0 array_lt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1073 (  ">"	   PGNSP PGUID b f 2277 2277 16 1072 1074  0 0 0 0 array_gt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1074 (  "<="	   PGNSP PGUID b f 2277 2277 16 1075 1073  0 0 0 0 array_le scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1075 (  ">="	   PGNSP PGUID b f 2277 2277 16 1074 1072  0 0 0 0 array_ge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 349 (  "||"	   PGNSP PGUID b f 2277 2283 2277 0 0  0 0 0 0 array_append   -       -     ));
-DATA(insert OID = 374 (  "||"	   PGNSP PGUID b f 2283 2277 2277 0 0  0 0 0 0 array_prepend  -       -     ));
-DATA(insert OID = 375 (  "||"	   PGNSP PGUID b f 2277 2277 2277 0 0  0 0 0 0 array_cat      -       -     ));
+DATA(insert OID = 329 (  "="	   PGNSP PGUID b f 2277 2277 16   329 0 0 0	0 0 array_eq     eqsel eqjoinsel ));
+DATA(insert OID = 349 (  "||"	   PGNSP PGUID b f 2277 2283 2277   0 0 0 0	0 0 array_append   -       -     ));
+DATA(insert OID = 374 (  "||"	   PGNSP PGUID b f 2283 2277 2277   0 0 0 0	0 0 array_prepend  -       -     ));
+DATA(insert OID = 375 (  "||"	   PGNSP PGUID b f 2277 2277 2277   0 0 0 0	0 0 array_cat      -       -     ));
 
 DATA(insert OID = 352 (  "="	   PGNSP PGUID b t	28	28	16 352	 0	 0	 0	 0	 0 xideq eqsel eqjoinsel ));
 DATA(insert OID = 353 (  "="	   PGNSP PGUID b f	28	23	16	 0	 0	 0	 0	 0	 0 xideqint4 eqsel eqjoinsel ));
@@ -430,7 +425,6 @@ DATA(insert OID = 965 (  "^"	   PGNSP PGUID b f	701  701	701 0 0 0 0 0 0 dpow -
 DATA(insert OID = 966 (  "+"	   PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclinsert - - ));
 DATA(insert OID = 967 (  "-"	   PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclremove - - ));
 DATA(insert OID = 968 (  "~"	   PGNSP PGUID b f 1034 1033	 16 0 0 0 0 0 0 aclcontains - - ));
-DATA(insert OID = 974 (  "="	   PGNSP PGUID b f 1033 1033	 16 0 0 0 0 0 0 aclitemeq eqsel eqjoinsel ));
 
 /* additional geometric operators - thomas 1997-07-09 */
 DATA(insert OID =  969 (  "@@"	   PGNSP PGUID l f	0  601	600    0  0 0 0 0 0 lseg_center - - ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index d4c2f64cb7e9cf01c4288cf5ac3ff66b5f289344..bae6f644fc577cb6163b27fb37784227420c1eaf 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.306 2003/06/24 23:14:47 momjian Exp $
+ * $Id: pg_proc.h,v 1.307 2003/06/25 21:30:32 momjian Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -758,8 +758,6 @@ DATA(insert OID = 359 (  btnamecmp		   PGNSP PGUID 12 f f t f i 2 23 "19 19"	btn
 DESCR("btree less-equal-greater");
 DATA(insert OID = 360 (  bttextcmp		   PGNSP PGUID 12 f f t f i 2 23 "25 25"	bttextcmp - _null_ ));
 DESCR("btree less-equal-greater");
-DATA(insert OID = 382 (  btarraycmp		   PGNSP PGUID 12 f f t f i 2 23 "2277 2277"	btarraycmp - _null_ ));
-DESCR("btree less-equal-greater");
 
 DATA(insert OID = 361 (  lseg_distance	   PGNSP PGUID 12 f f t f i 2 701 "601 601"  lseg_distance - _null_ ));
 DESCR("distance between");
@@ -990,23 +988,14 @@ DESCR("greater-than");
 DATA(insert OID = 743 (  text_ge		   PGNSP PGUID 12 f f t f i 2 16 "25 25"	text_ge - _null_ ));
 DESCR("greater-than-or-equal");
 
+DATA(insert OID = 744 (  array_eq		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_eq - _null_ ));
+DESCR("array equal");
+
 DATA(insert OID = 745 (  current_user	   PGNSP PGUID 12 f f t f s 0 19 "" current_user - _null_ ));
 DESCR("current user name");
 DATA(insert OID = 746 (  session_user	   PGNSP PGUID 12 f f t f s 0 19 "" session_user - _null_ ));
 DESCR("session user name");
 
-DATA(insert OID = 744 (  array_eq		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_eq - _null_ ));
-DESCR("array equal");
-DATA(insert OID = 390 (  array_ne		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_ne - _null_ ));
-DESCR("array not equal");
-DATA(insert OID = 391 (  array_lt		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_lt - _null_ ));
-DESCR("array less than");
-DATA(insert OID = 392 (  array_gt		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_gt - _null_ ));
-DESCR("array greater than");
-DATA(insert OID = 393 (  array_le		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_le - _null_ ));
-DESCR("array less than or equal");
-DATA(insert OID = 396 (  array_ge		   PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_ge - _null_ ));
-DESCR("array greater than or equal");
 DATA(insert OID = 747 (  array_dims		   PGNSP PGUID 12 f f t f i 1 25 "2277" array_dims - _null_ ));
 DESCR("array dimensions");
 DATA(insert OID = 750 (  array_in		   PGNSP PGUID 12 f f t f s 3 2277 "2275 26 23"  array_in - _null_ ));
@@ -1017,18 +1006,22 @@ DATA(insert OID = 2091 (  array_lower	   PGNSP PGUID 12 f f t f i 2 23 "2277 23"
 DESCR("array lower dimension");
 DATA(insert OID = 2092 (  array_upper	   PGNSP PGUID 12 f f t f i 2 23 "2277 23" array_upper - _null_ ));
 DESCR("array upper dimension");
+DATA(insert OID = 377 (  singleton_array  PGNSP PGUID 12 f f t f i 1 2277 "2283" singleton_array - _null_ ));
+DESCR("create array from single element");
 DATA(insert OID = 378 (  array_append	   PGNSP PGUID 12 f f t f i 2 2277 "2277 2283" array_push - _null_ ));
 DESCR("append element onto end of array");
 DATA(insert OID = 379 (  array_prepend	   PGNSP PGUID 12 f f t f i 2 2277 "2283 2277" array_push - _null_ ));
 DESCR("prepend element onto front of array");
+DATA(insert OID = 380 (  array_accum	   PGNSP PGUID 12 f f f f i 2 2277 "2277 2283" array_accum - _null_ ));
+DESCR("push element onto end of array, creating array if needed");
+DATA(insert OID = 381 (  array_assign	   PGNSP PGUID 12 f f t f i 3 2277 "2277 23 2283" array_assign - _null_ ));
+DESCR("assign specific array element");
+DATA(insert OID = 382 (  array_subscript  PGNSP PGUID 12 f f t f i 2 2283 "2277 23" array_subscript - _null_ ));
+DESCR("return specific array element");
 DATA(insert OID = 383 (  array_cat	       PGNSP PGUID 12 f f t f i 2 2277 "2277 2277" array_cat - _null_ ));
 DESCR("concatenate two arrays");
 DATA(insert OID = 384  (  array_coerce	   PGNSP PGUID 12 f f t f i 1 2277 "2277" array_type_coerce - _null_ ));
 DESCR("coerce array type to another array type");
-DATA(insert OID = 394 (  string_to_array   PGNSP PGUID 12 f f t f i 2 1009 "25 25" text_to_array - _null_ ));
-DESCR("split delimited text into text[]");
-DATA(insert OID = 395 (  array_to_string   PGNSP PGUID 12 f f t f i 2 25 "2277 25" array_to_text - _null_ ));
-DESCR("concatenate array elements, using delimiter, into text");
 
 DATA(insert OID = 760 (  smgrin			   PGNSP PGUID 12 f f t f s 1 210 "2275"  smgrin - _null_ ));
 DESCR("I/O");
@@ -1329,8 +1322,6 @@ DATA(insert OID = 1036 (  aclremove		   PGNSP PGUID 12 f f t f s 2 1034 "1034 10
 DESCR("remove ACL item");
 DATA(insert OID = 1037 (  aclcontains	   PGNSP PGUID 12 f f t f s 2 16 "1034 1033"	aclcontains - _null_ ));
 DESCR("does ACL contain item?");
-DATA(insert OID = 1062 (  aclitemeq	       PGNSP PGUID 12 f f t f s 2 16 "1033 1033"	aclitem_eq - _null_ ));
-DESCR("equality operator for ACL items");
 DATA(insert OID = 1365 (  makeaclitem	   PGNSP PGUID 12 f f t f s 5 1033 "23 23 23 25 16"	makeaclitem - _null_ ));
 DESCR("make ACL item");
 DATA(insert OID = 1038 (  seteval		   PGNSP PGUID 12 f f t t v 1 23 "26"  seteval - _null_ ));
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 784b50885ea257cfece5f6d5db74e5a6a4f862bd..51844eac38bb794a2f6badd70c00b1b7bf707ad0 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,14 +11,13 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgr.h,v 1.28 2003/06/24 23:14:46 momjian Exp $
+ * $Id: fmgr.h,v 1.29 2003/06/25 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef FMGR_H
 #define FMGR_H
 
-#include "nodes/nodes.h"
 
 /*
  * All functions that can be called directly by fmgr must have this signature.
@@ -373,14 +372,14 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
 				 Datum arg6, Datum arg7, Datum arg8,
 				 Datum arg9);
 
+
 /*
  * Routines in fmgr.c
  */
 extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
-extern Oid fmgr_internal_function(const char *proname);
-extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
-extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
-extern Oid get_fn_expr_functype(FunctionCallInfo fcinfo);
+extern Oid	fmgr_internal_function(const char *proname);
+extern Oid	get_fn_expr_rettype(FunctionCallInfo fcinfo);
+extern Oid	get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
 
 /*
  * Routines in dfmgr.c
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 3756e443ff7e3e836f956178be372c961e31881a..23dff8ed622e06307ba507280b1c42a6445f0c43 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.84 2003/06/24 23:14:48 momjian Exp $
+ * $Id: primnodes.h,v 1.85 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -226,7 +226,6 @@ typedef struct Aggref
 	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
 	bool		aggstar;		/* TRUE if argument was really '*' */
 	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
-	List	   *args;			/* arguments to the aggregate */
 } Aggref;
 
 /* ----------------
@@ -359,19 +358,15 @@ typedef struct BoolExpr
 /* ----------------
  * SubLink
  *
- * A SubLink represents a subselect, or an expression, appearing in an
- * expression, and in some cases also the combining operator(s) just above
- * it.	The subLinkType indicates the form of the expression represented:
+ * A SubLink represents a subselect appearing in an expression, and in some
+ * cases also the combining operator(s) just above it.	The subLinkType
+ * indicates the form of the expression represented:
  *	EXISTS_SUBLINK		EXISTS(SELECT ...)
  *	ALL_SUBLINK			(lefthand) op ALL (SELECT ...)
  *	ANY_SUBLINK			(lefthand) op ANY (SELECT ...)
  *	MULTIEXPR_SUBLINK	(lefthand) op (SELECT ...)
  *	EXPR_SUBLINK		(SELECT with single targetlist item ...)
  *	ARRAY_SUBLINK		ARRAY(SELECT with single targetlist item ...)
- * If an expression is used in place of the subselect, it is transformed
- * into a simple "(SELECT expr)" in gram.y. This is to allow arrays to be
- * used as if they were the result of a single column subselect. If the
- * expression is scalar, it is treated as a one element array.
  * For ALL, ANY, and MULTIEXPR, the lefthand is a list of expressions of the
  * same length as the subselect's targetlist.  MULTIEXPR will *always* have
  * a list with more than one entry; if the subselect has just one target
@@ -420,8 +415,6 @@ typedef struct SubLink
 	SubLinkType subLinkType;	/* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
 	bool		useOr;			/* TRUE to combine column results with
 								 * "OR" not "AND" */
-	bool		isExpr;			/* TRUE if the subselect is really derived
-								 * from a single expression */
 	List	   *lefthand;		/* list of outer-query expressions on the
 								 * left */
 	List	   *operName;		/* originally specified operator name */
@@ -463,15 +456,6 @@ typedef struct SubPlan
 	SubLinkType subLinkType;	/* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
 	bool		useOr;			/* TRUE to combine column results with
 								 * "OR" not "AND" */
-	bool		isExpr;			/* TRUE if the subselect is really derived
-								 * from a single expression */
-	/* runtime cache for single array expressions */
-	Oid			exprtype;		/* array and element type, and other info
-								 * needed deconstruct the array */
-	Oid			elemtype;
-	int16		elmlen;
-	bool		elmbyval;
-	char		elmalign;
 	/* The combining operators, transformed to executable expressions: */
 	List	   *exprs;			/* list of OpExpr expression trees */
 	List	   *paramIds;		/* IDs of Params embedded in the above */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 946fc68c463e0fafa0e6f31c82bb677db474e86e..04add3c6f63ad04afb7acaa864776fffa606b75d 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: clauses.h,v 1.64 2003/06/24 23:14:49 momjian Exp $
+ * $Id: clauses.h,v 1.65 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,9 +28,6 @@ extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,
 extern Node *get_leftop(Expr *clause);
 extern Node *get_rightop(Expr *clause);
 
-extern Expr *make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
-									CoercionForm funcformat, List *funcargs);
-
 extern bool not_clause(Node *clause);
 extern Expr *make_notclause(Expr *notclause);
 extern Expr *get_notclausearg(Expr *notclause);
diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h
index e7c8bdb56cbeec47a9818dbeb727dfda4ec1d27c..13642f5a348026dcf2c1176eda5915a4cbe716c7 100644
--- a/src/include/parser/parse_oper.h
+++ b/src/include/parser/parse_oper.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_oper.h,v 1.26 2003/06/24 23:14:49 momjian Exp $
+ * $Id: parse_oper.h,v 1.27 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,6 @@ extern Operator ordering_oper(Oid argtype, bool noError);
 /* Convenience routines for common calls on the above */
 extern Oid	compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError);
 extern Oid	equality_oper_funcid(Oid argtype);
-extern Oid  ordering_oper_funcid(Oid argtype);
 extern Oid	ordering_oper_opid(Oid argtype);
 
 /* Extract operator OID or underlying-function OID from an Operator tuple */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 0d7761190196cf15d728a1349af40b55c2182ea2..9cf35618ad74f0ca1a5a25ec3df63c0c7575a10a 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.53 2003/06/24 23:14:49 momjian Exp $
+ * $Id: acl.h,v 1.54 2003/06/25 21:30:33 momjian Exp $
  *
  * NOTES
  *	  For backward-compatibility purposes we have to allow there
@@ -192,7 +192,6 @@ extern Datum aclinsert(PG_FUNCTION_ARGS);
 extern Datum aclremove(PG_FUNCTION_ARGS);
 extern Datum aclcontains(PG_FUNCTION_ARGS);
 extern Datum makeaclitem(PG_FUNCTION_ARGS);
-extern Datum aclitem_eq(PG_FUNCTION_ARGS);
 
 /*
  * prototypes for functions in aclchk.c
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index 5df86b1827f3bdc4eafbb509eddb78e08a9dc206..23a32d3459e909e471634d0a32d946e9aa3dd1f1 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: array.h,v 1.39 2003/06/24 23:14:49 momjian Exp $
+ * $Id: array.h,v 1.40 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,37 +32,6 @@ typedef struct
 	Oid			elemtype;		/* element type OID */
 } ArrayType;
 
-typedef struct ArrayBuildState
-{
-	MemoryContext mcontext;		/* where all the temp stuff is kept */
-	Datum	   *dvalues;		/* array of accumulated Datums */
-	/*
-	 * The allocated size of dvalues[] is always a multiple of
-	 * ARRAY_ELEMS_CHUNKSIZE
-	 */
-#define ARRAY_ELEMS_CHUNKSIZE	64
-	int			nelems;			/* number of valid Datums in dvalues[] */
-	Oid			element_type;	/* data type of the Datums */
-	int16		typlen;			/* needed info about datatype */
-	bool		typbyval;
-	char		typalign;
-} ArrayBuildState;
-
-/*
- * structure to cache type metadata needed for array manipulation
- */
-typedef struct ArrayMetaState
-{
-	Oid				element_type;
-	int				typlen;
-	bool			typbyval;
-	char			typdelim;
-	Oid				typelem;
-	Oid				typiofunc;
-	char			typalign;
-	FmgrInfo		proc;
-} ArrayMetaState;
-
 /*
  * fmgr macros for array objects
  */
@@ -117,15 +86,11 @@ extern Datum array_recv(PG_FUNCTION_ARGS);
 extern Datum array_send(PG_FUNCTION_ARGS);
 extern Datum array_length_coerce(PG_FUNCTION_ARGS);
 extern Datum array_eq(PG_FUNCTION_ARGS);
-extern Datum array_ne(PG_FUNCTION_ARGS);
-extern Datum array_lt(PG_FUNCTION_ARGS);
-extern Datum array_gt(PG_FUNCTION_ARGS);
-extern Datum array_le(PG_FUNCTION_ARGS);
-extern Datum array_ge(PG_FUNCTION_ARGS);
-extern Datum btarraycmp(PG_FUNCTION_ARGS);
 extern Datum array_dims(PG_FUNCTION_ARGS);
 extern Datum array_lower(PG_FUNCTION_ARGS);
 extern Datum array_upper(PG_FUNCTION_ARGS);
+extern Datum array_assign(PG_FUNCTION_ARGS);
+extern Datum array_subscript(PG_FUNCTION_ARGS);
 extern Datum array_type_coerce(PG_FUNCTION_ARGS);
 
 extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
@@ -159,14 +124,7 @@ extern void deconstruct_array(ArrayType *array,
 				  Oid elmtype,
 				  int elmlen, bool elmbyval, char elmalign,
 				  Datum **elemsp, int *nelemsp);
-extern ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
-										 Datum dvalue, bool disnull,
-										 Oid element_type,
-										 MemoryContext rcontext);
-extern Datum makeArrayResult(ArrayBuildState *astate,
-							 MemoryContext rcontext);
-extern Datum makeMdArrayResult(ArrayBuildState *astate, int ndims,
-							   int *dims, int *lbs, MemoryContext rcontext);
+
 
 /*
  * prototypes for functions defined in arrayutils.c
@@ -183,11 +141,12 @@ extern int	mda_next_tuple(int n, int *curr, int *span);
 /*
  * prototypes for functions defined in array_userfuncs.c
  */
+extern Datum singleton_array(PG_FUNCTION_ARGS);
 extern Datum array_push(PG_FUNCTION_ARGS);
+extern Datum array_accum(PG_FUNCTION_ARGS);
 extern Datum array_cat(PG_FUNCTION_ARGS);
 
-extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo,
-										 Oid element_type,
+extern ArrayType *create_singleton_array(Oid element_type,
 										 Datum element,
 										 int ndims);
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 43e174722b3e6ccca4fc2bc44aae3ffeb95fc367..958021eb1f0df4072280d526937ce117db7db38e 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.221 2003/06/24 23:14:49 momjian Exp $
+ * $Id: builtins.h,v 1.222 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -530,8 +530,6 @@ extern bool SplitIdentifierString(char *rawstring, char separator,
 					  List **namelist);
 extern Datum replace_text(PG_FUNCTION_ARGS);
 extern Datum split_text(PG_FUNCTION_ARGS);
-extern Datum text_to_array(PG_FUNCTION_ARGS);
-extern Datum array_to_text(PG_FUNCTION_ARGS);
 extern Datum to_hex32(PG_FUNCTION_ARGS);
 extern Datum to_hex64(PG_FUNCTION_ARGS);
 extern Datum md5_text(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index e9de9f02c3f3229e56df3e95ce2016994bd64eba..d7d3bba9d977218e780b7656744e1796400c7d85 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.73 2003/06/25 03:56:31 momjian Exp $
+ * $Id: lsyscache.h,v 1.74 2003/06/25 21:30:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,15 +15,6 @@
 
 #include "access/htup.h"
 
-/* I/O function selector for system_cache_lookup */
-typedef enum IOFuncSelector
-{
-	IOFunc_input,
-	IOFunc_output,
-	IOFunc_receive,
-	IOFunc_send
-} IOFuncSelector;
-
 extern bool op_in_opclass(Oid opno, Oid opclass);
 extern bool op_requires_recheck(Oid opno, Oid opclass);
 extern Oid	get_opclass_member(Oid opclass, int16 strategy);
@@ -50,7 +41,6 @@ extern RegProcedure get_oprrest(Oid opno);
 extern RegProcedure get_oprjoin(Oid opno);
 extern char *get_func_name(Oid funcid);
 extern Oid	get_func_rettype(Oid funcid);
-extern Oid *get_func_argtypes(Oid funcid, int *nargs);
 extern bool get_func_retset(Oid funcid);
 extern bool func_strict(Oid funcid);
 extern char func_volatile(Oid funcid);
@@ -66,14 +56,6 @@ extern bool get_typbyval(Oid typid);
 extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
 extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
 					 char *typalign);
-extern void get_type_metadata(Oid element_type,
-								IOFuncSelector which_func,
-								int *typlen,
-								bool *typbyval,
-								char *typdelim,
-								Oid *typelem,
-								Oid *proc,
-								char *typalign);
 extern char get_typstorage(Oid typid);
 extern int32 get_typtypmod(Oid typid);
 extern Node *get_typdefault(Oid typid);
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index ff175700cf4b41a9388b87955dd86557dccfef02..ffa849045a83d1ed94a8f4341be9782b30c3f954 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.238 2003/06/25 10:44:21 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.239 2003/06/25 21:30:33 momjian Exp $ */
 
 /* Copyright comment */
 %{
@@ -4599,7 +4599,7 @@ type_declaration: S_TYPEDEF
 			    $3.type_enum != ECPGt_char &&
 	        	    $3.type_enum != ECPGt_unsigned_char &&
 			    atoi(this->type->type_index) >= 0)
-				mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
+				mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
 
 			types = this;
 		}
@@ -5419,7 +5419,7 @@ ECPGTypedef: TYPE_P
 					$5.type_enum != ECPGt_char &&
 					$5.type_enum != ECPGt_unsigned_char &&
 					atoi(this->type->type_index) >= 0)
-					mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
+					mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
 
 				types = this;
 			}
@@ -5486,7 +5486,7 @@ ECPGVar: SQL_VAR
 
 					default:
 						if (atoi(length) >= 0)
-							mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
+							mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
 
 						if (atoi(dimension) < 0)
 							type = ECPGmake_simple_type($5.type_enum, make_str("1"));
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 80406bbccc5124115b194c0d5c71098e104dcb05..5f2dd86bb55f15fedccc6e005aa36cd255b2118a 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -504,7 +504,7 @@ ECPGfree_type(struct ECPGtype * type)
 				switch (type->u.element->type)
 				{
 					case ECPGt_array:
-						yyerror("internal error, found multidimensional array\n");
+						yyerror("internal error, found multi-dimensional array\n");
 						break;
 					case ECPGt_struct:
 					case ECPGt_union:
diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c
index 9fa2ec8a6c9a3756975e9f8d93fb1c6cdcc295a6..be96e18c0c5488d38bc3fe5ba0eafb644d39436c 100644
--- a/src/interfaces/ecpg/preproc/variable.c
+++ b/src/interfaces/ecpg/preproc/variable.c
@@ -436,7 +436,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 	if (atoi(type_index) >= 0)
 	{
 		if (atoi(*length) >= 0)
-			mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
+			mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
 
 		*length = type_index;
 	}
@@ -444,7 +444,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 	if (atoi(type_dimension) >= 0)
 	{
 		if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
-			mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
+			mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
 
 		if (atoi(*dimension) >= 0)
 			*length = *dimension;
@@ -463,10 +463,10 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 		mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
 
 	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
-		mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
+		mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
 
 	if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
-		mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
+		mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
 
 	switch (type_enum)
 	{
@@ -480,7 +480,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 			}
 
 			if (atoi(*length) >= 0)
-				mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for structures");
+				mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for structures");
 
 			break;
 		case ECPGt_varchar:
@@ -525,7 +525,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 			}
 
 			if (atoi(*length) >= 0)
-				mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for simple data types");
+				mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for simple data types");
 
 			break;
 	}
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index c5f638bd4653e23c9e98ac7cbb0d4614e7c3cfa6..617cf09a9a00a1f6b36339e019a60a7c3c317443 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -178,13 +178,19 @@ SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
 (1 row)
 
 -- functions
-SELECT array_append(array[42], 6) AS "{42,6}";
+SELECT singleton_array(42) AS "{42}";
+ {42} 
+------
+ {42}
+(1 row)
+
+SELECT array_append(singleton_array(42), 6) AS "{42,6}";
  {42,6} 
 --------
  {42,6}
 (1 row)
 
-SELECT array_prepend(6, array[42]) AS "{6,42}";
+SELECT array_prepend(6, singleton_array(42)) AS "{6,42}";
  {6,42} 
 --------
  {6,42}
@@ -208,6 +214,24 @@ SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}";
  {{3,4},{5,6},{1,2}}
 (1 row)
 
+SELECT array_subscript(n, 2) AS "1.2" FROM arrtest2;
+ 1.2 
+-----
+ 1.2
+(1 row)
+
+SELECT array_assign(n, 2, 9.99) AS "{1.1,9.99,1.3}" FROM arrtest2;
+ {1.1,9.99,1.3} 
+----------------
+ {1.1,9.99,1.3}
+(1 row)
+
+SELECT array_subscript(array_assign(n, 2, 9.99), 2) AS "9.99" FROM arrtest2;
+ 9.99 
+------
+ 9.99
+(1 row)
+
 -- operators
 SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];
        a       
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index e39044e40acabe1ba64f02c0be6b0ffd4219b5fc..82eff24125df262f27466880cf96b500991134d1 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -130,11 +130,15 @@ SELECT ARRAY[ARRAY['hello'],ARRAY['world']];
 SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
 
 -- functions
-SELECT array_append(array[42], 6) AS "{42,6}";
-SELECT array_prepend(6, array[42]) AS "{6,42}";
+SELECT singleton_array(42) AS "{42}";
+SELECT array_append(singleton_array(42), 6) AS "{42,6}";
+SELECT array_prepend(6, singleton_array(42)) AS "{6,42}";
 SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}";
 SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}";
 SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}";
+SELECT array_subscript(n, 2) AS "1.2" FROM arrtest2;
+SELECT array_assign(n, 2, 9.99) AS "{1.1,9.99,1.3}" FROM arrtest2;
+SELECT array_subscript(array_assign(n, 2, 9.99), 2) AS "9.99" FROM arrtest2;
 
 -- operators
 SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];