Fix up text concatenation so that it accepts all the reasonable cases that
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 6 Jun 2007 23:00:50 +0000 (23:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 6 Jun 2007 23:00:50 +0000 (23:00 +0000)
were accepted by prior Postgres releases.  This takes care of the loose end
left by the preceding patch to downgrade implicit casts-to-text.  To avoid
breaking desirable behavior for array concatenation, introduce a new
polymorphic pseudo-type "anynonarray" --- the added concatenation operators
are actually text || anynonarray and anynonarray || text.

22 files changed:
doc/src/sgml/datatype.sgml
doc/src/sgml/extend.sgml
doc/src/sgml/func.sgml
doc/src/sgml/plpgsql.sgml
doc/src/sgml/xfunc.sgml
src/backend/catalog/pg_proc.c
src/backend/executor/functions.c
src/backend/parser/parse_agg.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_func.c
src/backend/utils/adt/pseudotypes.c
src/backend/utils/adt/xml.c
src/backend/utils/fmgr/funcapi.c
src/include/catalog/catversion.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/utils/builtins.h
src/include/utils/lsyscache.h
src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/text.out
src/test/regress/sql/text.sql

index 3802aa24dff97bb096e682b091aeea1626e50602..c64b040e45792c0db4a669ef97443632f8d0c4f9 100644 (file)
@@ -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>
index bb5834e74a9a570df3343cb85ca0f1497584bbeb..28bdfb853221937b96296dbbff1ecacc3f49e985 100644 (file)
@@ -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>
    </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
      <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.
      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>
 
index c2f3371dc48039262e2ee1b51951a8faa2b31884..387c4e81c8fc65896fd62f784f701a981c0f3dba 100644 (file)
@@ -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>
    <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>
        <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>
index c1f57ddf4f8d2f8a9c27bc43a1358c4e014078f0..d14519b61333c8888e8164099aa02d772733b9b2 100644 (file)
@@ -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
index 553b33e17326c14089539996d071ccc89ca9b5fb..de7eed5a6db7cf1e8f1483245de1c7ea793f32e0 100644 (file)
@@ -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
index 26c5eb75e3e751cdd8dd44a40c4b752717468152..9db3ef4edbb601ea84170b0a1b400fad9984835e 100644 (file)
@@ -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;
index 9ad1391612362d2015c1713944cd0a782a489c0a..8beea3f53968cca06ea466a408b9c9c1c5c345ce 100644 (file)
@@ -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 */
 
index 1409285cda45a1d52de15064a7000fa9b57f24ef..1afc55bc9a7b9e138a0dfc5883083e8995d4e308 100644 (file)
@@ -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.
index 98cc6691124c0be2a3bb1832044ab1bdc9eb1120..abc056858119b5f29b0ab22d40bbd056b8d5a727 100644 (file)
@@ -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
index 5e7a1cccffa92ab6b519f7a3d181aaef39a0666b..393fa6c41ac43b727c6cab99af96023f237e4a7d 100644 (file)
@@ -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,
index fc9f3324827111127dc43fe9f03fd034c6aa1b30..248bcfa3058f352682814f1a66b45a230a5808c0 100644 (file)
@@ -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).
  */
index f9fd48db66144128c4a862ab2a871260c51b05aa..2e84fac1d70276211fae2d75f9de96b041dd2e9a 100644 (file)
@@ -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;
index c32130c3ec132de04714436cf0d69f7a327c4b43..53a505858b1f8aa79958e2485ffdf1648e471f5f 100644 (file)
@@ -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;
index ec6d516713932127a254f8a72f1cee581bd84287..8dfca8ecc7255a7d5e5450344e9e10c9aa4ffe5b 100644 (file)
@@ -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
index 6848b274e4521185f539d53251ac8a59b266d0d8..e3b2910eb22f2ffddad2352dfb6f65016109b3f4 100644 (file)
@@ -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 ));
index c656c7a6717f5cc00c7c121ce164acaba1c2e28a..49c1429e377033b46585d6b7d0c43982f54f7ccc 100644 (file)
@@ -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 */ 
index 0d9ff0d6eeff4da905f28cfb635a07eca77b938c..753487348b4efe18a63bb3599cc366291092d6f3 100644 (file)
@@ -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)
 
 /*
index 5ff4fe738fc631116a95d3f81c03de239c31a197..faf8b6926216df88ca4502a063434441fdb8d353 100644 (file)
@@ -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);
index 25782e322e9845a9703c9f09c07353f2d2edffb0..0a326cb9ba9f24401ab417d21ed4b1f921254209 100644 (file)
@@ -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')
 
index 74918c890ca528b368ddd1a3779da256870e58d9..a547d174c1bff6b415c5a44d51592efe8468e927 100644 (file)
@@ -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;
index 2d732f6844aed01a363be0ec0c6c76505927e3c5..08d002fe71ecadf89a7e04c4c79898d075165146 100644 (file)
@@ -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.
index 60daf7077c656661e4370f77b4abff120c9b563a..b739e56e2d69ff06c420bbf1239baabcb64aa75f 100644 (file)
@@ -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;