Restructure polymorphic-type resolution in funcapi.c.
authorTom Lane <[email protected]>
Sat, 14 Mar 2020 18:42:22 +0000 (14:42 -0400)
committerTom Lane <[email protected]>
Sat, 14 Mar 2020 18:42:22 +0000 (14:42 -0400)
resolve_polymorphic_tupdesc() and resolve_polymorphic_argtypes() failed to
cover the case of having to resolve anyarray given only an anyrange input.
The bug was masked if anyelement was also used (as either input or
output), which probably helps account for our not having noticed.

While looking at this I noticed that resolve_generic_type() would produce
the wrong answer if asked to make that same resolution.  ISTM that
resolve_generic_type() is confusingly defined and overly complex, so
rather than fix it, let's just make funcapi.c do the specific lookups
it requires for itself.

With this change, resolve_generic_type() is not used anywhere, so remove
it in HEAD.  In the back branches, leave it alone (complete with bug)
just in case any external code is using it.

While we're here, make some other refactoring adjustments in funcapi.c
with an eye to upcoming future expansion of the set of polymorphic types:

* Simplify quick-exit tests by adding an overall have_polymorphic_result
flag.  This is about a wash now but will be a win when there are more
flags.

* Reduce duplication of code between resolve_polymorphic_tupdesc() and
resolve_polymorphic_argtypes().

* Don't bother to validate correct matching of anynonarray or anyenum;
the parser should have done that, and even if it didn't, just doing
"return false" here would lead to a very confusing, off-point error
message.  (Really, "return false" in these two functions should only
occur if the call_expr isn't supplied or we can't obtain data type
info from it.)

* For the same reason, throw an elog rather than "return false" if
we fail to resolve a polymorphic type.

The bug's been there since we added anyrange, so back-patch to
all supported branches.

Discussion: https://postgr.es/m/6093.1584202130@sss.pgh.pa.us

src/backend/parser/parse_coerce.c
src/backend/utils/fmgr/funcapi.c
src/include/parser/parse_coerce.h
src/test/regress/expected/rangetypes.out
src/test/regress/sql/rangetypes.sql

index 929f758ef45441bd026fc412f123a0ae4d816464..4a2b463d1b7fc068158b805eebb42a7c7d317079 100644 (file)
@@ -14,7 +14,6 @@
  */
 #include "postgres.h"
 
-#include "access/htup_details.h"
 #include "catalog/pg_cast.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_inherits.h"
@@ -26,7 +25,6 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
-#include "utils/datum.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
@@ -1968,108 +1966,6 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
    return rettype;
 }
 
-/*
- * resolve_generic_type()
- *     Deduce an individual actual datatype on the assumption that
- *     the rules for polymorphic types are being followed.
- *
- * declared_type is the declared datatype we want to resolve.
- * context_actual_type is the actual input datatype to some argument
- * that has declared datatype context_declared_type.
- *
- * If declared_type isn't polymorphic, we just return it.  Otherwise,
- * context_declared_type must be polymorphic, and we deduce the correct
- * return type based on the relationship of the two polymorphic types.
- */
-Oid
-resolve_generic_type(Oid declared_type,
-                    Oid context_actual_type,
-                    Oid context_declared_type)
-{
-   if (declared_type == ANYARRAYOID)
-   {
-       if (context_declared_type == ANYARRAYOID)
-       {
-           /*
-            * Use actual type, but it must be an array; or if it's a domain
-            * over array, use the base array type.
-            */
-           Oid         context_base_type = getBaseType(context_actual_type);
-           Oid         array_typelem = get_element_type(context_base_type);
-
-           if (!OidIsValid(array_typelem))
-               ereport(ERROR,
-                       (errcode(ERRCODE_DATATYPE_MISMATCH),
-                        errmsg("argument declared %s is not an array but type %s",
-                               "anyarray", format_type_be(context_base_type))));
-           return context_base_type;
-       }
-       else if (context_declared_type == ANYELEMENTOID ||
-                context_declared_type == ANYNONARRAYOID ||
-                context_declared_type == ANYENUMOID ||
-                context_declared_type == ANYRANGEOID)
-       {
-           /* Use the array type corresponding to actual type */
-           Oid         array_typeid = get_array_type(context_actual_type);
-
-           if (!OidIsValid(array_typeid))
-               ereport(ERROR,
-                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                        errmsg("could not find array type for data type %s",
-                               format_type_be(context_actual_type))));
-           return array_typeid;
-       }
-   }
-   else if (declared_type == ANYELEMENTOID ||
-            declared_type == ANYNONARRAYOID ||
-            declared_type == ANYENUMOID ||
-            declared_type == ANYRANGEOID)
-   {
-       if (context_declared_type == ANYARRAYOID)
-       {
-           /* Use the element type corresponding to actual type */
-           Oid         context_base_type = getBaseType(context_actual_type);
-           Oid         array_typelem = get_element_type(context_base_type);
-
-           if (!OidIsValid(array_typelem))
-               ereport(ERROR,
-                       (errcode(ERRCODE_DATATYPE_MISMATCH),
-                        errmsg("argument declared %s is not an array but type %s",
-                               "anyarray", format_type_be(context_base_type))));
-           return array_typelem;
-       }
-       else if (context_declared_type == ANYRANGEOID)
-       {
-           /* Use the element type corresponding to actual type */
-           Oid         context_base_type = getBaseType(context_actual_type);
-           Oid         range_typelem = get_range_subtype(context_base_type);
-
-           if (!OidIsValid(range_typelem))
-               ereport(ERROR,
-                       (errcode(ERRCODE_DATATYPE_MISMATCH),
-                        errmsg("argument declared %s is not a range type but type %s",
-                               "anyrange", format_type_be(context_base_type))));
-           return range_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 */
-           return context_actual_type;
-       }
-   }
-   else
-   {
-       /* declared_type isn't polymorphic, so return it as-is */
-       return declared_type;
-   }
-   /* If we get here, declared_type is polymorphic and context isn't */
-   /* NB: this is a calling-code logic error, not a user error */
-   elog(ERROR, "could not determine polymorphic type because context isn't polymorphic");
-   return InvalidOid;          /* keep compiler quiet */
-}
-
 
 /* TypeCategory()
  *     Assign a category to the specified type OID.
index 0201e4f8d34238d88322968f900ca07808e707dc..4e9d21bd541fe450b7e52a838809acdd4c097828 100644 (file)
@@ -20,7 +20,6 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "nodes/nodeFuncs.h"
-#include "parser/parse_coerce.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/typcache.h"
 
 
+typedef struct polymorphic_actuals
+{
+   Oid         anyelement_type;    /* anyelement mapping, if known */
+   Oid         anyarray_type;  /* anyarray mapping, if known */
+   Oid         anyrange_type;  /* anyrange mapping, if known */
+} polymorphic_actuals;
+
 static void shutdown_MultiFuncCall(Datum arg);
 static TypeFuncClass internal_get_result_type(Oid funcid,
                                              Node *call_expr,
                                              ReturnSetInfo *rsinfo,
                                              Oid *resultTypeId,
                                              TupleDesc *resultTupleDesc);
+static void resolve_anyelement_from_others(polymorphic_actuals *actuals);
+static void resolve_anyarray_from_others(polymorphic_actuals *actuals);
+static void resolve_anyrange_from_others(polymorphic_actuals *actuals);
 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
                                        oidvector *declared_args,
                                        Node *call_expr);
@@ -455,11 +464,95 @@ get_expr_result_tupdesc(Node *expr, bool noError)
    return NULL;
 }
 
+/*
+ * Resolve actual type of ANYELEMENT from other polymorphic inputs
+ *
+ * Note: the error cases here and in the sibling functions below are not
+ * really user-facing; they could only occur if the function signature is
+ * incorrect or the parser failed to enforce consistency of the actual
+ * argument types.  Hence, we don't sweat too much over the error messages.
+ */
+static void
+resolve_anyelement_from_others(polymorphic_actuals *actuals)
+{
+   if (OidIsValid(actuals->anyarray_type))
+   {
+       /* Use the element type corresponding to actual type */
+       Oid         array_base_type = getBaseType(actuals->anyarray_type);
+       Oid         array_typelem = get_element_type(array_base_type);
+
+       if (!OidIsValid(array_typelem))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg("argument declared %s is not an array but type %s",
+                           "anyarray",
+                           format_type_be(array_base_type))));
+       actuals->anyelement_type = array_typelem;
+   }
+   else if (OidIsValid(actuals->anyrange_type))
+   {
+       /* Use the element type corresponding to actual type */
+       Oid         range_base_type = getBaseType(actuals->anyrange_type);
+       Oid         range_typelem = get_range_subtype(range_base_type);
+
+       if (!OidIsValid(range_typelem))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg("argument declared %s is not a range type but type %s",
+                           "anyrange",
+                           format_type_be(range_base_type))));
+       actuals->anyelement_type = range_typelem;
+   }
+   else
+       elog(ERROR, "could not determine polymorphic type");
+}
+
+/*
+ * Resolve actual type of ANYARRAY from other polymorphic inputs
+ */
+static void
+resolve_anyarray_from_others(polymorphic_actuals *actuals)
+{
+   /* If we don't know ANYELEMENT, resolve that first */
+   if (!OidIsValid(actuals->anyelement_type))
+       resolve_anyelement_from_others(actuals);
+
+   if (OidIsValid(actuals->anyelement_type))
+   {
+       /* Use the array type corresponding to actual type */
+       Oid         array_typeid = get_array_type(actuals->anyelement_type);
+
+       if (!OidIsValid(array_typeid))
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_OBJECT),
+                    errmsg("could not find array type for data type %s",
+                           format_type_be(actuals->anyelement_type))));
+       actuals->anyarray_type = array_typeid;
+   }
+   else
+       elog(ERROR, "could not determine polymorphic type");
+}
+
+/*
+ * Resolve actual type of ANYRANGE from other polymorphic inputs
+ */
+static void
+resolve_anyrange_from_others(polymorphic_actuals *actuals)
+{
+   /*
+    * We can't deduce a range type from other polymorphic inputs, because
+    * there may be multiple range types with the same subtype.
+    */
+   elog(ERROR, "could not determine polymorphic type");
+}
+
 /*
  * Given the result tuple descriptor for a function with OUT parameters,
- * 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.
+ * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
+ * with concrete data types deduced from the input arguments.
+ * declared_args is an oidvector of the function's declared input arg types
+ * (showing which are polymorphic), and call_expr is the call expression.
+ * Returns true if able to deduce all types, false if not.
  */
 static bool
 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
@@ -467,14 +560,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 {
    int         natts = tupdesc->natts;
    int         nargs = declared_args->dim1;
+   bool        have_polymorphic_result = false;
    bool        have_anyelement_result = false;
    bool        have_anyarray_result = false;
    bool        have_anyrange_result = false;
-   bool        have_anynonarray = false;
-   bool        have_anyenum = false;
-   Oid         anyelement_type = InvalidOid;
-   Oid         anyarray_type = InvalidOid;
-   Oid         anyrange_type = InvalidOid;
+   polymorphic_actuals poly_actuals;
    Oid         anycollation = InvalidOid;
    int         i;
 
@@ -484,28 +574,24 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
        switch (TupleDescAttr(tupdesc, i)->atttypid)
        {
            case ANYELEMENTOID:
+           case ANYNONARRAYOID:
+           case ANYENUMOID:
+               have_polymorphic_result = true;
                have_anyelement_result = true;
                break;
            case ANYARRAYOID:
+               have_polymorphic_result = true;
                have_anyarray_result = true;
                break;
-           case ANYNONARRAYOID:
-               have_anyelement_result = true;
-               have_anynonarray = true;
-               break;
-           case ANYENUMOID:
-               have_anyelement_result = true;
-               have_anyenum = true;
-               break;
            case ANYRANGEOID:
+               have_polymorphic_result = true;
                have_anyrange_result = true;
                break;
            default:
                break;
        }
    }
-   if (!have_anyelement_result && !have_anyarray_result &&
-       !have_anyrange_result)
+   if (!have_polymorphic_result)
        return true;
 
    /*
@@ -515,6 +601,8 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
    if (!call_expr)
        return false;           /* no hope */
 
+   memset(&poly_actuals, 0, sizeof(poly_actuals));
+
    for (i = 0; i < nargs; i++)
    {
        switch (declared_args->values[i])
@@ -522,66 +610,46 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
            case ANYELEMENTOID:
            case ANYNONARRAYOID:
            case ANYENUMOID:
-               if (!OidIsValid(anyelement_type))
-                   anyelement_type = get_call_expr_argtype(call_expr, i);
+               if (!OidIsValid(poly_actuals.anyelement_type))
+               {
+                   poly_actuals.anyelement_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(poly_actuals.anyelement_type))
+                       return false;
+               }
                break;
            case ANYARRAYOID:
-               if (!OidIsValid(anyarray_type))
-                   anyarray_type = get_call_expr_argtype(call_expr, i);
+               if (!OidIsValid(poly_actuals.anyarray_type))
+               {
+                   poly_actuals.anyarray_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(poly_actuals.anyarray_type))
+                       return false;
+               }
                break;
            case ANYRANGEOID:
-               if (!OidIsValid(anyrange_type))
-                   anyrange_type = get_call_expr_argtype(call_expr, i);
+               if (!OidIsValid(poly_actuals.anyrange_type))
+               {
+                   poly_actuals.anyrange_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(poly_actuals.anyrange_type))
+                       return false;
+               }
                break;
            default:
                break;
        }
    }
 
-   /* If nothing found, parser messed up */
-   if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
-       !OidIsValid(anyrange_type))
-       return false;
-
    /* If needed, deduce one polymorphic type from others */
-   if (have_anyelement_result && !OidIsValid(anyelement_type))
-   {
-       if (OidIsValid(anyarray_type))
-           anyelement_type = resolve_generic_type(ANYELEMENTOID,
-                                                  anyarray_type,
-                                                  ANYARRAYOID);
-       if (OidIsValid(anyrange_type))
-       {
-           Oid         subtype = resolve_generic_type(ANYELEMENTOID,
-                                                      anyrange_type,
-                                                      ANYRANGEOID);
-
-           /* check for inconsistent array and range results */
-           if (OidIsValid(anyelement_type) && anyelement_type != subtype)
-               return false;
-           anyelement_type = subtype;
-       }
-   }
-
-   if (have_anyarray_result && !OidIsValid(anyarray_type))
-       anyarray_type = resolve_generic_type(ANYARRAYOID,
-                                            anyelement_type,
-                                            ANYELEMENTOID);
-
-   /*
-    * We can't deduce a range type from other polymorphic inputs, because
-    * there may be multiple range types for the same subtype.
-    */
-   if (have_anyrange_result && !OidIsValid(anyrange_type))
-       return false;
+   if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
+       resolve_anyelement_from_others(&poly_actuals);
 
-   /* Enforce ANYNONARRAY if needed */
-   if (have_anynonarray && type_is_array(anyelement_type))
-       return false;
+   if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
+       resolve_anyarray_from_others(&poly_actuals);
 
-   /* Enforce ANYENUM if needed */
-   if (have_anyenum && !type_is_enum(anyelement_type))
-       return false;
+   if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
+       resolve_anyrange_from_others(&poly_actuals);
 
    /*
     * Identify the collation to use for polymorphic OUT parameters. (It'll
@@ -589,10 +657,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
     * range types are not collatable, so any possible internal collation of a
     * range type is not considered here.
     */
-   if (OidIsValid(anyelement_type))
-       anycollation = get_typcollation(anyelement_type);
-   else if (OidIsValid(anyarray_type))
-       anycollation = get_typcollation(anyarray_type);
+   if (OidIsValid(poly_actuals.anyelement_type))
+       anycollation = get_typcollation(poly_actuals.anyelement_type);
+   else if (OidIsValid(poly_actuals.anyarray_type))
+       anycollation = get_typcollation(poly_actuals.anyarray_type);
 
    if (OidIsValid(anycollation))
    {
@@ -619,7 +687,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
            case ANYENUMOID:
                TupleDescInitEntry(tupdesc, i + 1,
                                   NameStr(att->attname),
-                                  anyelement_type,
+                                  poly_actuals.anyelement_type,
                                   -1,
                                   0);
                TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
@@ -627,7 +695,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
            case ANYARRAYOID:
                TupleDescInitEntry(tupdesc, i + 1,
                                   NameStr(att->attname),
-                                  anyarray_type,
+                                  poly_actuals.anyarray_type,
                                   -1,
                                   0);
                TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
@@ -635,7 +703,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
            case ANYRANGEOID:
                TupleDescInitEntry(tupdesc, i + 1,
                                   NameStr(att->attname),
-                                  anyrange_type,
+                                  poly_actuals.anyrange_type,
                                   -1,
                                   0);
                /* no collation should be attached to a range type */
@@ -650,10 +718,12 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 
 /*
  * 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.
+ * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
+ * deduced from the input arguments found in call_expr.
+ * 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.
+ * argument representation, and slightly different output responsibilities.
  *
  * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
  */
@@ -661,16 +731,20 @@ bool
 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
                             Node *call_expr)
 {
+   bool        have_polymorphic_result = false;
    bool        have_anyelement_result = false;
    bool        have_anyarray_result = false;
    bool        have_anyrange_result = false;
-   Oid         anyelement_type = InvalidOid;
-   Oid         anyarray_type = InvalidOid;
-   Oid         anyrange_type = InvalidOid;
+   polymorphic_actuals poly_actuals;
    int         inargno;
    int         i;
 
-   /* First pass: resolve polymorphic inputs, check for outputs */
+   /*
+    * First pass: resolve polymorphic inputs, check for outputs.  As in
+    * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
+    * type consistency.
+    */
+   memset(&poly_actuals, 0, sizeof(poly_actuals));
    inargno = 0;
    for (i = 0; i < numargs; i++)
    {
@@ -682,47 +756,56 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
            case ANYNONARRAYOID:
            case ANYENUMOID:
                if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
                    have_anyelement_result = true;
+               }
                else
                {
-                   if (!OidIsValid(anyelement_type))
+                   if (!OidIsValid(poly_actuals.anyelement_type))
                    {
-                       anyelement_type = get_call_expr_argtype(call_expr,
-                                                               inargno);
-                       if (!OidIsValid(anyelement_type))
+                       poly_actuals.anyelement_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(poly_actuals.anyelement_type))
                            return false;
                    }
-                   argtypes[i] = anyelement_type;
+                   argtypes[i] = poly_actuals.anyelement_type;
                }
                break;
            case ANYARRAYOID:
                if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
                    have_anyarray_result = true;
+               }
                else
                {
-                   if (!OidIsValid(anyarray_type))
+                   if (!OidIsValid(poly_actuals.anyarray_type))
                    {
-                       anyarray_type = get_call_expr_argtype(call_expr,
-                                                             inargno);
-                       if (!OidIsValid(anyarray_type))
+                       poly_actuals.anyarray_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(poly_actuals.anyarray_type))
                            return false;
                    }
-                   argtypes[i] = anyarray_type;
+                   argtypes[i] = poly_actuals.anyarray_type;
                }
                break;
            case ANYRANGEOID:
                if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
                    have_anyrange_result = true;
+               }
                else
                {
-                   if (!OidIsValid(anyrange_type))
+                   if (!OidIsValid(poly_actuals.anyrange_type))
                    {
-                       anyrange_type = get_call_expr_argtype(call_expr,
-                                                             inargno);
-                       if (!OidIsValid(anyrange_type))
+                       poly_actuals.anyrange_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(poly_actuals.anyrange_type))
                            return false;
                    }
-                   argtypes[i] = anyrange_type;
+                   argtypes[i] = poly_actuals.anyrange_type;
                }
                break;
            default:
@@ -733,48 +816,18 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
    }
 
    /* Done? */
-   if (!have_anyelement_result && !have_anyarray_result &&
-       !have_anyrange_result)
+   if (!have_polymorphic_result)
        return true;
 
-   /* If no input polymorphics, parser messed up */
-   if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
-       !OidIsValid(anyrange_type))
-       return false;
-
    /* If needed, deduce one polymorphic type from others */
-   if (have_anyelement_result && !OidIsValid(anyelement_type))
-   {
-       if (OidIsValid(anyarray_type))
-           anyelement_type = resolve_generic_type(ANYELEMENTOID,
-                                                  anyarray_type,
-                                                  ANYARRAYOID);
-       if (OidIsValid(anyrange_type))
-       {
-           Oid         subtype = resolve_generic_type(ANYELEMENTOID,
-                                                      anyrange_type,
-                                                      ANYRANGEOID);
-
-           /* check for inconsistent array and range results */
-           if (OidIsValid(anyelement_type) && anyelement_type != subtype)
-               return false;
-           anyelement_type = subtype;
-       }
-   }
-
-   if (have_anyarray_result && !OidIsValid(anyarray_type))
-       anyarray_type = resolve_generic_type(ANYARRAYOID,
-                                            anyelement_type,
-                                            ANYELEMENTOID);
+   if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
+       resolve_anyelement_from_others(&poly_actuals);
 
-   /*
-    * We can't deduce a range type from other polymorphic inputs, because
-    * there may be multiple range types for the same subtype.
-    */
-   if (have_anyrange_result && !OidIsValid(anyrange_type))
-       return false;
+   if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
+       resolve_anyarray_from_others(&poly_actuals);
 
-   /* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
+   if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
+       resolve_anyrange_from_others(&poly_actuals);
 
    /* And finally replace the output column types as needed */
    for (i = 0; i < numargs; i++)
@@ -784,13 +837,13 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
            case ANYELEMENTOID:
            case ANYNONARRAYOID:
            case ANYENUMOID:
-               argtypes[i] = anyelement_type;
+               argtypes[i] = poly_actuals.anyelement_type;
                break;
            case ANYARRAYOID:
-               argtypes[i] = anyarray_type;
+               argtypes[i] = poly_actuals.anyarray_type;
                break;
            case ANYRANGEOID:
-               argtypes[i] = anyrange_type;
+               argtypes[i] = poly_actuals.anyrange_type;
                break;
            default:
                break;
index d6a95c10f7a3a7c1cfd9b1d4135a68f640cabf2b..ff9219dda93fa8e2bebabc7220c32a47a6c2b689 100644 (file)
@@ -79,9 +79,6 @@ extern Oid    enforce_generic_type_consistency(const Oid *actual_arg_types,
                                             int nargs,
                                             Oid rettype,
                                             bool allow_poly);
-extern Oid resolve_generic_type(Oid declared_type,
-                                Oid context_actual_type,
-                                Oid context_declared_type);
 
 extern CoercionPathType find_coercion_pathway(Oid targetTypeId,
                                              Oid sourceTypeId,
index 220f2d96cbf948d683816188de7ece79aa716e4d..348235a15e9e1ef36f6f3115ec7da8d52582d4e0 100644 (file)
@@ -1490,6 +1490,15 @@ select * from outparam_succeed(int4range(1,2));
  [1,2) | foo
 (1 row)
 
+create function outparam2_succeed(r anyrange, out lu anyarray, out ul anyarray)
+  as $$ select array[lower($1), upper($1)], array[upper($1), lower($1)] $$
+  language sql;
+select * from outparam2_succeed(int4range(1,11));
+   lu   |   ul   
+--------+--------
+ {1,11} | {11,1}
+(1 row)
+
 create function inoutparam_succeed(out i anyelement, inout r anyrange)
   as $$ select upper($1), $1 $$ language sql;
 select * from inoutparam_succeed(int4range(1,2));
@@ -1498,12 +1507,14 @@ select * from inoutparam_succeed(int4range(1,2));
  2 | [1,2)
 (1 row)
 
-create function table_succeed(i anyelement, r anyrange) returns table(i anyelement, r anyrange)
-  as $$ select $1, $2 $$ language sql;
-select * from table_succeed(123, int4range(1,11));
-  i  |   r    
------+--------
- 123 | [1,11)
+create function table_succeed(r anyrange)
+  returns table(l anyelement, u anyelement)
+  as $$ select lower($1), upper($1) $$
+  language sql;
+select * from table_succeed(int4range(1,11));
+ l | u  
+---+----
+ 1 | 11
 (1 row)
 
 -- should fail
index 72d80bc9d4662ea319f8eafceea84241588e2f77..85eaa9b34c67aba0af4a89fd39e653d630bc1218 100644 (file)
@@ -517,15 +517,23 @@ create function outparam_succeed(i anyrange, out r anyrange, out t text)
 
 select * from outparam_succeed(int4range(1,2));
 
+create function outparam2_succeed(r anyrange, out lu anyarray, out ul anyarray)
+  as $$ select array[lower($1), upper($1)], array[upper($1), lower($1)] $$
+  language sql;
+
+select * from outparam2_succeed(int4range(1,11));
+
 create function inoutparam_succeed(out i anyelement, inout r anyrange)
   as $$ select upper($1), $1 $$ language sql;
 
 select * from inoutparam_succeed(int4range(1,2));
 
-create function table_succeed(i anyelement, r anyrange) returns table(i anyelement, r anyrange)
-  as $$ select $1, $2 $$ language sql;
+create function table_succeed(r anyrange)
+  returns table(l anyelement, u anyelement)
+  as $$ select lower($1), upper($1) $$
+  language sql;
 
-select * from table_succeed(123, int4range(1,11));
+select * from table_succeed(int4range(1,11));
 
 -- should fail
 create function outparam_fail(i anyelement, out r anyrange, out t text)