Commit 2d4db367 authored by Tom Lane's avatar Tom Lane

Fix up text concatenation so that it accepts all the reasonable cases that

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.
parent 7dab4f75
<!-- $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"> <chapter id="datatype">
<title id="datatype-title">Data Types</title> <title id="datatype-title">Data Types</title>
...@@ -3676,12 +3676,16 @@ SELECT * FROM pg_attribute ...@@ -3676,12 +3676,16 @@ SELECT * FROM pg_attribute
<primary>any</primary> <primary>any</primary>
</indexterm> </indexterm>
<indexterm zone="datatype-pseudo">
<primary>anyelement</primary>
</indexterm>
<indexterm zone="datatype-pseudo"> <indexterm zone="datatype-pseudo">
<primary>anyarray</primary> <primary>anyarray</primary>
</indexterm> </indexterm>
<indexterm zone="datatype-pseudo"> <indexterm zone="datatype-pseudo">
<primary>anyelement</primary> <primary>anynonarray</primary>
</indexterm> </indexterm>
<indexterm zone="datatype-pseudo"> <indexterm zone="datatype-pseudo">
...@@ -3760,6 +3764,12 @@ SELECT * FROM pg_attribute ...@@ -3760,6 +3764,12 @@ SELECT * FROM pg_attribute
<xref linkend="datatype-enum">).</entry> <xref linkend="datatype-enum">).</entry>
</row> </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> <row>
<entry><type>cstring</></entry> <entry><type>cstring</></entry>
<entry>Indicates that a function accepts or returns a null-terminated C string.</entry> <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
...@@ -3813,7 +3823,7 @@ SELECT * FROM pg_attribute ...@@ -3813,7 +3823,7 @@ SELECT * FROM pg_attribute
only <type>void</> and <type>record</> as a result type (plus only <type>void</> and <type>record</> as a result type (plus
<type>trigger</> when the function is used as a trigger). Some also <type>trigger</> when the function is used as a trigger). Some also
support polymorphic functions using the types <type>anyarray</>, support polymorphic functions using the types <type>anyarray</>,
<type>anyelement</> and <type>anyenum</>. <type>anyelement</>, <type>anyenum</>, and <type>anynonarray</>.
</para> </para>
<para> <para>
......
<!-- $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"> <chapter id="extend">
<title>Extending <acronym>SQL</acronym></title> <title>Extending <acronym>SQL</acronym></title>
...@@ -193,8 +193,8 @@ ...@@ -193,8 +193,8 @@
</indexterm> </indexterm>
<para> <para>
Three pseudo-types of special interest are <type>anyelement</>, Four pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, and <type>anyenum</>, <type>anyarray</>, <type>anynonarray</>, and <type>anyenum</>,
which are collectively called <firstterm>polymorphic types</>. which are collectively called <firstterm>polymorphic types</>.
Any function declared using these types is said to be Any function declared using these types is said to be
a <firstterm>polymorphic function</>. A polymorphic function can a <firstterm>polymorphic function</>. A polymorphic function can
...@@ -216,6 +216,9 @@ ...@@ -216,6 +216,9 @@
<type>anyelement</type>, the actual array type in the <type>anyelement</type>, the actual array type in the
<type>anyarray</type> positions must be an array whose elements are <type>anyarray</type> positions must be an array whose elements are
the same type appearing in the <type>anyelement</type> positions. 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</>, <type>anyenum</> is treated exactly the same as <type>anyelement</>,
but adds the additional constraint that the actual type must but adds the additional constraint that the actual type must
be an enum type. be an enum type.
...@@ -242,6 +245,15 @@ ...@@ -242,6 +245,15 @@
is that a function declared as <literal>f(anyarray) returns anyenum</> is that a function declared as <literal>f(anyarray) returns anyenum</>
will only accept arrays of enum types. will only accept arrays of enum types.
</para> </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> </sect2>
</sect1> </sect1>
......
<!-- $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"> <chapter id="functions">
<title>Functions and Operators</title> <title>Functions and Operators</title>
...@@ -986,24 +986,36 @@ ...@@ -986,24 +986,36 @@
<para> <para>
This section describes functions and operators for examining and This section describes functions and operators for examining and
manipulating string values. Strings in this context include values manipulating string values. Strings in this context include values
of all the types <type>character</type>, <type>character of the types <type>character</type>, <type>character varying</type>,
varying</type>, and <type>text</type>. Unless otherwise noted, all and <type>text</type>. Unless otherwise noted, all
of the functions listed below work on all of these types, but be of the functions listed below work on all of these types, but be
wary of potential effects of the automatic padding when using the wary of potential effects of automatic space-padding when using the
<type>character</type> type. Generally, the functions described <type>character</type> type. Some functions also exist
here also work on data of non-string types by converting that data
to a string representation first. Some functions also exist
natively for the bit-string types. natively for the bit-string types.
</para> </para>
<para> <para>
<acronym>SQL</acronym> defines some string functions with a special syntax where <acronym>SQL</acronym> defines some string functions with a special syntax
certain key words rather than commas are used to separate the wherein certain key words rather than commas are used to separate the
arguments. Details are in <xref linkend="functions-string-sql">. arguments. Details are in <xref linkend="functions-string-sql">.
These functions are also implemented using the regular syntax for These functions are also implemented using the regular syntax for
function invocation. (See <xref linkend="functions-string-other">.) function invocation. (See <xref linkend="functions-string-other">.)
</para> </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> <indexterm>
<primary>bit_length</primary> <primary>bit_length</primary>
</indexterm> </indexterm>
...@@ -1064,6 +1076,22 @@ ...@@ -1064,6 +1076,22 @@
<entry><literal>PostgreSQL</literal></entry> <entry><literal>PostgreSQL</literal></entry>
</row> </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> <row>
<entry><literal><function>bit_length</function>(<parameter>string</parameter>)</literal></entry> <entry><literal><function>bit_length</function>(<parameter>string</parameter>)</literal></entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
......
<!-- $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"> <chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title> <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
...@@ -210,8 +210,8 @@ $$ LANGUAGE plpgsql; ...@@ -210,8 +210,8 @@ $$ LANGUAGE plpgsql;
<para> <para>
<application>PL/pgSQL</> functions can also be declared to accept <application>PL/pgSQL</> functions can also be declared to accept
and return the polymorphic types and return the polymorphic types
<type>anyelement</type>, <type>anyarray</type>, and <type>anyenum</>. <type>anyelement</type>, <type>anyarray</type>, <type>anynonarray</type>,
The actual and <type>anyenum</>. The actual
data types handled by a polymorphic function can vary from call to data types handled by a polymorphic function can vary from call to
call, as discussed in <xref linkend="extend-types-polymorphic">. call, as discussed in <xref linkend="extend-types-polymorphic">.
An example is shown in <xref linkend="plpgsql-declaration-aliases">. An example is shown in <xref linkend="plpgsql-declaration-aliases">.
...@@ -700,7 +700,7 @@ $$ LANGUAGE plpgsql; ...@@ -700,7 +700,7 @@ $$ LANGUAGE plpgsql;
<para> <para>
When the return type of a <application>PL/pgSQL</application> When the return type of a <application>PL/pgSQL</application>
function is declared as a polymorphic type (<type>anyelement</type>, 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> a special parameter <literal>$0</literal>
is created. Its data type is the actual return type of the function, is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see <xref as deduced from the actual input types (see <xref
......
<!-- $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"> <sect1 id="xfunc">
<title>User-Defined Functions</title> <title>User-Defined Functions</title>
...@@ -718,7 +718,8 @@ SELECT name, listchildren(name) FROM nodes; ...@@ -718,7 +718,8 @@ SELECT name, listchildren(name) FROM nodes;
<para> <para>
<acronym>SQL</acronym> functions can be declared to accept and <acronym>SQL</acronym> functions can be declared to accept and
return the polymorphic types <type>anyelement</type>, 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 linkend="extend-types-polymorphic"> for a more detailed
explanation of polymorphic functions. Here is a polymorphic explanation of polymorphic functions. Here is a polymorphic
function <function>make_array</function> that builds up an array function <function>make_array</function> that builds up an array
...@@ -2831,7 +2832,8 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer, ...@@ -2831,7 +2832,8 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
<para> <para>
C-language functions can be declared to accept and C-language functions can be declared to accept and
return the polymorphic types 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 See <xref linkend="extend-types-polymorphic"> for a more detailed explanation
of polymorphic functions. When function arguments or return types of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know are defined as polymorphic types, the function author cannot know
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -147,6 +147,7 @@ ProcedureCreate(const char *procedureName,
{ {
case ANYARRAYOID: case ANYARRAYOID:
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
genericInParam = true; genericInParam = true;
break; break;
...@@ -170,6 +171,7 @@ ProcedureCreate(const char *procedureName, ...@@ -170,6 +171,7 @@ ProcedureCreate(const char *procedureName,
{ {
case ANYARRAYOID: case ANYARRAYOID:
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
genericOutParam = true; genericOutParam = true;
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -849,9 +849,9 @@ ShutdownSQLFunction(Datum arg)
* to be sure that the user is returning the type he claims. * to be sure that the user is returning the type he claims.
* *
* For a polymorphic function the passed rettype must be the actual resolved * For a polymorphic function the passed rettype must be the actual resolved
* output type of the function; we should never see ANYARRAY, ANYENUM or * output type of the function; we should never see a polymorphic pseudotype
* ANYELEMENT as rettype. (This means we can't check the type during function * such as ANYELEMENT as rettype. (This means we can't check the type during
* definition of a polymorphic function.) * function definition of a polymorphic function.)
* *
* This function returns true if the sql function returns the entire tuple * This function returns true if the sql function returns the entire tuple
* result of its final SELECT, and false otherwise. Note that because we * 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, ...@@ -874,6 +874,8 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
char fn_typtype; char fn_typtype;
Oid restype; Oid restype;
AssertArg(!IsPolymorphicType(rettype));
if (junkFilter) if (junkFilter)
*junkFilter = NULL; /* default result */ *junkFilter = NULL; /* default result */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -363,7 +363,7 @@ check_ungrouped_columns_walker(Node *node,
* *
* agg_input_types, agg_state_type, agg_result_type identify the input, * agg_input_types, agg_state_type, agg_result_type identify the input,
* transition, and result types of the aggregate. These should all be * 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 * transfn_oid and finalfn_oid identify the funcs to be called; the latter
* may be InvalidOid. * may be InvalidOid.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -133,6 +133,7 @@ coerce_type(ParseState *pstate, Node *node,
} }
if (targetTypeId == ANYOID || if (targetTypeId == ANYOID ||
targetTypeId == ANYELEMENTOID || targetTypeId == ANYELEMENTOID ||
targetTypeId == ANYNONARRAYOID ||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) || (targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID)) (targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
{ {
...@@ -141,12 +142,12 @@ coerce_type(ParseState *pstate, Node *node, ...@@ -141,12 +142,12 @@ coerce_type(ParseState *pstate, Node *node,
* *
* Note: by returning the unmodified node here, we are saying that * 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 * it's OK to treat an UNKNOWN constant as a valid input for a
* function accepting ANY or ANYELEMENT. This should be all right, * function accepting ANY, ANYELEMENT, or ANYNONARRAY. This should be
* since an UNKNOWN value is still a perfectly valid Datum. However * all right, since an UNKNOWN value is still a perfectly valid Datum.
* an UNKNOWN value is definitely *not* an array, and so we mustn't * However an UNKNOWN value is definitely *not* an array, and so we
* accept it for ANYARRAY. (Instead, we will call anyarray_in below, * mustn't accept it for ANYARRAY. (Instead, we will call anyarray_in
* which will produce an error.) Likewise, UNKNOWN input is no good * below, which will produce an error.) Likewise, UNKNOWN input is no
* for ANYENUM. * good for ANYENUM.
* *
* NB: we do NOT want a RelabelType here. * NB: we do NOT want a RelabelType here.
*/ */
...@@ -1078,9 +1079,13 @@ coerce_to_common_type(ParseState *pstate, Node *node, ...@@ -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 * 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 * (alone or in combination with plain ANYELEMENT), we add the extra
* condition that the ANYELEMENT type must be an enum. * 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 * If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
* or ANYARRAY argument, assume it is okay. * argument, assume it is okay.
* *
* If an input is of type ANYARRAY (ie, we know it's an array, but not * 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 * 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, ...@@ -1100,21 +1105,26 @@ check_generic_type_consistency(Oid *actual_arg_types,
Oid array_typeid = InvalidOid; Oid array_typeid = InvalidOid;
Oid array_typelem; Oid array_typelem;
bool have_anyelement = false; bool have_anyelement = false;
bool have_anynonarray = false;
bool have_anyenum = false; bool have_anyenum = false;
/* /*
* Loop through the arguments to see if we have any that are ANYARRAY or * Loop through the arguments to see if we have any that are polymorphic.
* ANYELEMENT. If so, require the actual types to be self-consistent * If so, require the actual types to be consistent.
*/ */
for (j = 0; j < nargs; j++) for (j = 0; j < nargs; j++)
{ {
Oid decl_type = declared_arg_types[j];
Oid actual_type = actual_arg_types[j]; Oid actual_type = actual_arg_types[j];
if (declared_arg_types[j] == ANYELEMENTOID || if (decl_type == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID) decl_type == ANYNONARRAYOID ||
decl_type == ANYENUMOID)
{ {
have_anyelement = true; have_anyelement = true;
if (declared_arg_types[j] == ANYENUMOID) if (decl_type == ANYNONARRAYOID)
have_anynonarray = true;
else if (decl_type == ANYENUMOID)
have_anyenum = true; have_anyenum = true;
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
continue; continue;
...@@ -1122,7 +1132,7 @@ check_generic_type_consistency(Oid *actual_arg_types, ...@@ -1122,7 +1132,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
return false; return false;
elem_typeid = actual_type; elem_typeid = actual_type;
} }
else if (declared_arg_types[j] == ANYARRAYOID) else if (decl_type == ANYARRAYOID)
{ {
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
continue; continue;
...@@ -1161,6 +1171,13 @@ check_generic_type_consistency(Oid *actual_arg_types, ...@@ -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) if (have_anyenum)
{ {
/* require the element type to be an enum */ /* require the element type to be an enum */
...@@ -1177,7 +1194,7 @@ check_generic_type_consistency(Oid *actual_arg_types, ...@@ -1177,7 +1194,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
* Make sure a polymorphic function is legally callable, and * Make sure a polymorphic function is legally callable, and
* deduce actual argument and result types. * 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 * return type, we make sure the actual data types are consistent with
* each other. The argument consistency rules are shown above for * each other. The argument consistency rules are shown above for
* check_generic_type_consistency(). * check_generic_type_consistency().
...@@ -1211,6 +1228,10 @@ check_generic_type_consistency(Oid *actual_arg_types, ...@@ -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 * 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 * (alone or in combination with plain ANYELEMENT), we add the extra
* condition that the ANYELEMENT type must be an enum. * 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 Oid
enforce_generic_type_consistency(Oid *actual_arg_types, enforce_generic_type_consistency(Oid *actual_arg_types,
...@@ -1225,22 +1246,28 @@ 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_typeid = InvalidOid;
Oid array_typelem; Oid array_typelem;
bool have_anyelement = (rettype == ANYELEMENTOID || bool have_anyelement = (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
rettype == ANYENUMOID); rettype == ANYENUMOID);
bool have_anynonarray = (rettype == ANYNONARRAYOID);
bool have_anyenum = (rettype == ANYENUMOID); bool have_anyenum = (rettype == ANYENUMOID);
/* /*
* Loop through the arguments to see if we have any that are ANYARRAY or * Loop through the arguments to see if we have any that are polymorphic.
* ANYELEMENT. If so, require the actual types to be self-consistent * If so, require the actual types to be consistent.
*/ */
for (j = 0; j < nargs; j++) for (j = 0; j < nargs; j++)
{ {
Oid decl_type = declared_arg_types[j];
Oid actual_type = actual_arg_types[j]; Oid actual_type = actual_arg_types[j];
if (declared_arg_types[j] == ANYELEMENTOID || if (decl_type == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID) decl_type == ANYNONARRAYOID ||
decl_type == ANYENUMOID)
{ {
have_generics = have_anyelement = true; 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; have_anyenum = true;
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
{ {
...@@ -1256,7 +1283,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types, ...@@ -1256,7 +1283,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
format_type_be(actual_type)))); format_type_be(actual_type))));
elem_typeid = actual_type; elem_typeid = actual_type;
} }
else if (declared_arg_types[j] == ANYARRAYOID) else if (decl_type == ANYARRAYOID)
{ {
have_generics = true; have_generics = true;
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
...@@ -1326,6 +1353,16 @@ enforce_generic_type_consistency(Oid *actual_arg_types, ...@@ -1326,6 +1353,16 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
errmsg("could not determine polymorphic type because input has type \"unknown\""))); 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) if (have_anyenum)
{ {
/* require the element type to be an enum */ /* require the element type to be an enum */
...@@ -1343,15 +1380,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types, ...@@ -1343,15 +1380,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
{ {
for (j = 0; j < nargs; j++) for (j = 0; j < nargs; j++)
{ {
Oid decl_type = declared_arg_types[j];
Oid actual_type = actual_arg_types[j]; Oid actual_type = actual_arg_types[j];
if (actual_type != UNKNOWNOID) if (actual_type != UNKNOWNOID)
continue; continue;
if (declared_arg_types[j] == ANYELEMENTOID || if (decl_type == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID) decl_type == ANYNONARRAYOID ||
decl_type == ANYENUMOID)
declared_arg_types[j] = elem_typeid; declared_arg_types[j] = elem_typeid;
else if (declared_arg_types[j] == ANYARRAYOID) else if (decl_type == ANYARRAYOID)
{ {
if (!OidIsValid(array_typeid)) if (!OidIsValid(array_typeid))
{ {
...@@ -1383,7 +1422,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types, ...@@ -1383,7 +1422,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
} }
/* if we return ANYELEMENT use the appropriate argument type */ /* if we return ANYELEMENT use the appropriate argument type */
if (rettype == ANYELEMENTOID || rettype == ANYENUMOID) if (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
rettype == ANYENUMOID)
return elem_typeid; return elem_typeid;
/* we don't return a generic type; send back the original return type */ /* we don't return a generic type; send back the original return type */
...@@ -1423,6 +1464,7 @@ resolve_generic_type(Oid declared_type, ...@@ -1423,6 +1464,7 @@ resolve_generic_type(Oid declared_type,
return context_actual_type; return context_actual_type;
} }
else if (context_declared_type == ANYELEMENTOID || else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
context_declared_type == ANYENUMOID) context_declared_type == ANYENUMOID)
{ {
/* Use the array type corresponding to actual type */ /* Use the array type corresponding to actual type */
...@@ -1436,7 +1478,9 @@ resolve_generic_type(Oid declared_type, ...@@ -1436,7 +1478,9 @@ resolve_generic_type(Oid declared_type,
return array_typeid; 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) if (context_declared_type == ANYARRAYOID)
{ {
...@@ -1451,6 +1495,7 @@ resolve_generic_type(Oid declared_type, ...@@ -1451,6 +1495,7 @@ resolve_generic_type(Oid declared_type,
return array_typelem; return array_typelem;
} }
else if (context_declared_type == ANYELEMENTOID || else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
context_declared_type == ANYENUMOID) context_declared_type == ANYENUMOID)
{ {
/* Use the actual type; it doesn't matter if array or not */ /* Use the actual type; it doesn't matter if array or not */
...@@ -1564,6 +1609,7 @@ TypeCategory(Oid inType) ...@@ -1564,6 +1609,7 @@ TypeCategory(Oid inType)
case (INTERNALOID): case (INTERNALOID):
case (OPAQUEOID): case (OPAQUEOID):
case (ANYELEMENTOID): case (ANYELEMENTOID):
case (ANYNONARRAYOID):
case (ANYENUMOID): case (ANYENUMOID):
result = GENERIC_TYPE; result = GENERIC_TYPE;
break; break;
...@@ -1707,7 +1753,12 @@ IsBinaryCoercible(Oid srctype, Oid targettype) ...@@ -1707,7 +1753,12 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
/* Also accept any array type as coercible to ANYARRAY */ /* Also accept any array type as coercible to ANYARRAY */
if (targettype == ANYARRAYOID) 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; return true;
/* Also accept any enum type as coercible to ANYENUM */ /* Also accept any enum type as coercible to ANYENUM */
...@@ -1863,22 +1914,6 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, ...@@ -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 * If we still haven't found a possibility, consider automatic casting
* using I/O functions. We allow assignment casts to textual types * using I/O functions. We allow assignment casts to textual types
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -227,9 +227,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
} }
/* /*
* enforce consistency with ANYARRAY and ANYELEMENT argument and return * enforce consistency with polymorphic argument and return types,
* types, possibly adjusting return type or declared_arg_types (which will * possibly adjusting return type or declared_arg_types (which will be
* be used as the cast destination by make_fn_arguments) * used as the cast destination by make_fn_arguments)
*/ */
rettype = enforce_generic_type_consistency(actual_arg_types, rettype = enforce_generic_type_consistency(actual_arg_types,
declared_arg_types, declared_arg_types,
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -347,6 +347,32 @@ anyelement_out(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); /* keep compiler quiet */ 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). * shell_in - input routine for "shell" types (those not yet filled in).
*/ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -1481,7 +1481,7 @@ map_sql_value_to_xml_value(Datum value, Oid type)
initStringInfo(&buf); initStringInfo(&buf);
if (is_array_type(type)) if (type_is_array(type))
{ {
int i; int i;
ArrayType *array; ArrayType *array;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 2002-2007, PostgreSQL Global Development Group * Copyright (c) 2002-2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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) ...@@ -193,8 +193,8 @@ shutdown_MultiFuncCall(Datum arg)
* only when we couldn't resolve the actual rowtype for lack of information. * only when we couldn't resolve the actual rowtype for lack of information.
* *
* The other hard case that this handles is resolution of polymorphism. * The other hard case that this handles is resolution of polymorphism.
* We will never return ANYELEMENT, ANYARRAY or ANYENUM, either as a scalar * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
* result type or as a component of a rowtype. * as a scalar result type or as a component of a rowtype.
* *
* This function is relatively expensive --- in a function returning set, * This function is relatively expensive --- in a function returning set,
* try to call it only the first time through. * try to call it only the first time through.
...@@ -389,9 +389,9 @@ internal_get_result_type(Oid funcid, ...@@ -389,9 +389,9 @@ internal_get_result_type(Oid funcid,
/* /*
* Given the result tuple descriptor for a function with OUT parameters, * Given the result tuple descriptor for a function with OUT parameters,
* replace any polymorphic columns (ANYELEMENT/ANYARRAY/ANYENUM) with correct * replace any polymorphic columns (ANYELEMENT etc) with correct data types
* data types deduced from the input arguments. Returns TRUE if able to deduce * deduced from the input arguments. Returns TRUE if able to deduce all types,
* all types, FALSE if not. * FALSE if not.
*/ */
static bool static bool
resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
...@@ -401,6 +401,7 @@ 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; int nargs = declared_args->dim1;
bool have_anyelement_result = false; bool have_anyelement_result = false;
bool have_anyarray_result = false; bool have_anyarray_result = false;
bool have_anynonarray = false;
bool have_anyenum = false; bool have_anyenum = false;
Oid anyelement_type = InvalidOid; Oid anyelement_type = InvalidOid;
Oid anyarray_type = InvalidOid; Oid anyarray_type = InvalidOid;
...@@ -417,6 +418,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, ...@@ -417,6 +418,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
case ANYARRAYOID: case ANYARRAYOID:
have_anyarray_result = true; have_anyarray_result = true;
break; break;
case ANYNONARRAYOID:
have_anyelement_result = true;
have_anynonarray = true;
break;
case ANYENUMOID: case ANYENUMOID:
have_anyelement_result = true; have_anyelement_result = true;
have_anyenum = true; have_anyenum = true;
...@@ -440,6 +445,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, ...@@ -440,6 +445,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
switch (declared_args->values[i]) switch (declared_args->values[i])
{ {
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
if (!OidIsValid(anyelement_type)) if (!OidIsValid(anyelement_type))
anyelement_type = get_call_expr_argtype(call_expr, i); anyelement_type = get_call_expr_argtype(call_expr, i);
...@@ -467,7 +473,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, ...@@ -467,7 +473,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
anyelement_type, anyelement_type,
ANYELEMENTOID); 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)) if (have_anyenum && !type_is_enum(anyelement_type))
return false; return false;
...@@ -477,6 +487,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, ...@@ -477,6 +487,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
switch (tupdesc->attrs[i]->atttypid) switch (tupdesc->attrs[i]->atttypid)
{ {
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
TupleDescInitEntry(tupdesc, i + 1, TupleDescInitEntry(tupdesc, i + 1,
NameStr(tupdesc->attrs[i]->attname), NameStr(tupdesc->attrs[i]->attname),
...@@ -500,11 +511,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, ...@@ -500,11 +511,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
} }
/* /*
* Given the declared argument types and modes for a function, * Given the declared argument types and modes for a function, replace any
* replace any polymorphic types (ANYELEMENT/ANYARRAY/ANYENUM) with correct * polymorphic types (ANYELEMENT etc) with correct data types deduced from the
* data types deduced from the input arguments. Returns TRUE if able to deduce * input arguments. Returns TRUE if able to deduce all types, FALSE if not.
* all types, FALSE if not. This is the same logic as * This is the same logic as resolve_polymorphic_tupdesc, but with a different
* resolve_polymorphic_tupdesc, but with a different argument representation. * argument representation.
* *
* argmodes may be NULL, in which case all arguments are assumed to be IN mode. * 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, ...@@ -528,6 +539,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
switch (argtypes[i]) switch (argtypes[i])
{ {
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
if (argmode == PROARGMODE_OUT) if (argmode == PROARGMODE_OUT)
have_anyelement_result = true; have_anyelement_result = true;
...@@ -583,7 +595,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, ...@@ -583,7 +595,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
anyelement_type, anyelement_type,
ANYELEMENTOID); 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 */ /* And finally replace the output column types as needed */
for (i = 0; i < numargs; i++) for (i = 0; i < numargs; i++)
...@@ -591,6 +603,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, ...@@ -591,6 +603,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
switch (argtypes[i]) switch (argtypes[i])
{ {
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: case ANYENUMOID:
argtypes[i] = anyelement_type; argtypes[i] = anyelement_type;
break; break;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200706051 #define CATALOG_VERSION_NO 200706061
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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 ...@@ -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 = 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 = 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 = 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 = 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 - - )); 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 ...@@ -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 = 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 )); 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 */ /* 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 = 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 )); DATA(insert OID = 2861 ( "~" PGNSP PGUID b f f 604 604 16 2860 0 poly_contain contsel contjoinsel ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * 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 ...@@ -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"); 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_ )); 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"); 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"); 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_ )); 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"); DESCR("adjust timestamp to new time zone");
...@@ -1509,7 +1509,7 @@ DESCR("adjust interval precision"); ...@@ -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_ )); 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"); 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"); 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_ )); 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"); DESCR("get description for object id and shared catalog name");
...@@ -1722,7 +1722,7 @@ DESCR("less-equal-greater"); ...@@ -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_ )); 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"); 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"); 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_ )); 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 ...@@ -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"); 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_ )); 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"); 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"); 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_ )); 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"); DESCR("return portion of bitstring");
...@@ -2981,6 +2981,11 @@ DESCR("adjust time precision"); ...@@ -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_ )); 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"); 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_ )); 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"); 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_ )); 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 ...@@ -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"); 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_ )); 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"); 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 */ /* 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_ )); 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"); ...@@ -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_ )); 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"); 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"); DESCR("evaluate XPath expression");
/* uuid */ /* uuid */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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 ...@@ -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 #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_ )); 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 #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_ )); 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 #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 ...@@ -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) \ #define IsPolymorphicType(typid) \
((typid) == ANYELEMENTOID || \ ((typid) == ANYELEMENTOID || \
(typid) == ANYARRAYOID || \ (typid) == ANYARRAYOID || \
(typid) == ANYNONARRAYOID || \
(typid) == ANYENUMOID) (typid) == ANYENUMOID)
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -458,6 +458,8 @@ extern Datum anyarray_in(PG_FUNCTION_ARGS);
extern Datum anyarray_out(PG_FUNCTION_ARGS); extern Datum anyarray_out(PG_FUNCTION_ARGS);
extern Datum anyarray_recv(PG_FUNCTION_ARGS); extern Datum anyarray_recv(PG_FUNCTION_ARGS);
extern Datum anyarray_send(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_in(PG_FUNCTION_ARGS);
extern Datum anyenum_out(PG_FUNCTION_ARGS); extern Datum anyenum_out(PG_FUNCTION_ARGS);
extern Datum void_in(PG_FUNCTION_ARGS); extern Datum void_in(PG_FUNCTION_ARGS);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -130,7 +130,7 @@ extern char *get_namespace_name(Oid nspid);
extern Oid get_roleid(const char *rolname); extern Oid get_roleid(const char *rolname);
extern Oid get_roleid_checked(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') #define TypeIsToastable(typid) (get_typstorage(typid) != 'p')
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -480,7 +480,7 @@ do_compile(FunctionCallInfo fcinfo,
{ {
if (rettypeid == ANYARRAYOID) if (rettypeid == ANYARRAYOID)
rettypeid = INT4ARRAYOID; rettypeid = INT4ARRAYOID;
else else /* ANYELEMENT or ANYNONARRAY */
rettypeid = INT4OID; rettypeid = INT4OID;
/* XXX what could we use for ANYENUM? */ /* XXX what could we use for ANYENUM? */
} }
...@@ -2027,6 +2027,7 @@ plpgsql_resolve_polymorphic_argtypes(int numargs, ...@@ -2027,6 +2027,7 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
switch (argtypes[i]) switch (argtypes[i])
{ {
case ANYELEMENTOID: case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: /* XXX dubious */ case ANYENUMOID: /* XXX dubious */
argtypes[i] = INT4OID; argtypes[i] = INT4OID;
break; break;
......
...@@ -23,3 +23,31 @@ SELECT '' AS two, * FROM TEXT_TBL; ...@@ -23,3 +23,31 @@ SELECT '' AS two, * FROM TEXT_TBL;
| hi de ho neighbor | hi de ho neighbor
(2 rows) (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.
...@@ -13,3 +13,18 @@ INSERT INTO TEXT_TBL VALUES ('hi de ho neighbor'); ...@@ -13,3 +13,18 @@ INSERT INTO TEXT_TBL VALUES ('hi de ho neighbor');
SELECT '' AS two, * FROM TEXT_TBL; 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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment