From 2d4db3675fa7a2f4831b755bc98242421901042f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jun 2007 23:00:50 +0000 Subject: [PATCH] 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. --- doc/src/sgml/datatype.sgml | 16 +++- doc/src/sgml/extend.sgml | 18 +++- doc/src/sgml/func.sgml | 46 +++++++++-- doc/src/sgml/plpgsql.sgml | 8 +- doc/src/sgml/xfunc.sgml | 8 +- src/backend/catalog/pg_proc.c | 4 +- src/backend/executor/functions.c | 10 ++- src/backend/parser/parse_agg.c | 4 +- src/backend/parser/parse_coerce.c | 123 ++++++++++++++++++---------- src/backend/parser/parse_func.c | 8 +- src/backend/utils/adt/pseudotypes.c | 28 ++++++- src/backend/utils/adt/xml.c | 4 +- src/backend/utils/fmgr/funcapi.c | 39 ++++++--- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_operator.h | 8 +- src/include/catalog/pg_proc.h | 21 +++-- src/include/catalog/pg_type.h | 5 +- src/include/utils/builtins.h | 4 +- src/include/utils/lsyscache.h | 4 +- src/pl/plpgsql/src/pl_comp.c | 5 +- src/test/regress/expected/text.out | 28 +++++++ src/test/regress/sql/text.sql | 15 ++++ 22 files changed, 301 insertions(+), 109 deletions(-) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 3802aa24df..c64b040e45 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,4 +1,4 @@ - + Data Types @@ -3676,12 +3676,16 @@ SELECT * FROM pg_attribute any + + anyelement + + anyarray - anyelement + anynonarray @@ -3760,6 +3764,12 @@ SELECT * FROM pg_attribute ). + + anynonarray + Indicates that a function accepts any non-array data type + (see ). + + cstring Indicates that a function accepts or returns a null-terminated C string. @@ -3813,7 +3823,7 @@ SELECT * FROM pg_attribute only void and record as a result type (plus trigger when the function is used as a trigger). Some also support polymorphic functions using the types anyarray, - anyelement and anyenum. + anyelement, anyenum, and anynonarray. diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index bb5834e74a..28bdfb8532 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -1,4 +1,4 @@ - + Extending <acronym>SQL</acronym> @@ -193,8 +193,8 @@ - Three pseudo-types of special interest are anyelement, - anyarray, and anyenum, + Four pseudo-types of special interest are anyelement, + anyarray, anynonarray, and anyenum, which are collectively called polymorphic types. Any function declared using these types is said to be a polymorphic function. A polymorphic function can @@ -216,6 +216,9 @@ anyelement, the actual array type in the anyarray positions must be an array whose elements are the same type appearing in the anyelement positions. + anynonarray is treated exactly the same as anyelement, + but adds the additional constraint that the actual type must not be + an array type. anyenum is treated exactly the same as 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 f(anyarray) returns anyenum will only accept arrays of enum types. + + + Note that anynonarray and anyenum do not represent + separate type variables; they are the same type as + anyelement, just with an additional constraint. For + example, declaring a function as f(anyelement, anyenum) + is equivalent to declaring it as f(anyenum, anyenum): + both actual arguments have to be the same enum type. + diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c2f3371dc4..387c4e81c8 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ - + Functions and Operators @@ -986,24 +986,36 @@ This section describes functions and operators for examining and manipulating string values. Strings in this context include values - of all the types character, character - varying, and text. Unless otherwise noted, all + of the types character, character varying, + and text. 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 - character 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 + character type. Some functions also exist natively for the bit-string types. - SQL defines some string functions with a special syntax where - certain key words rather than commas are used to separate the + SQL defines some string functions with a special syntax + wherein certain key words rather than commas are used to separate the arguments. Details are in . These functions are also implemented using the regular syntax for function invocation. (See .) + + + Before PostgreSQL 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 + text. Those coercions have been removed because they frequently + caused surprising behaviors. However, the string concatenation operator + (||) still accepts non-string input, so long as at least one + input is of a string type, as shown in . For other cases, insert an explicit + coercion to text if you need to duplicate the previous behavior. + + + bit_length @@ -1064,6 +1076,22 @@ PostgreSQL + + + string || + non-string + or + non-string || + string + + text + + String concatenation with one non-string input + + 'Value: ' || 42 + Value: 42 + + bit_length(string) int diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index c1f57ddf4f..d14519b613 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -1,4 +1,4 @@ - + <application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language @@ -210,8 +210,8 @@ $$ LANGUAGE plpgsql; PL/pgSQL functions can also be declared to accept and return the polymorphic types - anyelement, anyarray, and anyenum. - The actual + anyelement, anyarray, anynonarray, + and anyenum. The actual data types handled by a polymorphic function can vary from call to call, as discussed in . An example is shown in . @@ -700,7 +700,7 @@ $$ LANGUAGE plpgsql; When the return type of a PL/pgSQL function is declared as a polymorphic type (anyelement, - anyarray, or anyenum), + anyarray, anynonarray, or anyenum), a special parameter $0 is created. Its data type is the actual return type of the function, as deduced from the actual input types (see + User-Defined Functions @@ -718,7 +718,8 @@ SELECT name, listchildren(name) FROM nodes; SQL functions can be declared to accept and return the polymorphic types anyelement, - anyarray, and anyenum. See anyarray, anynonarray, and + anyenum. See for a more detailed explanation of polymorphic functions. Here is a polymorphic function make_array that builds up an array @@ -2831,7 +2832,8 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer, C-language functions can be declared to accept and return the polymorphic types - anyelement, anyarray, and anyenum. + anyelement, anyarray, anynonarray, + and anyenum. See 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 26c5eb75e3..9db3ef4edb 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 9ad1391612..8beea3f539 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 1409285cda..1afc55bc9a 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 98cc669112..abc0568581 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 5e7a1cccff..393fa6c41a 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 fc9f332482..248bcfa305 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 f9fd48db66..2e84fac1d7 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 c32130c3ec..53a505858b 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 ec6d516713..8dfca8ecc7 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 6848b274e4..e3b2910eb2 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 c656c7a671..49c1429e37 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 0d9ff0d6ee..753487348b 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 5ff4fe738f..faf8b69262 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 25782e322e..0a326cb9ba 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 74918c890c..a547d174c1 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 2d732f6844..08d002fe71 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 60daf7077c..b739e56e2d 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;