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.
This commit is contained in:
Tom Lane 2007-06-06 23:00:50 +00:00
parent 7dab4f75ca
commit 2d4db3675f
22 changed files with 301 additions and 109 deletions

View 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>

View 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>
@ -193,8 +193,8 @@
</indexterm>
<para>
Three pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, and <type>anyenum</>,
Four pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, <type>anynonarray</>, and <type>anyenum</>,
which are collectively called <firstterm>polymorphic types</>.
Any function declared using these types is said to be
a <firstterm>polymorphic function</>. A polymorphic function can
@ -216,6 +216,9 @@
<type>anyelement</type>, the actual array type in the
<type>anyarray</type> positions must be an array whose elements are
the same type appearing in the <type>anyelement</type> positions.
<type>anynonarray</> is treated exactly the same as <type>anyelement</>,
but adds the additional constraint that the actual type must not be
an array type.
<type>anyenum</> is treated exactly the same as <type>anyelement</>,
but adds the additional constraint that the actual type must
be an enum type.
@ -242,6 +245,15 @@
is that a function declared as <literal>f(anyarray) returns anyenum</>
will only accept arrays of enum types.
</para>
<para>
Note that <type>anynonarray</> and <type>anyenum</> do not represent
separate type variables; they are the same type as
<type>anyelement</type>, just with an additional constraint. For
example, declaring a function as <literal>f(anyelement, anyenum)</>
is equivalent to declaring it as <literal>f(anyenum, anyenum)</>:
both actual arguments have to be the same enum type.
</para>
</sect2>
</sect1>

View 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>
@ -986,24 +986,36 @@
<para>
This section describes functions and operators for examining and
manipulating string values. Strings in this context include values
of all the types <type>character</type>, <type>character
varying</type>, and <type>text</type>. Unless otherwise noted, all
of the types <type>character</type>, <type>character varying</type>,
and <type>text</type>. Unless otherwise noted, all
of the functions listed below work on all of these types, but be
wary of potential effects of the automatic padding when using the
<type>character</type> type. Generally, the functions described
here also work on data of non-string types by converting that data
to a string representation first. Some functions also exist
wary of potential effects of automatic space-padding when using the
<type>character</type> type. Some functions also exist
natively for the bit-string types.
</para>
<para>
<acronym>SQL</acronym> defines some string functions with a special syntax where
certain key words rather than commas are used to separate the
<acronym>SQL</acronym> defines some string functions with a special syntax
wherein certain key words rather than commas are used to separate the
arguments. Details are in <xref linkend="functions-string-sql">.
These functions are also implemented using the regular syntax for
function invocation. (See <xref linkend="functions-string-other">.)
</para>
<note>
<para>
Before <productname>PostgreSQL</productname> 8.3, these functions would
silently accept values of several non-string data types as well, due to
the presence of implicit coercions from those data types to
<type>text</>. Those coercions have been removed because they frequently
caused surprising behaviors. However, the string concatenation operator
(<literal>||</>) still accepts non-string input, so long as at least one
input is of a string type, as shown in <xref
linkend="functions-string-sql">. For other cases, insert an explicit
coercion to <type>text</> if you need to duplicate the previous behavior.
</para>
</note>
<indexterm>
<primary>bit_length</primary>
</indexterm>
@ -1064,6 +1076,22 @@
<entry><literal>PostgreSQL</literal></entry>
</row>
<row>
<entry>
<literal><parameter>string</parameter> <literal>||</literal>
<parameter>non-string</parameter></literal>
or
<literal><parameter>non-string</parameter> <literal>||</literal>
<parameter>string</parameter></literal>
</entry>
<entry> <type>text</type> </entry>
<entry>
String concatenation with one non-string input
</entry>
<entry><literal>'Value: ' || 42</literal></entry>
<entry><literal>Value: 42</literal></entry>
</row>
<row>
<entry><literal><function>bit_length</function>(<parameter>string</parameter>)</literal></entry>
<entry><type>int</type></entry>

View 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

View 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

View 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;

View 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 */

View 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.

View 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

View 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,

View 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).
*/

View 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;

View 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;

View 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

View 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 ));

View 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 */

View 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)
/*

View 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);

View 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')

View 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;

View 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.

View 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;