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