Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
More code review for rangetypes patch.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Nov 2011 21:19:53 +0000 (16:19 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Nov 2011 21:19:53 +0000 (16:19 -0500)
Fix up some infelicitous coding in DefineRange, and add some missing error
checks.  Rearrange operator strategy number assignments for GiST anyrange
opclass so that they don't make such a mess of opr_sanity's table of
operator names associated with different strategy numbers.  Assign
hopefully-temporary selectivity estimators to range operators that didn't
have one --- poor as the estimates are, they're still a lot better than the
default 0.5 estimate, and they'll shut up the opr_sanity test that wants to
see selectivity estimators on all built-in operators.

src/backend/commands/typecmds.c
src/backend/utils/adt/rangetypes_gist.c
src/include/catalog/catversion.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_operator.h
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/plpgsql.out
src/test/regress/expected/rangetypes.out
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/rangetypes.sql

index 8ffbc52fdef14c2cb8282cedfa5f064dd01cc82f..54105f2c408106354592b11cead7dc56074c9747 100644 (file)
@@ -67,7 +67,6 @@
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
-#include "utils/rangetypes.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
@@ -85,6 +84,8 @@ typedef struct
 /* Potentially set by contrib/pg_upgrade_support functions */
 Oid            binary_upgrade_next_array_pg_type_oid = InvalidOid;
 
+static void makeRangeConstructors(const char *name, Oid namespace,
+                     Oid rangeOid, Oid subtype);
 static Oid findTypeInputFunction(List *procname, Oid typeOid);
 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
@@ -92,9 +93,9 @@ static Oid    findTypeSendFunction(List *procname, Oid typeOid);
 static Oid findTypeTypmodinFunction(List *procname);
 static Oid findTypeTypmodoutFunction(List *procname);
 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
+static Oid findRangeSubOpclass(List *opcname, Oid subtype);
 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
-static Oid findRangeSubOpclass(List *procname, Oid typeOid);
-static Oid findRangeSubtypeDiffFunction(List *procname, Oid typeOid);
+static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
 static void validateDomainConstraint(Oid domainoid, char *ccbin);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
 static void checkDomainOwner(HeapTuple tup);
@@ -103,8 +104,6 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
                    Oid baseTypeOid,
                    int typMod, Constraint *constr,
                    char *domainName);
-static void makeRangeConstructor(char *name, Oid namespace, Oid rettype,
-                    Oid subtype);
 
 
 /*
@@ -1154,6 +1153,61 @@ DefineEnum(CreateEnumStmt *stmt)
    pfree(enumArrayName);
 }
 
+/*
+ * AlterEnum
+ *     Adds a new label to an existing enum.
+ */
+void
+AlterEnum(AlterEnumStmt *stmt)
+{
+   Oid         enum_type_oid;
+   TypeName   *typename;
+   HeapTuple   tup;
+
+   /* Make a TypeName so we can use standard type lookup machinery */
+   typename = makeTypeNameFromNameList(stmt->typeName);
+   enum_type_oid = typenameTypeId(NULL, typename);
+
+   tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
+   if (!HeapTupleIsValid(tup))
+       elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
+
+   /* Check it's an enum and check user has permission to ALTER the enum */
+   checkEnumOwner(tup);
+
+   /* Add the new label */
+   AddEnumLabel(enum_type_oid, stmt->newVal,
+                stmt->newValNeighbor, stmt->newValIsAfter);
+
+   ReleaseSysCache(tup);
+}
+
+
+/*
+ * checkEnumOwner
+ *
+ * Check that the type is actually an enum and that the current user
+ * has permission to do ALTER TYPE on it.  Throw an error if not.
+ */
+static void
+checkEnumOwner(HeapTuple tup)
+{
+   Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
+
+   /* Check that this is actually an enum */
+   if (typTup->typtype != TYPTYPE_ENUM)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                errmsg("%s is not an enum",
+                       format_type_be(HeapTupleGetOid(tup)))));
+
+   /* Permission check: must own type */
+   if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+                      format_type_be(HeapTupleGetOid(tup)));
+}
+
+
 /*
  * DefineRange
  *     Registers a new range type.
@@ -1162,20 +1216,21 @@ void
 DefineRange(CreateRangeStmt *stmt)
 {
    char       *typeName;
-   char       *rangeArrayName;
    Oid         typeNamespace;
    Oid         typoid;
+   char       *rangeArrayName;
    Oid         rangeArrayOid;
-   List       *parameters = stmt->params;
+   Oid         rangeSubtype = InvalidOid;
    List       *rangeSubOpclassName = NIL;
-   List       *rangeSubtypeDiffName = NIL;
    List       *rangeCollationName = NIL;
-   Oid         rangeCollation = InvalidOid;
-   regproc     rangeAnalyze = InvalidOid;
-   Oid         rangeSubtype = InvalidOid;
-   regproc     rangeSubOpclass = InvalidOid;
-   regproc     rangeCanonical = InvalidOid;
-   regproc     rangeSubtypeDiff = InvalidOid;
+   List       *rangeCanonicalName = NIL;
+   List       *rangeSubtypeDiffName = NIL;
+   List       *rangeAnalyzeName = NIL;
+   Oid         rangeSubOpclass;
+   Oid         rangeCollation;
+   regproc     rangeCanonical;
+   regproc     rangeSubtypeDiff;
+   regproc     rangeAnalyze;
    int16       subtyplen;
    bool        subtypbyval;
    char        subtypalign;
@@ -1194,8 +1249,7 @@ DefineRange(CreateRangeStmt *stmt)
                       get_namespace_name(typeNamespace));
 
    /*
-    * Look to see if type already exists (presumably as a shell; if not,
-    * TypeCreate will complain).
+    * Look to see if type already exists.
     */
    typoid = GetSysCacheOid2(TYPENAMENSP,
                             CStringGetDatum(typeName),
@@ -1209,37 +1263,27 @@ DefineRange(CreateRangeStmt *stmt)
    {
        if (moveArrayTypeName(typoid, typeName, typeNamespace))
            typoid = InvalidOid;
+       else
+           ereport(ERROR,
+                   (errcode(ERRCODE_DUPLICATE_OBJECT),
+                    errmsg("type \"%s\" already exists", typeName)));
    }
 
    /*
     * If it doesn't exist, create it as a shell, so that the OID is known for
-    * use in the I/O function definitions.
+    * use in the range function definitions.
     */
    if (!OidIsValid(typoid))
    {
        typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
        /* Make new shell type visible for modification below */
        CommandCounterIncrement();
-
-       /*
-        * If the command was a parameterless CREATE TYPE, we're done ---
-        * creating the shell type was all we're supposed to do.
-        */
-       if (parameters == NIL)
-           return;
-   }
-   else
-   {
-       /* Complain if dummy CREATE TYPE and entry already exists */
-       if (parameters == NIL)
-           ereport(ERROR,
-                   (errcode(ERRCODE_DUPLICATE_OBJECT),
-                    errmsg("type \"%s\" already exists", typeName)));
    }
 
+   /* Extract the parameters from the parameter list */
    foreach(lc, stmt->params)
    {
-       DefElem    *defel = lfirst(lc);
+       DefElem    *defel = (DefElem *) lfirst(lc);
 
        if (pg_strcasecmp(defel->defname, "subtype") == 0)
        {
@@ -1247,16 +1291,16 @@ DefineRange(CreateRangeStmt *stmt)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
+           /* we can look up the subtype name immediately */
            rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
        }
-       else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+       else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
        {
-           if (OidIsValid(rangeCanonical))
+           if (rangeSubOpclassName != NIL)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
-           rangeCanonical = findRangeCanonicalFunction(
-                                        defGetQualifiedName(defel), typoid);
+           rangeSubOpclassName = defGetQualifiedName(defel);
        }
        else if (pg_strcasecmp(defel->defname, "collation") == 0)
        {
@@ -1266,63 +1310,87 @@ DefineRange(CreateRangeStmt *stmt)
                         errmsg("conflicting or redundant options")));
            rangeCollationName = defGetQualifiedName(defel);
        }
-       else if (pg_strcasecmp(defel->defname, "analyze") == 0)
+       else if (pg_strcasecmp(defel->defname, "canonical") == 0)
        {
-           if (OidIsValid(rangeAnalyze))
+           if (rangeCanonicalName != NIL)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
-           rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel),
-                                                  typoid);
+           rangeCanonicalName = defGetQualifiedName(defel);
        }
-       else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+       else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
        {
-           if (rangeSubOpclassName != NIL)
+           if (rangeSubtypeDiffName != NIL)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
-           rangeSubOpclassName = defGetQualifiedName(defel);
+           rangeSubtypeDiffName = defGetQualifiedName(defel);
        }
-       else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+       else if (pg_strcasecmp(defel->defname, "analyze") == 0)
        {
-           if (rangeSubtypeDiffName != NIL)
+           if (rangeAnalyzeName != NIL)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
-           rangeSubtypeDiffName = defGetQualifiedName(defel);
+           rangeAnalyzeName = defGetQualifiedName(defel);
        }
        else
-       {
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("type attribute \"%s\" not recognized",
                            defel->defname)));
-           continue;
-       }
    }
 
+   /* Must have a subtype */
    if (!OidIsValid(rangeSubtype))
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("type attribute \"subtype\" is required")));
+   /* disallow ranges of pseudotypes */
+   if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
+       ereport(ERROR,
+               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                errmsg("range subtype cannot be %s",
+                       format_type_be(rangeSubtype))));
 
+   /* Identify subopclass */
+   rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
+
+   /* Identify collation to use, if any */
    if (type_is_collatable(rangeSubtype))
    {
-       if (rangeCollationName == NIL)
-           rangeCollation = get_typcollation(rangeSubtype);
-       else
+       if (rangeCollationName != NIL)
            rangeCollation = get_collation_oid(rangeCollationName, false);
+       else
+           rangeCollation = get_typcollation(rangeSubtype);
+   }
+   else
+   {
+       if (rangeCollationName != NIL)
+           ereport(ERROR,
+                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                    errmsg("range collation specified but subtype does not support collation")));
+       rangeCollation = InvalidOid;
    }
-   else if (rangeCollationName != NIL)
-       ereport(ERROR,
-               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                errmsg("range collation specified but subtype does not support collation")));
 
-   rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
+   /* Identify support functions, if provided */
+   if (rangeCanonicalName != NIL)
+       rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
+                                                   typoid);
+   else
+       rangeCanonical = InvalidOid;
 
    if (rangeSubtypeDiffName != NIL)
        rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
                                                        rangeSubtype);
+   else
+       rangeSubtypeDiff = InvalidOid;
+
+   if (rangeAnalyzeName != NIL)
+       rangeAnalyze = findTypeAnalyzeFunction(rangeAnalyzeName,
+                                              typoid);
+   else
+       rangeAnalyze = InvalidOid;
 
    get_typlenbyvalalign(rangeSubtype,
                         &subtyplen, &subtypbyval, &subtypalign);
@@ -1358,16 +1426,16 @@ DefineRange(CreateRangeStmt *stmt)
                   rangeArrayOid,       /* array type we are about to create */
                   InvalidOid,  /* base type ID (only for domains) */
                   NULL,        /* never a default type value */
-                  NULL,        /* binary default isn't sent either */
+                  NULL,        /* no binary form available either */
                   false,       /* never passed by value */
                   alignment,   /* alignment */
                   'x',         /* TOAST strategy (always extended) */
                   -1,          /* typMod (Domains only) */
                   0,           /* Array dimensions of typbasetype */
                   false,       /* Type NOT NULL */
-                  InvalidOid); /* typcollation */
+                  InvalidOid); /* type's collation (ranges never have one) */
 
-   /* create the entry in pg_range */
+   /* Create the entry in pg_range */
    RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
                rangeCanonical, rangeSubtypeDiff);
 
@@ -1411,61 +1479,64 @@ DefineRange(CreateRangeStmt *stmt)
    pfree(rangeArrayName);
 
    /* And create the constructor functions for this range type */
-   makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype);
+   makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
 }
 
 /*
- * Because there may exist several range types over one subtype, the range type
- * can't be determined from the subtype. This means that constructors can't be
- * polymorphic, and so we must generate a new constructor for every range type
- * defined.
+ * Because there may exist several range types over the same subtype, the
+ * range type can't be uniquely determined from the subtype.  So it's
+ * impossible to define a polymorphic constructor; we have to generate new
+ * constructor functions explicitly for each range type.
  *
- * We actually define 4 functions with 0 through 3 arguments. This is just to
- * offer more convenience for the user.
+ * We actually define 4 functions, with 0 through 3 arguments.  This is just
+ * to offer more convenience for the user.
  */
 static void
-makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
+makeRangeConstructors(const char *name, Oid namespace,
+                     Oid rangeOid, Oid subtype)
 {
-   ObjectAddress referenced;
+   static const char * const prosrc[4] = {"range_constructor0",
+                                          "range_constructor1",
+                                          "range_constructor2",
+                                          "range_constructor3"};
+   static const int pronargs[4] = {0, 1, 2, 3};
+
    Oid         constructorArgTypes[3];
+   ObjectAddress myself,
+               referenced;
    int         i;
 
-   referenced.classId = TypeRelationId;
-   referenced.objectId = rangeOid;
-   referenced.objectSubId = 0;
-
    constructorArgTypes[0] = subtype;
    constructorArgTypes[1] = subtype;
    constructorArgTypes[2] = TEXTOID;
 
-   for (i = 0; i < 4; i++)
+   referenced.classId = TypeRelationId;
+   referenced.objectId = rangeOid;
+   referenced.objectSubId = 0;
+
+   for (i = 0; i < lengthof(prosrc); i++)
    {
        oidvector  *constructorArgTypesVector;
-       ObjectAddress myself;
        Oid         procOid;
-       char       *prosrc[4] = {"range_constructor0",
-           "range_constructor1",
-           "range_constructor2",
-       "range_constructor3"};
 
-       constructorArgTypesVector = buildoidvector(constructorArgTypes, i);
+       constructorArgTypesVector = buildoidvector(constructorArgTypes,
+                                                  pronargs[i]);
 
-       procOid = ProcedureCreate(
-                                 name, /* name */
+       procOid = ProcedureCreate(name,         /* name: same as range type */
                                  namespace,    /* namespace */
                                  false,        /* replace */
-                                 false,        /* return set */
+                                 false,        /* returns set */
                                  rangeOid,     /* return type */
                                  INTERNALlanguageId,   /* language */
                                  F_FMGR_INTERNAL_VALIDATOR,    /* language validator */
                                  prosrc[i],    /* prosrc */
-                                 NULL, /* probin */
-                                 false,        /* agg */
-                                 false,        /* window */
-                                 false,        /* security definer */
-                                 false,        /* strict */
+                                 NULL,         /* probin */
+                                 false,        /* isAgg */
+                                 false,        /* isWindowFunc */
+                                 false,        /* security_definer */
+                                 false,        /* isStrict */
                                  PROVOLATILE_IMMUTABLE,        /* volatility */
-                                 constructorArgTypesVector,    /* param types */
+                                 constructorArgTypesVector,    /* parameterTypes */
                                  PointerGetDatum(NULL),        /* allParameterTypes */
                                  PointerGetDatum(NULL),        /* parameterModes */
                                  PointerGetDatum(NULL),        /* parameterNames */
@@ -1482,64 +1553,11 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
        myself.classId = ProcedureRelationId;
        myself.objectId = procOid;
        myself.objectSubId = 0;
+
        recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    }
 }
 
-/*
- * AlterEnum
- *     Adds a new label to an existing enum.
- */
-void
-AlterEnum(AlterEnumStmt *stmt)
-{
-   Oid         enum_type_oid;
-   TypeName   *typename;
-   HeapTuple   tup;
-
-   /* Make a TypeName so we can use standard type lookup machinery */
-   typename = makeTypeNameFromNameList(stmt->typeName);
-   enum_type_oid = typenameTypeId(NULL, typename);
-
-   tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
-   if (!HeapTupleIsValid(tup))
-       elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
-
-   /* Check it's an enum and check user has permission to ALTER the enum */
-   checkEnumOwner(tup);
-
-   /* Add the new label */
-   AddEnumLabel(enum_type_oid, stmt->newVal,
-                stmt->newValNeighbor, stmt->newValIsAfter);
-
-   ReleaseSysCache(tup);
-}
-
-
-/*
- * checkEnumOwner
- *
- * Check that the type is actually an enum and that the current user
- * has permission to do ALTER TYPE on it.  Throw an error if not.
- */
-static void
-checkEnumOwner(HeapTuple tup)
-{
-   Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
-
-   /* Check that this is actually an enum */
-   if (typTup->typtype != TYPTYPE_ENUM)
-       ereport(ERROR,
-               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                errmsg("%s is not an enum",
-                       format_type_be(HeapTupleGetOid(tup)))));
-
-   /* Permission check: must own type */
-   if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
-       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
-                      format_type_be(HeapTupleGetOid(tup)));
-}
-
 
 /*
  * Find suitable I/O functions for a type.
@@ -1801,99 +1819,120 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
    return procOid;
 }
 
+/*
+ * Find suitable support functions and opclasses for a range type.
+ */
+
 /*
  * Find named btree opclass for subtype, or default btree opclass if
- * opcname is NIL. This will be used for comparing values of subtype.
+ * opcname is NIL.
  */
 static Oid
 findRangeSubOpclass(List *opcname, Oid subtype)
 {
    Oid         opcid;
+   Oid         opInputType;
+
+   if (opcname != NIL)
+   {
+       opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
 
-   if (opcname == NIL)
+       /*
+        * Verify that the operator class accepts this datatype. Note we will
+        * accept binary compatibility.
+        */
+       opInputType = get_opclass_input_type(opcid);
+       if (!IsBinaryCoercible(subtype, opInputType))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg("operator class \"%s\" does not accept data type %s",
+                           NameListToString(opcname),
+                           format_type_be(subtype))));
+   }
+   else
    {
        opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
        if (!OidIsValid(opcid))
        {
+           /* We spell the error message identically to GetIndexOpClass */
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
-                    errmsg("data type %s has no default operator class for access method \"btree\"",
-                           format_type_be(subtype)),
-                    errhint("You must specify an operator class for the data type or define a default operator class for the data type.")));
+                    errmsg("data type %s has no default operator class for access method \"%s\"",
+                           format_type_be(subtype), "btree"),
+                    errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
        }
-       return opcid;
    }
 
-   opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
-
    return opcid;
 }
 
-/*
- * Used to find a range's 'canonical' function.
- */
 static Oid
-findRangeSubtypeDiffFunction(List *procname, Oid typeOid)
+findRangeCanonicalFunction(List *procname, Oid typeOid)
 {
-   Oid         argList[2];
+   Oid         argList[1];
    Oid         procOid;
 
+   /*
+    * Range canonical functions must take and return the range type, and must
+    * be immutable.
+    */
    argList[0] = typeOid;
-   argList[1] = typeOid;
 
-   procOid = LookupFuncName(procname, 2, argList, true);
+   procOid = LookupFuncName(procname, 1, argList, true);
 
    if (!OidIsValid(procOid))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("function %s does not exist",
-                       func_signature_string(procname, 2, NIL, argList))));
+                       func_signature_string(procname, 1, NIL, argList))));
 
-   if (get_func_rettype(procOid) != FLOAT8OID)
+   if (get_func_rettype(procOid) != typeOid)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-        errmsg("range subtype diff function %s must return type \"float8\"",
-               func_signature_string(procname, 2, NIL, argList))));
+                errmsg("range canonical function %s must return range type",
+                       func_signature_string(procname, 1, NIL, argList))));
 
    if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                errmsg("range subtype diff function %s must be immutable",
-                       func_signature_string(procname, 2, NIL, argList))));
+                errmsg("range canonical function %s must be immutable",
+                       func_signature_string(procname, 1, NIL, argList))));
 
    return procOid;
 }
 
-/*
- * Used to find a range's 'canonical' function.
- */
 static Oid
-findRangeCanonicalFunction(List *procname, Oid typeOid)
+findRangeSubtypeDiffFunction(List *procname, Oid subtype)
 {
-   Oid         argList[1];
+   Oid         argList[2];
    Oid         procOid;
 
-   argList[0] = typeOid;
+   /*
+    * Range subtype diff functions must take two arguments of the subtype,
+    * must return float8, and must be immutable.
+    */
+   argList[0] = subtype;
+   argList[1] = subtype;
 
-   procOid = LookupFuncName(procname, 1, argList, true);
+   procOid = LookupFuncName(procname, 2, argList, true);
 
    if (!OidIsValid(procOid))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("function %s does not exist",
-                       func_signature_string(procname, 1, NIL, argList))));
+                       func_signature_string(procname, 2, NIL, argList))));
 
-   if (get_func_rettype(procOid) != typeOid)
+   if (get_func_rettype(procOid) != FLOAT8OID)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                errmsg("range canonical function %s must return range type",
-                       NameListToString(procname))));
+                errmsg("range subtype diff function %s must return type double precision",
+                       func_signature_string(procname, 2, NIL, argList))));
 
    if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                errmsg("range canonical function %s must be immutable",
-                       func_signature_string(procname, 1, NIL, argList))));
+                errmsg("range subtype diff function %s must be immutable",
+                       func_signature_string(procname, 2, NIL, argList))));
 
    return procOid;
 }
index 3eb177a5ced1227841a94957d6050938608b1507..3fc05d2650be3546c3bb0c3591907665c1f4828e 100644 (file)
 
 
 /* Operator strategy numbers used in the GiST range opclass */
-#define RANGESTRAT_EQ                  1
-#define RANGESTRAT_NE                  2
+/* Numbers are chosen to match up operator names with existing usages */
+#define RANGESTRAT_BEFORE              1
+#define RANGESTRAT_OVERLEFT                2
 #define RANGESTRAT_OVERLAPS                3
-#define RANGESTRAT_CONTAINS_ELEM       4
-#define RANGESTRAT_ELEM_CONTAINED_BY   5
-#define RANGESTRAT_CONTAINS                6
-#define RANGESTRAT_CONTAINED_BY            7
-#define RANGESTRAT_BEFORE              8
-#define RANGESTRAT_AFTER               9
-#define RANGESTRAT_OVERLEFT                10
-#define RANGESTRAT_OVERRIGHT           11
-#define RANGESTRAT_ADJACENT                12
+#define RANGESTRAT_OVERRIGHT           4
+#define RANGESTRAT_AFTER               5
+#define RANGESTRAT_ADJACENT                6
+#define RANGESTRAT_CONTAINS                7
+#define RANGESTRAT_CONTAINED_BY            8
+#define RANGESTRAT_CONTAINS_ELEM       16
+#define RANGESTRAT_ELEM_CONTAINED_BY   17
+#define RANGESTRAT_EQ                  18
+#define RANGESTRAT_NE                  19
 
 #define RangeIsEmpty(r)  (range_get_flags(r) & RANGE_EMPTY)
 
@@ -460,47 +461,33 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
 
    switch (strategy)
    {
-       case RANGESTRAT_EQ:
-           proc = range_contains;
-           break;
-       case RANGESTRAT_NE:
-           return true;
-           break;
-       case RANGESTRAT_OVERLAPS:
-           proc = range_overlaps;
-           break;
-       case RANGESTRAT_CONTAINS_ELEM:
-       case RANGESTRAT_CONTAINS:
-           proc = range_contains;
-           break;
-       case RANGESTRAT_ELEM_CONTAINED_BY:
-       case RANGESTRAT_CONTAINED_BY:
-           return true;
-           break;
        case RANGESTRAT_BEFORE:
            if (RangeIsEmpty(key))
                return false;
            proc = range_overright;
            negate = true;
            break;
-       case RANGESTRAT_AFTER:
-           if (RangeIsEmpty(key))
-               return false;
-           proc = range_overleft;
-           negate = true;
-           break;
        case RANGESTRAT_OVERLEFT:
            if (RangeIsEmpty(key))
                return false;
            proc = range_after;
            negate = true;
            break;
+       case RANGESTRAT_OVERLAPS:
+           proc = range_overlaps;
+           break;
        case RANGESTRAT_OVERRIGHT:
            if (RangeIsEmpty(key))
                return false;
            proc = range_before;
            negate = true;
            break;
+       case RANGESTRAT_AFTER:
+           if (RangeIsEmpty(key))
+               return false;
+           proc = range_overleft;
+           negate = true;
+           break;
        case RANGESTRAT_ADJACENT:
            if (RangeIsEmpty(key) || RangeIsEmpty(query))
                return false;
@@ -510,6 +497,20 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
                return true;
            proc = range_overlaps;
            break;
+       case RANGESTRAT_CONTAINS:
+       case RANGESTRAT_CONTAINS_ELEM:
+           proc = range_contains;
+           break;
+       case RANGESTRAT_CONTAINED_BY:
+       case RANGESTRAT_ELEM_CONTAINED_BY:
+           return true;
+           break;
+       case RANGESTRAT_EQ:
+           proc = range_contains;
+           break;
+       case RANGESTRAT_NE:
+           return true;
+           break;
        default:
            elog(ERROR, "unrecognized range strategy: %d", strategy);
            proc = NULL;        /* keep compiler quiet */
@@ -536,48 +537,48 @@ range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy,
 
    switch (strategy)
    {
-       case RANGESTRAT_EQ:
-           proc = range_eq;
-           break;
-       case RANGESTRAT_NE:
-           proc = range_ne;
-           break;
-       case RANGESTRAT_OVERLAPS:
-           proc = range_overlaps;
-           break;
-       case RANGESTRAT_CONTAINS_ELEM:
-       case RANGESTRAT_CONTAINS:
-           proc = range_contains;
-           break;
-       case RANGESTRAT_ELEM_CONTAINED_BY:
-       case RANGESTRAT_CONTAINED_BY:
-           proc = range_contained_by;
-           break;
        case RANGESTRAT_BEFORE:
            if (RangeIsEmpty(key) || RangeIsEmpty(query))
                return false;
            proc = range_before;
            break;
-       case RANGESTRAT_AFTER:
-           if (RangeIsEmpty(key) || RangeIsEmpty(query))
-               return false;
-           proc = range_after;
-           break;
        case RANGESTRAT_OVERLEFT:
            if (RangeIsEmpty(key) || RangeIsEmpty(query))
                return false;
            proc = range_overleft;
            break;
+       case RANGESTRAT_OVERLAPS:
+           proc = range_overlaps;
+           break;
        case RANGESTRAT_OVERRIGHT:
            if (RangeIsEmpty(key) || RangeIsEmpty(query))
                return false;
            proc = range_overright;
            break;
+       case RANGESTRAT_AFTER:
+           if (RangeIsEmpty(key) || RangeIsEmpty(query))
+               return false;
+           proc = range_after;
+           break;
        case RANGESTRAT_ADJACENT:
            if (RangeIsEmpty(key) || RangeIsEmpty(query))
                return false;
            proc = range_adjacent;
            break;
+       case RANGESTRAT_CONTAINS:
+       case RANGESTRAT_CONTAINS_ELEM:
+           proc = range_contains;
+           break;
+       case RANGESTRAT_CONTAINED_BY:
+       case RANGESTRAT_ELEM_CONTAINED_BY:
+           proc = range_contained_by;
+           break;
+       case RANGESTRAT_EQ:
+           proc = range_eq;
+           break;
+       case RANGESTRAT_NE:
+           proc = range_ne;
+           break;
        default:
            elog(ERROR, "unrecognized range strategy: %d", strategy);
            proc = NULL;        /* keep compiler quiet */
index 6ed527b23e666390e454edeb2c40e229d9bff8f5..c397151370c968cef7f31feebe354e2a02b14005 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201111171
+#define CATALOG_VERSION_NO 201111211
 
 #endif
index 108ed89c20a3a81ee91efc994aa3194479d448ae..a240063a3fdc2ee70d1e2e1ae71ba7ea66d4077a 100644 (file)
@@ -726,17 +726,17 @@ DATA(insert ( 3903   3831 3831 1 s    3882 405 0 ));
 /*
  * GiST range_ops
  */
-DATA(insert (  3919   3831 3831 1 s    3882 783 0 ));
-DATA(insert (  3919   3831 3831 2 s    3883 783 0 ));
+DATA(insert (  3919   3831 3831 1 s    3893 783 0 ));
+DATA(insert (  3919   3831 3831 2 s    3895 783 0 ));
 DATA(insert (  3919   3831 3831 3 s    3888 783 0 ));
-DATA(insert (  3919   3831 2283 4 s    3889 783 0 ));
-DATA(insert (  3919   2283 3831 5 s    3891 783 0 ));
-DATA(insert (  3919   3831 3831 6 s    3890 783 0 ));
-DATA(insert (  3919   3831 3831 7 s    3892 783 0 ));
-DATA(insert (  3919   3831 3831 8 s    3893 783 0 ));
-DATA(insert (  3919   3831 3831 9 s    3894 783 0 ));
-DATA(insert (  3919   3831 3831 10 s   3895 783 0 ));
-DATA(insert (  3919   3831 3831 11 s   3896 783 0 ));
-DATA(insert (  3919   3831 3831 12 s   3897 783 0 ));
+DATA(insert (  3919   3831 3831 4 s    3896 783 0 ));
+DATA(insert (  3919   3831 3831 5 s    3894 783 0 ));
+DATA(insert (  3919   3831 3831 6 s    3897 783 0 ));
+DATA(insert (  3919   3831 3831 7 s    3890 783 0 ));
+DATA(insert (  3919   3831 3831 8 s    3892 783 0 ));
+DATA(insert (  3919   3831 2283 16 s   3889 783 0 ));
+DATA(insert (  3919   2283 3831 17 s   3891 783 0 ));
+DATA(insert (  3919   3831 3831 18 s   3882 783 0 ));
+DATA(insert (  3919   3831 3831 19 s   3883 783 0 ));
 
 #endif   /* PG_AMOP_H */
index 2d1a2800a488a51737977089316eddaf21eda499..eac5cb94e6f773fdd93cfdb8231ef3de37fcefeb 100644 (file)
@@ -1674,15 +1674,15 @@ DATA(insert OID = 3886 (  ">="     PGNSP PGUID b f f 3831 3831 16 3885 3884 range
 DESCR("greater than or equal");
 DATA(insert OID = 3887 (  ">"     PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt scalargtsel scalargtjoinsel ));
 DESCR("greater than");
-DATA(insert OID = 3888 (  "&&"    PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps - - ));
+DATA(insert OID = 3888 (  "&&"    PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps areasel areajoinsel ));
 DESCR("overlaps");
-DATA(insert OID = 3889 (  "@>"    PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem - - ));
+DATA(insert OID = 3889 (  "@>"    PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem contsel contjoinsel ));
 DESCR("contains");
-DATA(insert OID = 3890 (  "@>"    PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains - - ));
+DATA(insert OID = 3890 (  "@>"    PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains contsel contjoinsel ));
 DESCR("contains");
-DATA(insert OID = 3891 (  "<@"    PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range - - ));
+DATA(insert OID = 3891 (  "<@"    PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range contsel contjoinsel ));
 DESCR("is contained by");
-DATA(insert OID = 3892 (  "<@"    PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by - - ));
+DATA(insert OID = 3892 (  "<@"    PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by contsel contjoinsel ));
 DESCR("is contained by");
 DATA(insert OID = 3893 (  "<<"    PGNSP PGUID b f f 3831 3831 16 3894 0 range_before scalarltsel scalarltjoinsel ));
 DESCR("is left of");
@@ -1692,7 +1692,7 @@ DATA(insert OID = 3895 (  "&<"       PGNSP PGUID b f f 3831 3831 16 0 0 range_overl
 DESCR("overlaps or is left of");
 DATA(insert OID = 3896 (  "&>"    PGNSP PGUID b f f 3831 3831 16 0 0 range_overright scalargtsel scalargtjoinsel ));
 DESCR("overlaps or is right of");
-DATA(insert OID = 3897 (  "-|-"       PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent - - ));
+DATA(insert OID = 3897 (  "-|-"       PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent contsel contjoinsel ));
 DESCR("is adjacent to");
 DATA(insert OID = 3898 (  "+"     PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - ));
 DESCR("range union");
index 19b559ffa17d1bc52230bc277019b4e2260342ac..db74fcb9e696dc37bfba4cc519be2fe133bf2ffb 100644 (file)
@@ -140,16 +140,16 @@ WHERE p1.oid < p2.oid AND
 -- need to be modified whenever new pairs of types are made binary-equivalent,
 -- or when new polymorphic built-in functions are added!
 -- Note: ignore aggregate functions here, since they all point to the same
--- dummy built-in function.
+-- dummy built-in function.  Likewise, ignore range constructor functions.
 SELECT DISTINCT p1.prorettype, p2.prorettype
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.prorettype < p2.prorettype) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.prorettype < p2.prorettype)
 ORDER BY 1, 2;
  prorettype | prorettype 
 ------------+------------
@@ -163,9 +163,9 @@ WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.proargtypes[0] < p2.proargtypes[0]) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.proargtypes[0] < p2.proargtypes[0])
 ORDER BY 1, 2;
  proargtypes | proargtypes 
 -------------+-------------
@@ -182,9 +182,9 @@ WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.proargtypes[1] < p2.proargtypes[1]) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.proargtypes[1] < p2.proargtypes[1])
 ORDER BY 1, 2;
  proargtypes | proargtypes 
 -------------+-------------
@@ -1021,34 +1021,28 @@ ORDER BY 1, 2, 3;
         403 |            5 | ~>~
         405 |            1 | =
         783 |            1 | <<
-        783 |            1 | =
         783 |            1 | @@
         783 |            2 | &<
-        783 |            2 | <>
         783 |            3 | &&
         783 |            4 | &>
-        783 |            4 | @>
-        783 |            5 | <@
         783 |            5 | >>
-        783 |            6 | @>
+        783 |            6 | -|-
         783 |            6 | ~=
-        783 |            7 | <@
         783 |            7 | @>
-        783 |            8 | <<
         783 |            8 | <@
         783 |            9 | &<|
-        783 |            9 | >>
-        783 |           10 | &<
         783 |           10 | <<|
         783 |           10 | <^
-        783 |           11 | &>
         783 |           11 | >^
         783 |           11 | |>>
-        783 |           12 | -|-
         783 |           12 | |&>
         783 |           13 | ~
         783 |           14 | @
         783 |           15 | <->
+        783 |           16 | @>
+        783 |           17 | <@
+        783 |           18 | =
+        783 |           19 | <>
         783 |           27 | @>
         783 |           28 | <@
         783 |           47 | @>
@@ -1061,7 +1055,7 @@ ORDER BY 1, 2, 3;
        2742 |            2 | @@@
        2742 |            3 | <@
        2742 |            4 | =
-(51 rows)
+(45 rows)
 
 -- Check that all opclass search operators have selectivity estimators.
 -- This is not absolutely required, but it seems a reasonable thing
@@ -1070,15 +1064,9 @@ SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
 WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
     (p2.oprrest = 0 OR p2.oprjoin = 0);
- amopfamily | amopopr | oid  | oprname 
-------------+---------+------+---------
-       3919 |    3888 | 3888 | &&
-       3919 |    3889 | 3889 | @>
-       3919 |    3891 | 3891 | <@
-       3919 |    3890 | 3890 | @>
-       3919 |    3892 | 3892 | <@
-       3919 |    3897 | 3897 | -|-
-(6 rows)
+ amopfamily | amopopr | oid | oprname 
+------------+---------+-----+---------
+(0 rows)
 
 -- Check that each opclass in an opfamily has associated operators, that is
 -- ones whose oprleft matches opcintype (possibly by coercion).
index fc9d4019444a733d768827afa9c699c404636c57..238bf5f0aec5e85e6af8598e4174797116644e25 100644 (file)
@@ -4571,17 +4571,3 @@ ERROR:  value for domain orderedarray violates check constraint "sorted"
 CONTEXT:  PL/pgSQL function "testoa" line 5 at assignment
 drop function arrayassign1();
 drop function testoa(x1 int, x2 int, x3 int);
--- Test resolve_polymorphic_argtypes() codepath. It is only taken when
--- a function is invoked from a different backend from where it's defined,
--- so we create the a function with polymorphic argument, reconnect, and
--- and then call it.
-create function rangetypes_plpgsql(out a anyelement, b anyrange, c anyarray)
-  language plpgsql as
-  $$ begin a := upper(b) + c[1]; return; end; $$;
-\c -
-select rangetypes_plpgsql(int4range(1,10),ARRAY[2,20]);
- rangetypes_plpgsql 
---------------------
-                 12
-(1 row)
-
index dec748406f9bcb2279adbc55248ac901977401c7..130446d006953fb936cdc780e83b6e83f4da2b52 100644 (file)
@@ -936,6 +936,20 @@ select range_add_bounds(numrange(1.0001, 123.123));
          124.1231
 (1 row)
 
+create function rangetypes_sql(q anyrange, b anyarray, out c anyelement)
+  as $$ select upper($1) + $2[1] $$
+  language sql;
+select rangetypes_sql(int4range(1,10), ARRAY[2,20]);
+ rangetypes_sql 
+----------------
+             12
+(1 row)
+
+select rangetypes_sql(numrange(1,10), ARRAY[2,20]);  -- match failure
+ERROR:  function rangetypes_sql(numrange, integer[]) does not exist
+LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]);
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 --
 -- Arrays of ranges
 --
index 7f936c815474205dc68cec8d5db96f786aadae9f..b0d143087e8fd68b30461c5d59b5bc5fdd3da086 100644 (file)
@@ -125,7 +125,7 @@ WHERE p1.oid < p2.oid AND
 -- need to be modified whenever new pairs of types are made binary-equivalent,
 -- or when new polymorphic built-in functions are added!
 -- Note: ignore aggregate functions here, since they all point to the same
--- dummy built-in function.
+-- dummy built-in function.  Likewise, ignore range constructor functions.
 
 SELECT DISTINCT p1.prorettype, p2.prorettype
 FROM pg_proc AS p1, pg_proc AS p2
@@ -133,9 +133,9 @@ WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.prorettype < p2.prorettype) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.prorettype < p2.prorettype)
 ORDER BY 1, 2;
 
 SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
@@ -144,9 +144,9 @@ WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.proargtypes[0] < p2.proargtypes[0]) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.proargtypes[0] < p2.proargtypes[0])
 ORDER BY 1, 2;
 
 SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
@@ -155,9 +155,9 @@ WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     NOT p1.proisagg AND NOT p2.proisagg AND
-    (p1.proargtypes[1] < p2.proargtypes[1]) AND
-    -- range constructor functions are shared by all range types.
-    NOT p1.prosrc LIKE 'range_constructor%'
+    p1.prosrc NOT LIKE E'range\\_constructor_' AND
+    p2.prosrc NOT LIKE E'range\\_constructor_' AND
+    (p1.proargtypes[1] < p2.proargtypes[1])
 ORDER BY 1, 2;
 
 SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
index 2906943f06fbac2a777960b3cbeb0b5303d40938..b47c2de312a102a1342f54c5101be95edfa4d3b2 100644 (file)
@@ -3600,13 +3600,3 @@ select testoa(1,2,1); -- fail at update
 
 drop function arrayassign1();
 drop function testoa(x1 int, x2 int, x3 int);
-
--- Test resolve_polymorphic_argtypes() codepath. It is only taken when
--- a function is invoked from a different backend from where it's defined,
--- so we create the a function with polymorphic argument, reconnect, and
--- and then call it.
-create function rangetypes_plpgsql(out a anyelement, b anyrange, c anyarray)
-  language plpgsql as
-  $$ begin a := upper(b) + c[1]; return; end; $$;
-\c -
-select rangetypes_plpgsql(int4range(1,10),ARRAY[2,20]);
index bdd40cf5a9dc78cb53a2c04a7729c8243eadcd43..b34a0d7c347463c2ca0724f04cd09f8c7e6d4a16 100644 (file)
@@ -327,6 +327,13 @@ create function range_add_bounds(anyrange)
 
 select range_add_bounds(numrange(1.0001, 123.123));
 
+create function rangetypes_sql(q anyrange, b anyarray, out c anyelement)
+  as $$ select upper($1) + $2[1] $$
+  language sql;
+
+select rangetypes_sql(int4range(1,10), ARRAY[2,20]);
+select rangetypes_sql(numrange(1,10), ARRAY[2,20]);  -- match failure
+
 --
 -- Arrays of ranges
 --