diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3802aa24dff97bb096e682b091aeea1626e50602..c64b040e45792c0db4a669ef97443632f8d0c4f9 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.203 2007/06/01 23:40:18 neilc Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.204 2007/06/06 23:00:35 tgl Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
@@ -3676,12 +3676,16 @@ SELECT * FROM pg_attribute
     <primary>any</primary>
    </indexterm>
 
+   <indexterm zone="datatype-pseudo">
+    <primary>anyelement</primary>
+   </indexterm>
+
    <indexterm zone="datatype-pseudo">
     <primary>anyarray</primary>
    </indexterm>
 
    <indexterm zone="datatype-pseudo">
-    <primary>anyelement</primary>
+    <primary>anynonarray</primary>
    </indexterm>
 
    <indexterm zone="datatype-pseudo">
@@ -3760,6 +3764,12 @@ SELECT * FROM pg_attribute
         <xref linkend="datatype-enum">).</entry>
        </row>
 
+       <row>
+        <entry><type>anynonarray</></entry>
+        <entry>Indicates that a function accepts any non-array data type
+        (see <xref linkend="extend-types-polymorphic">).</entry>
+       </row>
+
        <row>
         <entry><type>cstring</></entry>
         <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
@@ -3813,7 +3823,7 @@ SELECT * FROM pg_attribute
     only <type>void</> and <type>record</> as a result type (plus
     <type>trigger</> when the function is used as a trigger).  Some also
     support polymorphic functions using the types <type>anyarray</>,
-    <type>anyelement</> and <type>anyenum</>.
+    <type>anyelement</>, <type>anyenum</>, and <type>anynonarray</>.
    </para>
 
    <para>
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index bb5834e74a9a570df3343cb85ca0f1497584bbeb..28bdfb853221937b96296dbbff1ecacc3f49e985 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.34 2007/04/02 03:49:36 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.35 2007/06/06 23:00:35 tgl Exp $ -->
 
  <chapter id="extend">
   <title>Extending <acronym>SQL</acronym></title>
@@ -193,8 +193,8 @@
    </indexterm>
 
     <para>
-     Three pseudo-types of special interest are <type>anyelement</>,
-     <type>anyarray</>, and <type>anyenum</>,
+     Four pseudo-types of special interest are <type>anyelement</>,
+     <type>anyarray</>, <type>anynonarray</>, and <type>anyenum</>,
      which are collectively called <firstterm>polymorphic types</>.
      Any function declared using these types is said to be
      a <firstterm>polymorphic function</>.  A polymorphic function can
@@ -216,6 +216,9 @@
      <type>anyelement</type>, the actual array type in the
      <type>anyarray</type> positions must be an array whose elements are
      the same type appearing in the <type>anyelement</type> positions.
+     <type>anynonarray</> is treated exactly the same as <type>anyelement</>,
+     but adds the additional constraint that the actual type must not be
+     an array type.
      <type>anyenum</> is treated exactly the same as <type>anyelement</>,
      but adds the additional constraint that the actual type must
      be an enum type.
@@ -242,6 +245,15 @@
      is that a function declared as <literal>f(anyarray) returns anyenum</>
      will only accept arrays of enum types.
     </para>
+
+    <para>
+     Note that <type>anynonarray</> and <type>anyenum</> do not represent
+     separate type variables; they are the same type as
+     <type>anyelement</type>, just with an additional constraint.  For
+     example, declaring a function as <literal>f(anyelement, anyenum)</>
+     is equivalent to declaring it as <literal>f(anyenum, anyenum)</>:
+     both actual arguments have to be the same enum type.
+    </para>
    </sect2>
   </sect1>
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c2f3371dc48039262e2ee1b51951a8faa2b31884..387c4e81c8fc65896fd62f784f701a981c0f3dba 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.381 2007/05/30 18:13:29 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.382 2007/06/06 23:00:35 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -986,24 +986,36 @@
    <para>
     This section describes functions and operators for examining and
     manipulating string values.  Strings in this context include values
-    of all the types <type>character</type>, <type>character
-     varying</type>, and <type>text</type>.  Unless otherwise noted, all
+    of the types <type>character</type>, <type>character varying</type>,
+    and <type>text</type>.  Unless otherwise noted, all
     of the functions listed below work on all of these types, but be
-    wary of potential effects of the automatic padding when using the
-    <type>character</type> type.  Generally, the functions described
-    here also work on data of non-string types by converting that data
-    to a string representation first.  Some functions also exist
+    wary of potential effects of automatic space-padding when using the
+    <type>character</type> type.  Some functions also exist
     natively for the bit-string types.
    </para>
 
    <para>
-    <acronym>SQL</acronym> defines some string functions with a special syntax where
-    certain key words rather than commas are used to separate the
+    <acronym>SQL</acronym> defines some string functions with a special syntax
+    wherein certain key words rather than commas are used to separate the
     arguments.  Details are in <xref linkend="functions-string-sql">.
     These functions are also implemented using the regular syntax for
     function invocation.  (See <xref linkend="functions-string-other">.)
    </para>
 
+   <note>
+    <para>
+     Before <productname>PostgreSQL</productname> 8.3, these functions would
+     silently accept values of several non-string data types as well, due to
+     the presence of implicit coercions from those data types to
+     <type>text</>.  Those coercions have been removed because they frequently
+     caused surprising behaviors.  However, the string concatenation operator
+     (<literal>||</>) still accepts non-string input, so long as at least one
+     input is of a string type, as shown in <xref
+     linkend="functions-string-sql">.  For other cases, insert an explicit
+     coercion to <type>text</> if you need to duplicate the previous behavior.
+    </para>
+   </note>
+
    <indexterm>
     <primary>bit_length</primary>
    </indexterm>
@@ -1064,6 +1076,22 @@
        <entry><literal>PostgreSQL</literal></entry>
       </row>
 
+      <row>
+       <entry>
+        <literal><parameter>string</parameter> <literal>||</literal>
+        <parameter>non-string</parameter></literal>
+        or
+        <literal><parameter>non-string</parameter> <literal>||</literal>
+        <parameter>string</parameter></literal>
+       </entry>
+       <entry> <type>text</type> </entry>
+       <entry>
+        String concatenation with one non-string input
+       </entry>
+       <entry><literal>'Value: ' || 42</literal></entry>
+       <entry><literal>Value: 42</literal></entry>
+      </row>
+
       <row>
        <entry><literal><function>bit_length</function>(<parameter>string</parameter>)</literal></entry>
        <entry><type>int</type></entry>
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index c1f57ddf4f8d2f8a9c27bc43a1358c4e014078f0..d14519b61333c8888e8164099aa02d772733b9b2 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.109 2007/04/29 01:21:08 neilc Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.110 2007/06/06 23:00:36 tgl Exp $ -->
 
 <chapter id="plpgsql"> 
   <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@@ -210,8 +210,8 @@ $$ LANGUAGE plpgsql;
     <para>
      <application>PL/pgSQL</> functions can also be declared to accept
      and return the polymorphic types
-     <type>anyelement</type>, <type>anyarray</type>, and <type>anyenum</>.
-     The actual
+     <type>anyelement</type>, <type>anyarray</type>, <type>anynonarray</type>,
+     and <type>anyenum</>.  The actual
      data types handled by a polymorphic function can vary from call to
      call, as discussed in <xref linkend="extend-types-polymorphic">.
      An example is shown in <xref linkend="plpgsql-declaration-aliases">.
@@ -700,7 +700,7 @@ $$ LANGUAGE plpgsql;
      <para>
       When the return type of a <application>PL/pgSQL</application>
       function is declared as a polymorphic type (<type>anyelement</type>,
-      <type>anyarray</type>, or <type>anyenum</>),
+      <type>anyarray</type>, <type>anynonarray</type>, or <type>anyenum</>),
       a special parameter <literal>$0</literal>
       is created.  Its data type is the actual return type of the function,
       as deduced from the actual input types (see <xref
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 553b33e17326c14089539996d071ccc89ca9b5fb..de7eed5a6db7cf1e8f1483245de1c7ea793f32e0 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.127 2007/04/02 03:49:37 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.128 2007/06/06 23:00:36 tgl Exp $ -->
 
  <sect1 id="xfunc">
   <title>User-Defined Functions</title>
@@ -718,7 +718,8 @@ SELECT name, listchildren(name) FROM nodes;
     <para>
      <acronym>SQL</acronym> functions can be declared to accept and
      return the polymorphic types <type>anyelement</type>,
-     <type>anyarray</type>, and <type>anyenum</type>.  See <xref
+     <type>anyarray</type>, <type>anynonarray</type>, and
+     <type>anyenum</type>.  See <xref
      linkend="extend-types-polymorphic"> for a more detailed
      explanation of polymorphic functions. Here is a polymorphic
      function <function>make_array</function> that builds up an array
@@ -2831,7 +2832,8 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
     <para>
      C-language functions can be declared to accept and
      return the polymorphic types
-     <type>anyelement</type>, <type>anyarray</type>, and <type>anyenum</type>.
+     <type>anyelement</type>, <type>anyarray</type>, <type>anynonarray</type>,
+     and <type>anyenum</type>.
      See <xref linkend="extend-types-polymorphic"> for a more detailed explanation
      of polymorphic functions. When function arguments or return types
      are defined as polymorphic types, the function author cannot know
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 26c5eb75e3e751cdd8dd44a40c4b752717468152..9db3ef4edbb601ea84170b0a1b400fad9984835e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.144 2007/04/02 03:49:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.145 2007/06/06 23:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -147,6 +147,7 @@ ProcedureCreate(const char *procedureName,
 		{
 			case ANYARRAYOID:
 			case ANYELEMENTOID:
+			case ANYNONARRAYOID:
 			case ANYENUMOID:
 				genericInParam = true;
 				break;
@@ -170,6 +171,7 @@ ProcedureCreate(const char *procedureName,
 			{
 				case ANYARRAYOID:
 				case ANYELEMENTOID:
+				case ANYNONARRAYOID:
 				case ANYENUMOID:
 					genericOutParam = true;
 					break;
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 9ad1391612362d2015c1713944cd0a782a489c0a..8beea3f53968cca06ea466a408b9c9c1c5c345ce 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.116 2007/04/27 22:05:47 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.117 2007/06/06 23:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -849,9 +849,9 @@ ShutdownSQLFunction(Datum arg)
  * to be sure that the user is returning the type he claims.
  *
  * For a polymorphic function the passed rettype must be the actual resolved
- * output type of the function; we should never see ANYARRAY, ANYENUM or
- * ANYELEMENT as rettype.  (This means we can't check the type during function
- * definition of a polymorphic function.)
+ * output type of the function; we should never see a polymorphic pseudotype
+ * such as ANYELEMENT as rettype.  (This means we can't check the type during
+ * function definition of a polymorphic function.)
  *
  * This function returns true if the sql function returns the entire tuple
  * result of its final SELECT, and false otherwise.  Note that because we
@@ -874,6 +874,8 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
 	char		fn_typtype;
 	Oid			restype;
 
+	AssertArg(!IsPolymorphicType(rettype));
+
 	if (junkFilter)
 		*junkFilter = NULL;		/* default result */
 
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 1409285cda45a1d52de15064a7000fa9b57f24ef..1afc55bc9a7b9e138a0dfc5883083e8995d4e308 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.77 2007/02/01 19:10:27 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.78 2007/06/06 23:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,7 +363,7 @@ check_ungrouped_columns_walker(Node *node,
  *
  * agg_input_types, agg_state_type, agg_result_type identify the input,
  * transition, and result types of the aggregate.  These should all be
- * resolved to actual types (ie, none should ever be ANYARRAY or ANYELEMENT).
+ * resolved to actual types (ie, none should ever be ANYELEMENT etc).
  *
  * transfn_oid and finalfn_oid identify the funcs to be called; the latter
  * may be InvalidOid.
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 98cc6691124c0be2a3bb1832044ab1bdc9eb1120..abc056858119b5f29b0ab22d40bbd056b8d5a727 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.154 2007/06/05 21:31:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.155 2007/06/06 23:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -133,6 +133,7 @@ coerce_type(ParseState *pstate, Node *node,
 	}
 	if (targetTypeId == ANYOID ||
 		targetTypeId == ANYELEMENTOID ||
+		targetTypeId == ANYNONARRAYOID ||
 		(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
 		(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
 	{
@@ -141,12 +142,12 @@ coerce_type(ParseState *pstate, Node *node,
 		 *
 		 * Note: by returning the unmodified node here, we are saying that
 		 * it's OK to treat an UNKNOWN constant as a valid input for a
-		 * function accepting ANY or ANYELEMENT.  This should be all right,
-		 * since an UNKNOWN value is still a perfectly valid Datum.  However
-		 * an UNKNOWN value is definitely *not* an array, and so we mustn't
-		 * accept it for ANYARRAY.  (Instead, we will call anyarray_in below,
-		 * which will produce an error.)  Likewise, UNKNOWN input is no good
-		 * for ANYENUM.
+		 * function accepting ANY, ANYELEMENT, or ANYNONARRAY.  This should be
+		 * all right, since an UNKNOWN value is still a perfectly valid Datum.
+		 * However an UNKNOWN value is definitely *not* an array, and so we
+		 * mustn't accept it for ANYARRAY.  (Instead, we will call anyarray_in
+		 * below, which will produce an error.)  Likewise, UNKNOWN input is no
+		 * good for ANYENUM.
 		 *
 		 * NB: we do NOT want a RelabelType here.
 		 */
@@ -1078,9 +1079,13 @@ coerce_to_common_type(ParseState *pstate, Node *node,
  * 4) ANYENUM is treated the same as ANYELEMENT except that if it is used
  *	  (alone or in combination with plain ANYELEMENT), we add the extra
  *	  condition that the ANYELEMENT type must be an enum.
+ * 5) ANYNONARRAY is treated the same as ANYELEMENT except that if it is used,
+ *	  we add the extra condition that the ANYELEMENT type must not be an array.
+ *	  (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
+ *	  is an extra restriction if not.)
  *
- * If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
- * or ANYARRAY argument, assume it is okay.
+ * If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
+ * argument, assume it is okay.
  *
  * If an input is of type ANYARRAY (ie, we know it's an array, but not
  * what element type), we will accept it as a match to an argument declared
@@ -1100,21 +1105,26 @@ check_generic_type_consistency(Oid *actual_arg_types,
 	Oid			array_typeid = InvalidOid;
 	Oid			array_typelem;
 	bool		have_anyelement = false;
+	bool		have_anynonarray = false;
 	bool		have_anyenum = false;
 
 	/*
-	 * Loop through the arguments to see if we have any that are ANYARRAY or
-	 * ANYELEMENT. If so, require the actual types to be self-consistent
+	 * Loop through the arguments to see if we have any that are polymorphic.
+	 * If so, require the actual types to be consistent.
 	 */
 	for (j = 0; j < nargs; j++)
 	{
+		Oid			decl_type = declared_arg_types[j];
 		Oid			actual_type = actual_arg_types[j];
 
-		if (declared_arg_types[j] == ANYELEMENTOID ||
-			declared_arg_types[j] == ANYENUMOID)
+		if (decl_type == ANYELEMENTOID ||
+			decl_type == ANYNONARRAYOID ||
+			decl_type == ANYENUMOID)
 		{
 			have_anyelement = true;
-			if (declared_arg_types[j] == ANYENUMOID)
+			if (decl_type == ANYNONARRAYOID)
+				have_anynonarray = true;
+			else if (decl_type == ANYENUMOID)
 				have_anyenum = true;
 			if (actual_type == UNKNOWNOID)
 				continue;
@@ -1122,7 +1132,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
 				return false;
 			elem_typeid = actual_type;
 		}
-		else if (declared_arg_types[j] == ANYARRAYOID)
+		else if (decl_type == ANYARRAYOID)
 		{
 			if (actual_type == UNKNOWNOID)
 				continue;
@@ -1161,6 +1171,13 @@ check_generic_type_consistency(Oid *actual_arg_types,
 		}
 	}
 
+	if (have_anynonarray)
+	{
+		/* require the element type to not be an array */
+		if (type_is_array(elem_typeid))
+			return false;
+	}
+
 	if (have_anyenum)
 	{
 		/* require the element type to be an enum */
@@ -1177,7 +1194,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
  *		Make sure a polymorphic function is legally callable, and
  *		deduce actual argument and result types.
  *
- * If ANYARRAY, ANYELEMENT, or ANYENUM is used for a function's arguments or
+ * If any polymorphic pseudotype is used in a function's arguments or
  * return type, we make sure the actual data types are consistent with
  * each other. The argument consistency rules are shown above for
  * check_generic_type_consistency().
@@ -1211,6 +1228,10 @@ check_generic_type_consistency(Oid *actual_arg_types,
  * 7) ANYENUM is treated the same as ANYELEMENT except that if it is used
  *	  (alone or in combination with plain ANYELEMENT), we add the extra
  *	  condition that the ANYELEMENT type must be an enum.
+ * 8) ANYNONARRAY is treated the same as ANYELEMENT except that if it is used,
+ *	  we add the extra condition that the ANYELEMENT type must not be an array.
+ *	  (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
+ *	  is an extra restriction if not.)
  */
 Oid
 enforce_generic_type_consistency(Oid *actual_arg_types,
@@ -1225,22 +1246,28 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	Oid			array_typeid = InvalidOid;
 	Oid			array_typelem;
 	bool		have_anyelement = (rettype == ANYELEMENTOID ||
+								   rettype == ANYNONARRAYOID ||
 								   rettype == ANYENUMOID);
+	bool		have_anynonarray = (rettype == ANYNONARRAYOID);
 	bool		have_anyenum = (rettype == ANYENUMOID);
 
 	/*
-	 * Loop through the arguments to see if we have any that are ANYARRAY or
-	 * ANYELEMENT. If so, require the actual types to be self-consistent
+	 * Loop through the arguments to see if we have any that are polymorphic.
+	 * If so, require the actual types to be consistent.
 	 */
 	for (j = 0; j < nargs; j++)
 	{
+		Oid			decl_type = declared_arg_types[j];
 		Oid			actual_type = actual_arg_types[j];
 
-		if (declared_arg_types[j] == ANYELEMENTOID ||
-			declared_arg_types[j] == ANYENUMOID)
+		if (decl_type == ANYELEMENTOID ||
+			decl_type == ANYNONARRAYOID ||
+			decl_type == ANYENUMOID)
 		{
 			have_generics = have_anyelement = true;
-			if (declared_arg_types[j] == ANYENUMOID)
+			if (decl_type == ANYNONARRAYOID)
+				have_anynonarray = true;
+			else if (decl_type == ANYENUMOID)
 				have_anyenum = true;
 			if (actual_type == UNKNOWNOID)
 			{
@@ -1256,7 +1283,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 								   format_type_be(actual_type))));
 			elem_typeid = actual_type;
 		}
-		else if (declared_arg_types[j] == ANYARRAYOID)
+		else if (decl_type == ANYARRAYOID)
 		{
 			have_generics = true;
 			if (actual_type == UNKNOWNOID)
@@ -1326,6 +1353,16 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 				 errmsg("could not determine polymorphic type because input has type \"unknown\"")));
 	}
 
+	if (have_anynonarray)
+	{
+		/* require the element type to not be an array */
+		if (type_is_array(elem_typeid))
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("type matched to anynonarray is an array type: %s",
+							format_type_be(elem_typeid))));
+	}
+
 	if (have_anyenum)
 	{
 		/* require the element type to be an enum */
@@ -1343,15 +1380,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	{
 		for (j = 0; j < nargs; j++)
 		{
+			Oid			decl_type = declared_arg_types[j];
 			Oid			actual_type = actual_arg_types[j];
 
 			if (actual_type != UNKNOWNOID)
 				continue;
 
-			if (declared_arg_types[j] == ANYELEMENTOID ||
-				declared_arg_types[j] == ANYENUMOID)
+			if (decl_type == ANYELEMENTOID ||
+				decl_type == ANYNONARRAYOID ||
+				decl_type == ANYENUMOID)
 				declared_arg_types[j] = elem_typeid;
-			else if (declared_arg_types[j] == ANYARRAYOID)
+			else if (decl_type == ANYARRAYOID)
 			{
 				if (!OidIsValid(array_typeid))
 				{
@@ -1383,7 +1422,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	}
 
 	/* if we return ANYELEMENT use the appropriate argument type */
-	if (rettype == ANYELEMENTOID || rettype == ANYENUMOID)
+	if (rettype == ANYELEMENTOID ||
+		rettype == ANYNONARRAYOID ||
+		rettype == ANYENUMOID)
 		return elem_typeid;
 
 	/* we don't return a generic type; send back the original return type */
@@ -1423,6 +1464,7 @@ resolve_generic_type(Oid declared_type,
 			return context_actual_type;
 		}
 		else if (context_declared_type == ANYELEMENTOID ||
+				 context_declared_type == ANYNONARRAYOID ||
 				 context_declared_type == ANYENUMOID)
 		{
 			/* Use the array type corresponding to actual type */
@@ -1436,7 +1478,9 @@ resolve_generic_type(Oid declared_type,
 			return array_typeid;
 		}
 	}
-	else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
+	else if (declared_type == ANYELEMENTOID ||
+			 declared_type == ANYNONARRAYOID ||
+			 declared_type == ANYENUMOID)
 	{
 		if (context_declared_type == ANYARRAYOID)
 		{
@@ -1451,6 +1495,7 @@ resolve_generic_type(Oid declared_type,
 			return array_typelem;
 		}
 		else if (context_declared_type == ANYELEMENTOID ||
+				 context_declared_type == ANYNONARRAYOID ||
 				 context_declared_type == ANYENUMOID)
 		{
 			/* Use the actual type; it doesn't matter if array or not */
@@ -1564,6 +1609,7 @@ TypeCategory(Oid inType)
 		case (INTERNALOID):
 		case (OPAQUEOID):
 		case (ANYELEMENTOID):
+		case (ANYNONARRAYOID):
 		case (ANYENUMOID):
 			result = GENERIC_TYPE;
 			break;
@@ -1707,7 +1753,12 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
 
 	/* Also accept any array type as coercible to ANYARRAY */
 	if (targettype == ANYARRAYOID)
-		if (get_element_type(srctype) != InvalidOid)
+		if (type_is_array(srctype))
+			return true;
+
+	/* Also accept any non-array type as coercible to ANYNONARRAY */
+	if (targettype == ANYNONARRAYOID)
+		if (!type_is_array(srctype))
 			return true;
 
 	/* Also accept any enum type as coercible to ANYENUM */
@@ -1863,22 +1914,6 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
 			}
 		}
 
-		/*
-		 * If we still haven't found a possibility, check for enums,
-		 * and retry looking for a cast to or from ANYENUM.  But don't
-		 * mistakenly conclude that ANYENUM-to-some-enum-type is a
-		 * trivial cast.
-		 */
-		if (result == COERCION_PATH_NONE)
-		{
-			if (type_is_enum(sourceTypeId))
-				result = find_coercion_pathway(targetTypeId, ANYENUMOID,
-											   ccontext, funcid);
-			else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId))
-				result = find_coercion_pathway(ANYENUMOID, sourceTypeId,
-											   ccontext, funcid);
-		}
-
 		/*
 		 * If we still haven't found a possibility, consider automatic casting
 		 * using I/O functions.  We allow assignment casts to textual types
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 5e7a1cccffa92ab6b519f7a3d181aaef39a0666b..393fa6c41ac43b727c6cab99af96023f237e4a7d 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.196 2007/06/05 21:31:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.197 2007/06/06 23:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -227,9 +227,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 	}
 
 	/*
-	 * enforce consistency with ANYARRAY and ANYELEMENT argument and return
-	 * types, possibly adjusting return type or declared_arg_types (which will
-	 * be used as the cast destination by make_fn_arguments)
+	 * enforce consistency with polymorphic argument and return types,
+	 * possibly adjusting return type or declared_arg_types (which will be
+	 * used as the cast destination by make_fn_arguments)
 	 */
 	rettype = enforce_generic_type_consistency(actual_arg_types,
 											   declared_arg_types,
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index fc9f3324827111127dc43fe9f03fd034c6aa1b30..248bcfa3058f352682814f1a66b45a230a5808c0 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.19 2007/04/02 03:49:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.20 2007/06/06 23:00:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -347,6 +347,32 @@ anyelement_out(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();			/* keep compiler quiet */
 }
 
+/*
+ * anynonarray_in		- input routine for pseudo-type ANYNONARRAY.
+ */
+Datum
+anynonarray_in(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type anynonarray")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * anynonarray_out		- output routine for pseudo-type ANYNONARRAY.
+ */
+Datum
+anynonarray_out(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot display a value of type anynonarray")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
 /*
  * shell_in		- input routine for "shell" types (those not yet filled in).
  */
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index f9fd48db66144128c4a862ab2a871260c51b05aa..2e84fac1d70276211fae2d75f9de96b041dd2e9a 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.43 2007/05/21 17:10:29 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.44 2007/06/06 23:00:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1481,7 +1481,7 @@ map_sql_value_to_xml_value(Datum value, Oid type)
 
 	initStringInfo(&buf);
 
-	if (is_array_type(type))
+	if (type_is_array(type))
 	{
 		int i;
 		ArrayType *array;
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index c32130c3ec132de04714436cf0d69f7a327c4b43..53a505858b1f8aa79958e2485ffdf1648e471f5f 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -7,7 +7,7 @@
  * Copyright (c) 2002-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.34 2007/04/02 03:49:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.35 2007/06/06 23:00:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,8 +193,8 @@ shutdown_MultiFuncCall(Datum arg)
  * only when we couldn't resolve the actual rowtype for lack of information.
  *
  * The other hard case that this handles is resolution of polymorphism.
- * We will never return ANYELEMENT, ANYARRAY or ANYENUM, either as a scalar
- * result type or as a component of a rowtype.
+ * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
+ * as a scalar result type or as a component of a rowtype.
  *
  * This function is relatively expensive --- in a function returning set,
  * try to call it only the first time through.
@@ -389,9 +389,9 @@ internal_get_result_type(Oid funcid,
 
 /*
  * Given the result tuple descriptor for a function with OUT parameters,
- * replace any polymorphic columns (ANYELEMENT/ANYARRAY/ANYENUM) with correct
- * data types deduced from the input arguments.	Returns TRUE if able to deduce
- * all types, FALSE if not.
+ * replace any polymorphic columns (ANYELEMENT etc) with correct data types
+ * deduced from the input arguments. Returns TRUE if able to deduce all types,
+ * FALSE if not.
  */
 static bool
 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
@@ -401,6 +401,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 	int			nargs = declared_args->dim1;
 	bool		have_anyelement_result = false;
 	bool		have_anyarray_result = false;
+	bool		have_anynonarray = false;
 	bool		have_anyenum = false;
 	Oid			anyelement_type = InvalidOid;
 	Oid			anyarray_type = InvalidOid;
@@ -417,6 +418,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 			case ANYARRAYOID:
 				have_anyarray_result = true;
 				break;
+			case ANYNONARRAYOID:
+				have_anyelement_result = true;
+				have_anynonarray = true;
+				break;
 			case ANYENUMOID:
 				have_anyelement_result = true;
 				have_anyenum = true;
@@ -440,6 +445,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 		switch (declared_args->values[i])
 		{
 			case ANYELEMENTOID:
+			case ANYNONARRAYOID:
 			case ANYENUMOID:
 				if (!OidIsValid(anyelement_type))
 					anyelement_type = get_call_expr_argtype(call_expr, i);
@@ -467,7 +473,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 											 anyelement_type,
 											 ANYELEMENTOID);
 
-	/* Check for enum if needed */
+	/* Enforce ANYNONARRAY if needed */
+	if (have_anynonarray && type_is_array(anyelement_type))
+		return false;
+
+	/* Enforce ANYENUM if needed */
 	if (have_anyenum && !type_is_enum(anyelement_type))
 		return false;
 
@@ -477,6 +487,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 		switch (tupdesc->attrs[i]->atttypid)
 		{
 			case ANYELEMENTOID:
+			case ANYNONARRAYOID:
 			case ANYENUMOID:
 				TupleDescInitEntry(tupdesc, i + 1,
 								   NameStr(tupdesc->attrs[i]->attname),
@@ -500,11 +511,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 }
 
 /*
- * Given the declared argument types and modes for a function,
- * replace any polymorphic types (ANYELEMENT/ANYARRAY/ANYENUM) with correct
- * data types deduced from the input arguments.	Returns TRUE if able to deduce
- * all types, FALSE if not.  This is the same logic as
- * resolve_polymorphic_tupdesc, but with a different argument representation.
+ * Given the declared argument types and modes for a function, replace any
+ * polymorphic types (ANYELEMENT etc) with correct data types deduced from the
+ * input arguments.  Returns TRUE if able to deduce all types, FALSE if not.
+ * This is the same logic as resolve_polymorphic_tupdesc, but with a different
+ * argument representation.
  *
  * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
  */
@@ -528,6 +539,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 		switch (argtypes[i])
 		{
 			case ANYELEMENTOID:
+			case ANYNONARRAYOID:
 			case ANYENUMOID:
 				if (argmode == PROARGMODE_OUT)
 					have_anyelement_result = true;
@@ -583,7 +595,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 											 anyelement_type,
 											 ANYELEMENTOID);
 
-	/* XXX do we need to enforce ANYENUM here?  I think not */
+	/* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
 
 	/* And finally replace the output column types as needed */
 	for (i = 0; i < numargs; i++)
@@ -591,6 +603,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 		switch (argtypes[i])
 		{
 			case ANYELEMENTOID:
+			case ANYNONARRAYOID:
 			case ANYENUMOID:
 				argtypes[i] = anyelement_type;
 				break;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index ec6d516713932127a254f8a72f1cee581bd84287..8dfca8ecc7255a7d5e5450344e9e10c9aa4ffe5b 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.410 2007/06/05 21:31:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.411 2007/06/06 23:00:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200706051
+#define CATALOG_VERSION_NO	200706061
 
 #endif
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 6848b274e4521185f539d53251ac8a59b266d0d8..e3b2910eb22f2ffddad2352dfb6f65016109b3f4 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.152 2007/05/08 18:56:47 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.153 2007/06/06 23:00:41 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -701,7 +701,7 @@ DATA(insert OID = 1793 (  "#"	  PGNSP PGUID b f f 1560 1560 1560 1793	 0 bitxor
 DATA(insert OID = 1794 (  "~"	  PGNSP PGUID l f f    0 1560 1560	  0  0 bitnot - - ));
 DATA(insert OID = 1795 (  "<<"	  PGNSP PGUID b f f 1560   23 1560	  0  0 bitshiftleft - - ));
 DATA(insert OID = 1796 (  ">>"	  PGNSP PGUID b f f 1560   23 1560	  0  0 bitshiftright - - ));
-DATA(insert OID = 1797 (  "||"	  PGNSP PGUID b f f 1560 1560 1560	  0  0 bitcat - - ));
+DATA(insert OID = 1797 (  "||"	  PGNSP PGUID b f f 1562 1562 1562	  0  0 bitcat - - ));
 
 DATA(insert OID = 1800 (  "+"	   PGNSP PGUID b f f 1083 1186 1083	 1849 0 time_pl_interval - - ));
 DATA(insert OID = 1801 (  "-"	   PGNSP PGUID b f f 1083 1186 1083	 0	0 time_mi_interval - - ));
@@ -875,6 +875,10 @@ DATA(insert OID = 2750 (  "&&"	   PGNSP PGUID b f f 2277 2277	16 2750  0 arrayov
 DATA(insert OID = 2751 (  "@>"	   PGNSP PGUID b f f 2277 2277	16 2752  0 arraycontains contsel contjoinsel ));
 DATA(insert OID = 2752 (  "<@"	   PGNSP PGUID b f f 2277 2277	16 2751  0 arraycontained contsel contjoinsel ));
 
+/* capturing operators to preserve pre-8.3 behavior of text concatenation */
+DATA(insert OID = 2779 (  "||"	   PGNSP PGUID b f f 25 2776	25	 0 0 textanycat - - ));
+DATA(insert OID = 2780 (  "||"	   PGNSP PGUID b f f 2776 25	25	 0 0 anytextcat - - ));
+
 /* obsolete names for contains/contained-by operators; remove these someday */
 DATA(insert OID = 2860 (  "@"	   PGNSP PGUID b f f 604 604	16 2861  0 poly_contained contsel contjoinsel ));
 DATA(insert OID = 2861 (  "~"	   PGNSP PGUID b f f 604 604	16 2860  0 poly_contain contsel contjoinsel ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c656c7a6717f5cc00c7c121ce164acaba1c2e28a..49c1429e377033b46585d6b7d0c43982f54f7ccc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.458 2007/06/05 21:31:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.459 2007/06/06 23:00:41 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -1425,7 +1425,7 @@ DATA(insert OID = 1156 (  timestamptz_ge   PGNSP PGUID 12 1 0 f f t f i 2 16 "11
 DESCR("greater-than-or-equal");
 DATA(insert OID = 1157 (  timestamptz_gt   PGNSP PGUID 12 1 0 f f t f i 2 16 "1184 1184" _null_ _null_ _null_ timestamp_gt - _null_ ));
 DESCR("greater-than");
-DATA(insert OID = 1158 (  to_timestamp	   PGNSP PGUID 14 1 0 f f t f i 1 1184 "701" _null_ _null_ _null_ "select (''epoch''::timestamptz + $1 * ''1 second''::interval)" - _null_ ));
+DATA(insert OID = 1158 (  to_timestamp	   PGNSP PGUID 14 1 0 f f t f i 1 1184 "701" _null_ _null_ _null_ "select (''epoch''::pg_catalog.timestamptz + $1 * ''1 second''::pg_catalog.interval)" - _null_ ));
 DESCR("convert UNIX epoch to timestamptz");
 DATA(insert OID = 1159 (  timezone		   PGNSP PGUID 12 1 0 f f t f i 2 1114 "25 1184" _null_ _null_ _null_  timestamptz_zone - _null_ ));
 DESCR("adjust timestamp to new time zone");
@@ -1509,7 +1509,7 @@ DESCR("adjust interval precision");
 
 DATA(insert OID = 1215 (  obj_description	PGNSP PGUID 14 100 0 f f t f s 2	25 "26 19" _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0" - _null_ ));
 DESCR("get description for object id and catalog name");
-DATA(insert OID = 1216 (  col_description	PGNSP PGUID 14 100 0 f f t f s 2	25 "26 23" _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = ''pg_catalog.pg_class''::regclass and objsubid = $2" - _null_ ));
+DATA(insert OID = 1216 (  col_description	PGNSP PGUID 14 100 0 f f t f s 2	25 "26 23" _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = ''pg_catalog.pg_class''::pg_catalog.regclass and objsubid = $2" - _null_ ));
 DESCR("get description for table column");
 DATA(insert OID = 1993 ( shobj_description	PGNSP PGUID 14 100 0 f f t f s 2	25 "26 19" _null_ _null_ _null_ "select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP)" - _null_ ));
 DESCR("get description for object id and shared catalog name");
@@ -1722,7 +1722,7 @@ DESCR("less-equal-greater");
 DATA(insert OID = 1359 (  timestamptz	   PGNSP PGUID 12 1 0 f f t f i 2 1184 "1082 1266" _null_ _null_ _null_ datetimetz_timestamptz - _null_ ));
 DESCR("convert date and time with time zone to timestamp with time zone");
 
-DATA(insert OID = 1364 (  time			   PGNSP PGUID 14 1 0 f f t f s 1 1083 "702" _null_ _null_ _null_  "select cast(cast($1 as timestamp without time zone) as time)" - _null_ ));
+DATA(insert OID = 1364 (  time			   PGNSP PGUID 14 1 0 f f t f s 1 1083 "702" _null_ _null_ _null_  "select cast(cast($1 as timestamp without time zone) as pg_catalog.time)" - _null_ ));
 DESCR("convert abstime to time");
 
 DATA(insert OID = 1367 (  character_length	PGNSP PGUID 12 1 0 f f t f i 1	23 "1042" _null_ _null_ _null_	bpcharlen - _null_ ));
@@ -2328,7 +2328,7 @@ DATA(insert OID = 1677 (  bitshiftleft		PGNSP PGUID 12 1 0 f f t f i 2 1560 "156
 DESCR("bitwise left shift");
 DATA(insert OID = 1678 (  bitshiftright		PGNSP PGUID 12 1 0 f f t f i 2 1560 "1560 23" _null_ _null_ _null_	bitshiftright - _null_ ));
 DESCR("bitwise right shift");
-DATA(insert OID = 1679 (  bitcat			PGNSP PGUID 12 1 0 f f t f i 2 1560 "1560 1560" _null_ _null_ _null_	bitcat - _null_ ));
+DATA(insert OID = 1679 (  bitcat			PGNSP PGUID 12 1 0 f f t f i 2 1562 "1562 1562" _null_ _null_ _null_	bitcat - _null_ ));
 DESCR("bitwise concatenation");
 DATA(insert OID = 1680 (  substring			PGNSP PGUID 12 1 0 f f t f i 3 1560 "1560 23 23" _null_ _null_ _null_ bitsubstr - _null_ ));
 DESCR("return portion of bitstring");
@@ -2981,6 +2981,11 @@ DESCR("adjust time precision");
 DATA(insert OID = 1969 (  timetz		   PGNSP PGUID 12 1 0 f f t f i 2 1266 "1266 23" _null_ _null_ _null_ timetz_scale - _null_ ));
 DESCR("adjust time with time zone precision");
 
+DATA(insert OID = 2003 (  textanycat	   PGNSP PGUID 14 1 0 f f t f i 2 25 "25 2776" _null_ _null_ _null_ "select $1 || $2::pg_catalog.text" - _null_ ));
+DESCR("concatenate");
+DATA(insert OID = 2004 (  anytextcat	   PGNSP PGUID 14 1 0 f f t f i 2 25 "2776 25" _null_ _null_ _null_ "select $1::pg_catalog.text || $2" - _null_ ));
+DESCR("concatenate");
+
 DATA(insert OID = 2005 (  bytealike		   PGNSP PGUID 12 1 0 f f t f i 2 16 "17 17" _null_ _null_ _null_ bytealike - _null_ ));
 DESCR("matches LIKE expression");
 DATA(insert OID = 2006 (  byteanlike	   PGNSP PGUID 12 1 0 f f t f i 2 16 "17 17" _null_ _null_ _null_ byteanlike - _null_ ));
@@ -3489,6 +3494,10 @@ DATA(insert OID = 2597 (  domain_in			PGNSP PGUID 12 1 0 f f f f v 3 2276 "2275
 DESCR("I/O");
 DATA(insert OID = 2598 (  domain_recv		PGNSP PGUID 12 1 0 f f f f v 3 2276 "2281 26 23" _null_ _null_ _null_ domain_recv - _null_ ));
 DESCR("I/O");
+DATA(insert OID = 2777 (  anynonarray_in	PGNSP PGUID 12 1 0 f f t f i 1 2776 "2275" _null_ _null_ _null_ anynonarray_in - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2778 (  anynonarray_out	PGNSP PGUID 12 1 0 f f t f i 1 2275 "2776" _null_ _null_ _null_ anynonarray_out - _null_ ));
+DESCR("I/O");
 
 /* cryptographic */
 DATA(insert OID =  2311 (  md5	   PGNSP PGUID 12 1 0 f f t f i 1 25 "25" _null_ _null_ _null_	md5_text - _null_ ));
@@ -4054,7 +4063,7 @@ DESCR("map database contents and structure to XML and XML Schema");
 
 DATA(insert OID = 2931 (  xpath      PGNSP PGUID 12 1 0 f f t f i 3 143 "25 142 1009" _null_ _null_ _null_ xpath - _null_ ));
 DESCR("evaluate XPath expression, with namespaces support");
-DATA(insert OID = 2932 (  xpath      PGNSP PGUID 14 1 0 f f t f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::_text)" - _null_ ));
+DATA(insert OID = 2932 (  xpath      PGNSP PGUID 14 1 0 f f t f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::pg_catalog.text[])" - _null_ ));
 DESCR("evaluate XPath expression");
 
 /* uuid */ 
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 0d9ff0d6eeff4da905f28cfb635a07eca77b938c..753487348b4efe18a63bb3599cc366291092d6f3 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.184 2007/05/12 00:54:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.185 2007/06/06 23:00:43 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -575,6 +575,8 @@ DATA(insert OID = 2282 ( opaque			PGNSP PGUID  4 t p t \054 0 0 0 opaque_in opaq
 #define OPAQUEOID		2282
 DATA(insert OID = 2283 ( anyelement		PGNSP PGUID  4 t p t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ ));
 #define ANYELEMENTOID	2283
+DATA(insert OID = 2776 ( anynonarray	PGNSP PGUID  4 t p t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+#define ANYNONARRAYOID	2776
 DATA(insert OID = 3500 ( anyenum		PGNSP PGUID  4 t p t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
 #define ANYENUMOID		3500
 
@@ -592,6 +594,7 @@ DATA(insert OID = 3500 ( anyenum		PGNSP PGUID  4 t p t \054 0 0 0 anyenum_in any
 #define IsPolymorphicType(typid)  \
 	((typid) == ANYELEMENTOID || \
 	 (typid) == ANYARRAYOID || \
+	 (typid) == ANYNONARRAYOID || \
 	 (typid) == ANYENUMOID)
 
 /*
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 5ff4fe738fc631116a95d3f81c03de239c31a197..faf8b6926216df88ca4502a063434441fdb8d353 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.295 2007/06/05 21:31:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.296 2007/06/06 23:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -458,6 +458,8 @@ extern Datum anyarray_in(PG_FUNCTION_ARGS);
 extern Datum anyarray_out(PG_FUNCTION_ARGS);
 extern Datum anyarray_recv(PG_FUNCTION_ARGS);
 extern Datum anyarray_send(PG_FUNCTION_ARGS);
+extern Datum anynonarray_in(PG_FUNCTION_ARGS);
+extern Datum anynonarray_out(PG_FUNCTION_ARGS);
 extern Datum anyenum_in(PG_FUNCTION_ARGS);
 extern Datum anyenum_out(PG_FUNCTION_ARGS);
 extern Datum void_in(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 25782e322e9845a9703c9f09c07353f2d2edffb0..0a326cb9ba9f24401ab417d21ed4b1f921254209 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.118 2007/04/02 03:49:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.119 2007/06/06 23:00:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,7 +130,7 @@ extern char *get_namespace_name(Oid nspid);
 extern Oid	get_roleid(const char *rolname);
 extern Oid	get_roleid_checked(const char *rolname);
 
-#define is_array_type(typid)  (get_element_type(typid) != InvalidOid)
+#define type_is_array(typid)  (get_element_type(typid) != InvalidOid)
 
 #define TypeIsToastable(typid)	(get_typstorage(typid) != 'p')
 
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 74918c890ca528b368ddd1a3779da256870e58d9..a547d174c1bff6b415c5a44d51592efe8468e927 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.114 2007/04/02 03:49:41 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.115 2007/06/06 23:00:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -480,7 +480,7 @@ do_compile(FunctionCallInfo fcinfo,
 				{
 					if (rettypeid == ANYARRAYOID)
 						rettypeid = INT4ARRAYOID;
-					else
+					else		/* ANYELEMENT or ANYNONARRAY */
 						rettypeid = INT4OID;
 					/* XXX what could we use for ANYENUM? */
 				}
@@ -2027,6 +2027,7 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
 			switch (argtypes[i])
 			{
 				case ANYELEMENTOID:
+				case ANYNONARRAYOID:
 				case ANYENUMOID:				/* XXX dubious */
 					argtypes[i] = INT4OID;
 					break;
diff --git a/src/test/regress/expected/text.out b/src/test/regress/expected/text.out
index 2d732f6844aed01a363be0ec0c6c76505927e3c5..08d002fe71ecadf89a7e04c4c79898d075165146 100644
--- a/src/test/regress/expected/text.out
+++ b/src/test/regress/expected/text.out
@@ -23,3 +23,31 @@ SELECT '' AS two, * FROM TEXT_TBL;
      | hi de ho neighbor
 (2 rows)
 
+-- As of 8.3 we have removed most implicit casts to text, so that for example
+-- this no longer works:
+select length(42);
+ERROR:  function length(integer) does not exist
+LINE 1: select length(42);
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+-- But as a special exception for usability's sake, we still allow implicit
+-- casting to text in concatenations, so long as the other input is text or
+-- an unknown literal.  So these work:
+select 'four: '::text || 2+2;
+ ?column? 
+----------
+ four: 4
+(1 row)
+
+select 'four: ' || 2+2;
+ ?column? 
+----------
+ four: 4
+(1 row)
+
+-- but not this:
+select 3 || 4.0;
+ERROR:  operator does not exist: integer || numeric
+LINE 1: select 3 || 4.0;
+                 ^
+HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
diff --git a/src/test/regress/sql/text.sql b/src/test/regress/sql/text.sql
index 60daf7077c656661e4370f77b4abff120c9b563a..b739e56e2d69ff06c420bbf1239baabcb64aa75f 100644
--- a/src/test/regress/sql/text.sql
+++ b/src/test/regress/sql/text.sql
@@ -13,3 +13,18 @@ INSERT INTO TEXT_TBL VALUES ('hi de ho neighbor');
 
 SELECT '' AS two, * FROM TEXT_TBL;
 
+-- As of 8.3 we have removed most implicit casts to text, so that for example
+-- this no longer works:
+
+select length(42);
+
+-- But as a special exception for usability's sake, we still allow implicit
+-- casting to text in concatenations, so long as the other input is text or
+-- an unknown literal.  So these work:
+
+select 'four: '::text || 2+2;
+select 'four: ' || 2+2;
+
+-- but not this:
+
+select 3 || 4.0;