]> granicus.if.org Git - postgresql/commitdiff
Further code review for range types patch.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Nov 2011 04:50:27 +0000 (23:50 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Nov 2011 04:50:27 +0000 (23:50 -0500)
Fix some bugs in coercion logic and pg_dump; more comment cleanup;
minor cosmetic improvements.

13 files changed:
doc/src/sgml/datatype.sgml
src/backend/catalog/pg_proc.c
src/backend/commands/typecmds.c
src/backend/parser/parse_coerce.c
src/backend/tcop/utility.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/syscache.c
src/backend/utils/fmgr/funcapi.c
src/bin/pg_dump/pg_dump.c
src/include/nodes/parsenodes.h
src/include/utils/builtins.h
src/include/utils/rangetypes.h
src/pl/plpgsql/src/pl_comp.c

index fe59a1c7763ee970508bbd2d09f5d5dcb28cfd1f..152ef2f0378e4f932a71f5842b3daeceec94dc9d 100644 (file)
@@ -4506,6 +4506,12 @@ SELECT * FROM pg_attribute
         <entry>Indicates that a function accepts any input data type.</entry>
        </row>
 
+       <row>
+        <entry><type>anyelement</></entry>
+        <entry>Indicates that a function accepts any data type
+        (see <xref linkend="extend-types-polymorphic">).</entry>
+       </row>
+
        <row>
         <entry><type>anyarray</></entry>
         <entry>Indicates that a function accepts any array data type
@@ -4513,8 +4519,8 @@ SELECT * FROM pg_attribute
        </row>
 
        <row>
-        <entry><type>anyelement</></entry>
-        <entry>Indicates that a function accepts any data type
+        <entry><type>anynonarray</></entry>
+        <entry>Indicates that a function accepts any non-array data type
         (see <xref linkend="extend-types-polymorphic">).</entry>
        </row>
 
@@ -4532,12 +4538,6 @@ SELECT * FROM pg_attribute
         <xref linkend="rangetypes">).</entry>
        </row>
 
-       <row>
-        <entry><type>anynonarray</></entry>
-        <entry>Indicates that a function accepts any non-array data type
-        (see <xref linkend="extend-types-polymorphic">).</entry>
-       </row>
-
        <row>
         <entry><type>cstring</></entry>
         <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
@@ -4595,9 +4595,9 @@ SELECT * FROM pg_attribute
     languages all forbid use of a pseudo-type as argument type, and allow
     only <type>void</> and <type>record</> as a result type (plus
     <type>trigger</> when the function is used as a trigger).  Some also
-    support polymorphic functions using the types <type>anyarray</>,
-    <type>anyelement</>, <type>anyenum</>, <type>anyrange</>, and
-    <type>anynonarray</>.
+    support polymorphic functions using the types <type>anyelement</>,
+    <type>anyarray</>, <type>anynonarray</>, <type>anyenum</>, and
+    <type>anyrange</>.
    </para>
 
    <para>
index 8378c360b97f540821840b05e04e3f54acf3e056..a70a2aaecea68ef8c67969389233ebee1e511bce 100644 (file)
@@ -91,7 +91,7 @@ ProcedureCreate(const char *procedureName,
        int                     parameterCount;
        int                     allParamCount;
        Oid                *allParams;
-       char       *modes = NULL;
+       char       *paramModes = NULL;
        bool            genericInParam = false;
        bool            genericOutParam = false;
        bool            anyrangeInParam = false;
@@ -130,6 +130,7 @@ ProcedureCreate(const char *procedureName,
                                                           FUNC_MAX_ARGS)));
        /* note: the above is correct, we do NOT count output arguments */
 
+       /* Deconstruct array inputs */
        if (allParameterTypes != PointerGetDatum(NULL))
        {
                /*
@@ -169,28 +170,27 @@ ProcedureCreate(const char *procedureName,
                        ARR_HASNULL(modesArray) ||
                        ARR_ELEMTYPE(modesArray) != CHAROID)
                        elog(ERROR, "parameterModes is not a 1-D char array");
-               modes = (char *) ARR_DATA_PTR(modesArray);
+               paramModes = (char *) ARR_DATA_PTR(modesArray);
        }
 
-
        /*
-        * Do not allow polymorphic return type unless at least one input argument
-        * is polymorphic.      Also, do not allow return type INTERNAL unless at
-        * least one input argument is INTERNAL.
+        * Detect whether we have polymorphic or INTERNAL arguments.  The first
+        * loop checks input arguments, the second output arguments.
         */
        for (i = 0; i < parameterCount; i++)
        {
                switch (parameterTypes->values[i])
                {
-                       case ANYRANGEOID:
-                               anyrangeInParam = true;
-                               /* FALL THROUGH */
                        case ANYARRAYOID:
                        case ANYELEMENTOID:
                        case ANYNONARRAYOID:
                        case ANYENUMOID:
                                genericInParam = true;
                                break;
+                       case ANYRANGEOID:
+                               genericInParam = true;
+                               anyrangeInParam = true;
+                               break;
                        case INTERNALOID:
                                internalInParam = true;
                                break;
@@ -201,23 +201,23 @@ ProcedureCreate(const char *procedureName,
        {
                for (i = 0; i < allParamCount; i++)
                {
-                       if (modes == NULL ||
-                               (modes[i] != PROARGMODE_OUT &&
-                                modes[i] != PROARGMODE_INOUT &&
-                                modes[i] != PROARGMODE_TABLE))
-                                continue;
+                       if (paramModes == NULL ||
+                               paramModes[i] == PROARGMODE_IN ||
+                               paramModes[i] == PROARGMODE_VARIADIC)
+                               continue;               /* ignore input-only params */
 
                        switch (allParams[i])
                        {
-                               case ANYRANGEOID:
-                                       anyrangeOutParam = true;
-                                       /* FALL THROUGH */
                                case ANYARRAYOID:
                                case ANYELEMENTOID:
                                case ANYNONARRAYOID:
                                case ANYENUMOID:
                                        genericOutParam = true;
                                        break;
+                               case ANYRANGEOID:
+                                       genericOutParam = true;
+                                       anyrangeOutParam = true;
+                                       break;
                                case INTERNALOID:
                                        internalOutParam = true;
                                        break;
@@ -225,6 +225,13 @@ ProcedureCreate(const char *procedureName,
                }
        }
 
+       /*
+        * Do not allow polymorphic return type unless at least one input argument
+        * is polymorphic.  ANYRANGE return type is even stricter: must have an
+        * ANYRANGE input (since we can't deduce the specific range type from
+        * ANYELEMENT).  Also, do not allow return type INTERNAL unless at least
+        * one input argument is INTERNAL.
+        */
        if ((IsPolymorphicType(returnType) || genericOutParam)
                && !genericInParam)
                ereport(ERROR,
@@ -259,7 +266,7 @@ ProcedureCreate(const char *procedureName,
                                                procedureName,
                                                format_type_be(parameterTypes->values[0]))));
 
-       if (modes != NULL)
+       if (paramModes != NULL)
        {
                /*
                 * Only the last input parameter can be variadic; if it is, save its
@@ -268,7 +275,7 @@ ProcedureCreate(const char *procedureName,
                 */
                for (i = 0; i < allParamCount; i++)
                {
-                       switch (modes[i])
+                       switch (paramModes[i])
                        {
                                case PROARGMODE_IN:
                                case PROARGMODE_INOUT:
@@ -298,7 +305,7 @@ ProcedureCreate(const char *procedureName,
                                        }
                                        break;
                                default:
-                                       elog(ERROR, "invalid parameter mode '%c'", modes[i]);
+                                       elog(ERROR, "invalid parameter mode '%c'", paramModes[i]);
                                        break;
                        }
                }
index a1628bc098535d55f0bb7b054151abb5b514917a..8ffbc52fdef14c2cb8282cedfa5f064dd01cc82f 100644 (file)
@@ -654,9 +654,9 @@ RemoveTypeById(Oid typeOid)
                EnumValuesDelete(typeOid);
 
        /*
-        * If it is a range type, delete the pg_range entries too; we don't bother
-        * with making dependency entries for those, so it has to be done "by
-        * hand" here.
+        * If it is a range type, delete the pg_range entry too; we don't bother
+        * with making a dependency entry for that, so it has to be done "by hand"
+        * here.
         */
        if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
                RangeDelete(typeOid);
@@ -1475,8 +1475,9 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
                                                                  0.0); /* prorows */
 
                /*
-                * Make the constructor internally-dependent on the range type so that
-                * the user doesn't have to treat them as separate objects.
+                * Make the constructors internally-dependent on the range type so
+                * that they go away silently when the type is dropped.  Note that
+                * pg_dump depends on this choice to avoid dumping the constructors.
                 */
                myself.classId = ProcedureRelationId;
                myself.objectId = procOid;
index a461ac9aef1c60e10a0081e33ca4814a951f35a0..c07232544aa5a2cc427f7206a8d1cbfe66992d7a 100644 (file)
@@ -165,11 +165,12 @@ coerce_type(ParseState *pstate, Node *node,
                 * Assume can_coerce_type verified that implicit coercion is okay.
                 *
                 * These cases are unlike the ones above because the exposed type of
-                * the argument must be an actual array or enum type.  In particular
-                * the argument must *not* be an UNKNOWN constant.      If it is, we just
-                * fall through; below, we'll call anyarray_in or anyenum_in, which
-                * will produce an error.  Also, if what we have is a domain over
-                * array or enum, we have to relabel it to its base type.
+                * the argument must be an actual array, enum, or range type.  In
+                * particular the argument must *not* be an UNKNOWN constant.  If it
+                * is, we just fall through; below, we'll call anyarray_in,
+                * anyenum_in, or anyrange_in, which will produce an error.  Also, if
+                * what we have is a domain over array, enum, or range, we have to
+                * relabel it to its base type.
                 *
                 * Note: currently, we can't actually see a domain-over-enum here,
                 * since the other functions in this file will not match such a
@@ -1273,27 +1274,36 @@ coerce_to_common_type(ParseState *pstate, Node *node,
  *
  * The argument consistency rules are:
  *
- * 1) All arguments declared ANYARRAY must have matching datatypes,
- *       and must in fact be varlena arrays.
- * 2) All arguments declared ANYELEMENT must have matching datatypes.
- * 3) If there are arguments of both ANYELEMENT and ANYARRAY, make sure the
- *       actual ANYELEMENT datatype is in fact the element type for the actual
- *       ANYARRAY datatype. Similarly, if there are arguments of both ANYELEMENT
- *       and ANYRANGE, make sure the actual ANYELEMENT datatype is in fact the
- *       subtype for the actual ANYRANGE type.
- * 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.)
+ * 1) All arguments declared ANYELEMENT must have the same datatype.
+ * 2) All arguments declared ANYARRAY must have the same datatype,
+ *    which must be a varlena array type.
+ * 3) All arguments declared ANYRANGE must have the same datatype,
+ *    which must be a range type.
+ * 4) If there are arguments of both ANYELEMENT and ANYARRAY, make sure the
+ *    actual ANYELEMENT datatype is in fact the element type for the actual
+ *    ANYARRAY datatype.
+ * 5) Similarly, if there are arguments of both ANYELEMENT and ANYRANGE,
+ *    make sure the actual ANYELEMENT datatype is in fact the subtype for
+ *    the actual ANYRANGE type.
+ * 6) 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.
+ * 7) 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.)
  *
  * Domains over arrays match ANYARRAY, and are immediately flattened to their
  * base type.  (Thus, for example, we will consider it a match if one ANYARRAY
- * argument is a domain over int4[] while another one is just int4[].) Also
+ * argument is a domain over int4[] while another one is just int4[].)  Also
  * notice that such a domain does *not* match ANYNONARRAY.
  *
+ * Similarly, domains over ranges match ANYRANGE, and are immediately
+ * flattened to their base type.
+ *
+ * Note that domains aren't currently considered to match ANYENUM,
+ * even if their base type would match.
+ *
  * If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
  * argument, assume it is okay.
  *
@@ -1357,7 +1367,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
                {
                        if (actual_type == UNKNOWNOID)
                                continue;
-                       actual_type = getBaseType(actual_type);
+                       actual_type = getBaseType(actual_type);         /* flatten domains */
                        if (OidIsValid(range_typeid) && actual_type != range_typeid)
                                return false;
                        range_typeid = actual_type;
@@ -1393,20 +1403,6 @@ check_generic_type_consistency(Oid *actual_arg_types,
                }
        }
 
-       if (have_anynonarray)
-       {
-               /* require the element type to not be an array or domain over array */
-               if (type_is_array_domain(elem_typeid))
-                       return false;
-       }
-
-       if (have_anyenum)
-       {
-               /* require the element type to be an enum */
-               if (!type_is_enum(elem_typeid))
-                       return false;
-       }
-
        /* Get the element type based on the range type, if we have one */
        if (OidIsValid(range_typeid))
        {
@@ -1428,6 +1424,20 @@ check_generic_type_consistency(Oid *actual_arg_types,
                }
        }
 
+       if (have_anynonarray)
+       {
+               /* require the element type to not be an array or domain over array */
+               if (type_is_array_domain(elem_typeid))
+                       return false;
+       }
+
+       if (have_anyenum)
+       {
+               /* require the element type to be an enum */
+               if (!type_is_enum(elem_typeid))
+                       return false;
+       }
+
        /* Looks valid */
        return true;
 }
@@ -1439,7 +1449,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
  *
  * 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
+ * each other.  The argument consistency rules are shown above for
  * check_generic_type_consistency().
  *
  * If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
@@ -1451,51 +1461,51 @@ check_generic_type_consistency(Oid *actual_arg_types,
  * if it is declared as a polymorphic type:
  *
  * 1) If return type is ANYARRAY, and any argument is ANYARRAY, use the
- *       argument's actual type as the function's return type. Similarly, if
- *       return type is ANYRANGE, and any argument is ANYRANGE, use the argument's
- *       actual type as the function's return type.
- * 2) If return type is ANYARRAY, no argument is ANYARRAY, but any argument is
- *       ANYELEMENT, use the actual type of the argument to determine the
- *       function's return type, i.e. the element type's corresponding array
- *       type. Note: similar behavior does not exist for ANYRANGE, because it's
- *       impossble to determine the range type from the subtype alone.\
- * 3) If return type is ANYARRAY, no argument is ANYARRAY or ANYELEMENT,
- *       generate an ERROR. Similarly, if the return type is ANYRANGE, and no
- *       argument is ANYRANGE or ANYELEMENT, generate an error. These conditions
- *       are prevented by CREATE FUNCTION and is therefore not expected here.
- * 4) If return type is ANYELEMENT, and any argument is ANYELEMENT, use the
- *       argument's actual type as the function's return type.
- * 5) If return type is ANYELEMENT, no argument is ANYELEMENT, but any argument
- *       is ANYARRAY or ANYRANGE, use the actual type of the argument to determine
- *       the function's return type; i.e. the array type's corresponding element
- *       type or the range type's corresponding subtype (or both, in which case
- *       they must match).
- * 6) If return type is ANYELEMENT, no argument is ANYARRAY, ANYRANGE, or
- *       ANYELEMENT, generate an ERROR. This condition is prevented by CREATE
- *       FUNCTION and is therefore not expected here.
- * 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.)
+ *    argument's actual type as the function's return type.
+ * 2) Similarly, if return type is ANYRANGE, and any argument is ANYRANGE,
+ *    use the argument's actual type as the function's return type.
+ * 3) If return type is ANYARRAY, no argument is ANYARRAY, but any argument is
+ *    ANYELEMENT, use the actual type of the argument to determine the
+ *    function's return type, i.e. the element type's corresponding array
+ *    type.  (Note: similar behavior does not exist for ANYRANGE, because it's
+ *    impossible to determine the range type from the subtype alone.)
+ * 4) If return type is ANYARRAY, but no argument is ANYARRAY or ANYELEMENT,
+ *    generate an error.  Similarly, if return type is ANYRANGE, but no
+ *    argument is ANYRANGE, generate an error.  (These conditions are
+ *    prevented by CREATE FUNCTION and therefore are not expected here.)
+ * 5) If return type is ANYELEMENT, and any argument is ANYELEMENT, use the
+ *    argument's actual type as the function's return type.
+ * 6) If return type is ANYELEMENT, no argument is ANYELEMENT, but any argument
+ *    is ANYARRAY or ANYRANGE, use the actual type of the argument to determine
+ *    the function's return type, i.e. the array type's corresponding element
+ *    type or the range type's corresponding subtype (or both, in which case
+ *    they must match).
+ * 7) If return type is ANYELEMENT, no argument is ANYELEMENT, ANYARRAY, or
+ *    ANYRANGE, generate an error.  (This condition is prevented by CREATE
+ *    FUNCTION and therefore is not expected here.)
+ * 8) 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.
+ * 9) 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.)
  *
  * Domains over arrays or ranges match ANYARRAY or ANYRANGE arguments,
  * respectively, and are immediately flattened to their base type. (In
- * particular, if the return type is also ANYARRAY or ANYRANGE, we'll set it to
- * the base type not the domain type.)
+ * particular, if the return type is also ANYARRAY or ANYRANGE, we'll set it
+ * to the base type not the domain type.)
  *
  * When allow_poly is false, we are not expecting any of the actual_arg_types
  * to be polymorphic, and we should not return a polymorphic result type
- * either.     When allow_poly is true, it is okay to have polymorphic "actual"
- * arg types, and we can return ANYARRAY or ANYELEMENT as the result.  (This
- * case is currently used only to check compatibility of an aggregate's
- * declaration with the underlying transfn.)
+ * either.  When allow_poly is true, it is okay to have polymorphic "actual"
+ * arg types, and we can return ANYARRAY, ANYRANGE, or ANYELEMENT as the
+ * result.  (This case is currently used only to check compatibility of an
+ * aggregate's declaration with the underlying transfn.)
  *
  * A special case is that we could see ANYARRAY as an actual_arg_type even
  * when allow_poly is false (this is possible only because pg_statistic has
- * columns shown as anyarray in the catalogs). We allow this to match a
+ * columns shown as anyarray in the catalogs).  We allow this to match a
  * declared ANYARRAY argument, but only if there is no ANYELEMENT argument
  * or result (since we can't determine a specific element type to match to
  * ANYELEMENT).  Note this means that functions taking ANYARRAY had better
@@ -1612,7 +1622,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
                if (array_typeid == ANYARRAYOID && !have_anyelement)
                {
                        /* Special case for ANYARRAY input: okay iff no ANYELEMENT */
-                       array_typelem = InvalidOid;
+                       array_typelem = ANYELEMENTOID;
                }
                else
                {
@@ -1642,15 +1652,24 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
                                                           format_type_be(elem_typeid))));
                }
        }
+
        /* Get the element type based on the range type, if we have one */
-       else if (OidIsValid(range_typeid))
+       if (OidIsValid(range_typeid))
        {
-               range_typelem = get_range_subtype(range_typeid);
-               if (!OidIsValid(range_typelem))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
-                                        errmsg("argument declared \"anyrange\" is not a range but type %s",
-                                                       format_type_be(range_typeid))));
+               if (range_typeid == ANYRANGEOID && !have_anyelement)
+               {
+                       /* Special case for ANYRANGE input: okay iff no ANYELEMENT */
+                       range_typelem = ANYELEMENTOID;
+               }
+               else
+               {
+                       range_typelem = get_range_subtype(range_typeid);
+                       if (!OidIsValid(range_typelem))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                errmsg("argument declared \"anyrange\" is not a range but type %s",
+                                                               format_type_be(range_typeid))));
+               }
 
                if (!OidIsValid(elem_typeid))
                {
@@ -1670,12 +1689,14 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
                                                           format_type_be(elem_typeid))));
                }
        }
-       else if (!OidIsValid(elem_typeid))
+
+       if (!OidIsValid(elem_typeid))
        {
                if (allow_poly)
                {
-                       array_typeid = ANYARRAYOID;
                        elem_typeid = ANYELEMENTOID;
+                       array_typeid = ANYARRAYOID;
+                       range_typeid = ANYRANGEOID;
                }
                else
                {
@@ -1861,13 +1882,14 @@ resolve_generic_type(Oid declared_type,
                else if (context_declared_type == ANYRANGEOID)
                {
                        /* Use the element type corresponding to actual type */
-                       Oid                     range_typelem = get_range_subtype(context_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 \"anyrange\" is not a range but type %s",
-                                                               format_type_be(context_actual_type))));
+                                                               format_type_be(context_base_type))));
                        return range_typelem;
                }
                else if (context_declared_type == ANYELEMENTOID ||
@@ -1970,12 +1992,12 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
 
        /* Also accept any array type as coercible to ANYARRAY */
        if (targettype == ANYARRAYOID)
-               if (type_is_array_domain(srctype))
+               if (type_is_array(srctype))
                        return true;
 
        /* Also accept any non-array type as coercible to ANYNONARRAY */
        if (targettype == ANYNONARRAYOID)
-               if (!type_is_array_domain(srctype))
+               if (!type_is_array(srctype))
                        return true;
 
        /* Also accept any enum type as coercible to ANYENUM */
index cc8f32d4cea132745f8faf340da9b79a2c6048b6..6f88c476adae1a9564ea337ee6b42716c5f48159 100644 (file)
@@ -851,11 +851,11 @@ standard_ProcessUtility(Node *parsetree,
                        }
                        break;
 
-               case T_CreateEnumStmt:  /* CREATE TYPE (enum) */
+               case T_CreateEnumStmt:  /* CREATE TYPE AS ENUM */
                        DefineEnum((CreateEnumStmt *) parsetree);
                        break;
 
-               case T_CreateRangeStmt:
+               case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
                        DefineRange((CreateRangeStmt *) parsetree);
                        break;
 
index 1b4d26d6593f843d6c7dd2c025ebe2fe3b19df77..ceca0e3ede0f1b5584ae290b4cb08cd369d8bd10 100644 (file)
@@ -2253,7 +2253,7 @@ type_is_enum(Oid typid)
 
 /*
  * type_is_range
- *       Returns true if the given type is an range type.
+ *       Returns true if the given type is a range type.
  */
 bool
 type_is_range(Oid typid)
@@ -2867,6 +2867,14 @@ get_namespace_name(Oid nspid)
                return NULL;
 }
 
+/*                             ---------- PG_RANGE CACHE ----------                             */
+
+/*
+ * get_range_subtype
+ *             Returns the subtype of a given range type
+ *
+ * Returns InvalidOid if the type is not a range type.
+ */
 Oid
 get_range_subtype(Oid rangeOid)
 {
index 71b09abb232c93f26201fde1e949e1cfb46a2203..043030bd70fd04b81b542a44e04bd9f98668a9a2 100644 (file)
@@ -555,7 +555,7 @@ static const struct cachedesc cacheinfo[] = {
                },
                2048
        },
-       {RangeRelationId,               /* RANGETYPE */
+       {RangeRelationId,                       /* RANGETYPE */
                RangeTypidIndexId,
                1,
                {
@@ -564,7 +564,7 @@ static const struct cachedesc cacheinfo[] = {
                        0,
                        0
                },
-               1024
+               64
        },
        {RelationRelationId,            /* RELNAMENSP */
                ClassNameNspIndexId,
index 3cc2a7ee0758112b43f7919da812eb48f53775ba..d19be8708552e66e475ddf8ad98db077637b92ef 100644 (file)
@@ -481,14 +481,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                !OidIsValid(anyrange_type))
                return false;
 
-       /*
-        * We can't deduce a range type from the subtype, because there may be
-        * multiple range types for a single subtype.
-        */
-       if (have_anyrange_result && !OidIsValid(anyrange_type))
-               return false;
-
-       /* If needed, deduce one polymorphic type from the other */
+       /* If needed, deduce one polymorphic type from others */
        if (have_anyelement_result && !OidIsValid(anyelement_type))
        {
                if (OidIsValid(anyarray_type))
@@ -497,14 +490,14 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                                                                                                   ANYARRAYOID);
                if (OidIsValid(anyrange_type))
                {
-                       Oid subtype = resolve_generic_type(ANYELEMENTOID,
-                                                                                          anyrange_type,
-                                                                                          ANYRANGEOID);
-                       if (OidIsValid(anyelement_type) &&
-                               anyelement_type != subtype)
+                       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;
-                       else
-                               anyelement_type = subtype;
+                       anyelement_type = subtype;
                }
        }
 
@@ -513,6 +506,13 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                                                                                         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;
+
        /* Enforce ANYNONARRAY if needed */
        if (have_anynonarray && type_is_array(anyelement_type))
                return false;
@@ -523,9 +523,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 
        /*
         * Identify the collation to use for polymorphic OUT parameters. (It'll
-        * necessarily be the same for both anyelement and anyarray.)
+        * necessarily be the same for both anyelement and anyarray.)  Note that
+        * 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))
@@ -573,7 +574,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                                                                   anyrange_type,
                                                                   -1,
                                                                   0);
-                               TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
+                               /* no collation should be attached to a range type */
                                break;
                        default:
                                break;
@@ -672,19 +673,12 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
                !have_anyrange_result)
                return true;
 
-       /*
-        * We can't deduce a range type from the subtype, because there may be
-        * multiple range types for a single subtype.
-        */
-       if (have_anyrange_result && !OidIsValid(anyrange_type))
-               return false;
-
        /* 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 the other */
+       /* If needed, deduce one polymorphic type from others */
        if (have_anyelement_result && !OidIsValid(anyelement_type))
        {
                if (OidIsValid(anyarray_type))
@@ -693,14 +687,14 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
                                                                                                   ANYARRAYOID);
                if (OidIsValid(anyrange_type))
                {
-                       Oid subtype = resolve_generic_type(ANYELEMENTOID,
-                                                                                          anyrange_type,
-                                                                                          ANYRANGEOID);
-                       if (OidIsValid(anyelement_type) &&
-                               anyelement_type != subtype)
+                       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;
-                       else
-                               anyelement_type = subtype;
+                       anyelement_type = subtype;
                }
        }
 
@@ -709,6 +703,13 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
                                                                                         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;
+
        /* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
 
        /* And finally replace the output column types as needed */
index d2005c1e8092ed59e0bdffabba40b5c3a4c564b4..41114ac4da9373975744556d0f711bd3adbe951b 100644 (file)
@@ -52,7 +52,6 @@
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_largeobject_metadata.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_range.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
 #include "libpq/libpq-fs.h"
@@ -3703,34 +3702,16 @@ getFuncs(int *numFuncs)
         * pg_catalog.  In normal dumps we can still ignore those --- but in
         * binary-upgrade mode, we must dump the member objects of the extension,
         * so be sure to fetch any such functions.
+        *
+        * Also, in 9.2 and up, exclude functions that are internally dependent on
+        * something else, since presumably those will be created as a result of
+        * creating the something else.  This currently only acts to suppress
+        * constructor functions for range types.  Note that this is OK only
+        * because the constructors don't have any dependencies the range type
+        * doesn't have; otherwise we might not get creation ordering correct.
         */
 
-       if (g_fout->remoteVersion >= 90200)
-       {
-               appendPQExpBuffer(query,
-                                                 "SELECT tableoid, oid, proname, prolang, "
-                                                 "pronargs, proargtypes, prorettype, proacl, "
-                                                 "pronamespace, "
-                                                 "(%s proowner) AS rolname "
-                                                 "FROM pg_proc p "
-                                                 "WHERE NOT proisagg AND "
-                                                 " NOT EXISTS (SELECT 1 FROM pg_depend "
-                                                 "   WHERE classid = 'pg_proc'::regclass AND "
-                                                 "   objid = p.oid AND deptype = 'i') AND "
-                                                 "(pronamespace != "
-                                                 "(SELECT oid FROM pg_namespace "
-                                                 "WHERE nspname = 'pg_catalog')",
-                                                 username_subquery);
-               if (binary_upgrade && g_fout->remoteVersion >= 90100)
-                       appendPQExpBuffer(query,
-                                                         " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
-                                                         "classid = 'pg_proc'::regclass AND "
-                                                         "objid = p.oid AND "
-                                                         "refclassid = 'pg_extension'::regclass AND "
-                                                         "deptype = 'e')");
-               appendPQExpBuffer(query, ")");
-       }
-       else if (g_fout->remoteVersion >= 70300)
+       if (g_fout->remoteVersion >= 70300)
        {
                appendPQExpBuffer(query,
                                                  "SELECT tableoid, oid, proname, prolang, "
@@ -3743,9 +3724,14 @@ getFuncs(int *numFuncs)
                                                  "(SELECT oid FROM pg_namespace "
                                                  "WHERE nspname = 'pg_catalog')",
                                                  username_subquery);
+               if (g_fout->remoteVersion >= 90200)
+                       appendPQExpBuffer(query,
+                                                         "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
+                                                         "WHERE classid = 'pg_proc'::regclass AND "
+                                                         "objid = p.oid AND deptype = 'i')");
                if (binary_upgrade && g_fout->remoteVersion >= 90100)
                        appendPQExpBuffer(query,
-                                                         " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+                                                         "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
                                                          "classid = 'pg_proc'::regclass AND "
                                                          "objid = p.oid AND "
                                                          "refclassid = 'pg_extension'::regclass AND "
@@ -7479,31 +7465,25 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
        PQExpBuffer labelq = createPQExpBuffer();
        PQExpBuffer query = createPQExpBuffer();
        PGresult   *res;
+       Oid                     collationOid;
+       char       *procname;
 
-       Oid                      collationOid;
-       Oid                      opclassOid;
-       Oid                      analyzeOid;
-       Oid                      canonicalOid;
-       Oid                      subdiffOid;
-
-       /* Set proper schema search path */
-       selectSourceSchema("pg_catalog");
+       /*
+        * select appropriate schema to ensure names in CREATE are properly
+        * qualified
+        */
+       selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
        appendPQExpBuffer(query,
-                                         "SELECT rngtypid, "
-                                         "format_type(rngsubtype, NULL) as rngsubtype, "
-                                         "rngsubtype::oid as rngsubtypeoid, "
+                                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
                                          "opc.opcname AS opcname, "
+                                         "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
+                                         "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
+                                         "opc.opcdefault, "
                                          "CASE WHEN rngcollation = st.typcollation THEN 0 "
                                          "     ELSE rngcollation END AS collation, "
-                                         "CASE WHEN opcdefault THEN 0 ELSE rngsubopc END "
-                                         "  AS rngsubopc, "
-                                         "(SELECT nspname FROM pg_namespace nsp "
-                                         "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
-                                         "t.typanalyze, t.typanalyze::oid as typanalyzeoid, "
-                                         "rngcanonical, rngcanonical::oid as rngcanonicaloid, "
-                                         "rngsubdiff, rngsubdiff::oid as rngsubdiffoid "
-                                         "FROM pg_catalog.pg_type t, pg_type st, "
+                                         "rngcanonical, rngsubdiff, t.typanalyze "
+                                         "FROM pg_catalog.pg_type t, pg_catalog.pg_type st, "
                                          "     pg_catalog.pg_opclass opc, pg_catalog.pg_range r "
                                          "WHERE t.oid = rngtypid AND st.oid = rngsubtype AND "
                                          "      opc.oid = rngsubopc AND rngtypid = '%u'",
@@ -7511,6 +7491,12 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 
        res = PQexec(g_conn, query->data);
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+       if (PQntuples(res) != 1)
+       {
+               write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
+                                 PQntuples(res), tyinfo->dobj.name);
+               exit_nicely();
+       }
 
        /*
         * DROP must be fully qualified in case same name appears in pg_catalog.
@@ -7522,68 +7508,53 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
        appendPQExpBuffer(delq, "%s;\n",
                                          fmtId(tyinfo->dobj.name));
 
-       /* We might already have a shell type, but setting pg_type_oid is harmless */
        if (binary_upgrade)
                binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
 
        appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
                                          fmtId(tyinfo->dobj.name));
 
-       /* SUBTYPE */
-       appendPQExpBuffer(q, "\n    SUBTYPE = %s",
+       appendPQExpBuffer(q, "\n    subtype = %s",
                                          PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
 
-       /* COLLATION */
-       collationOid = atooid(PQgetvalue(res, 0,
-                                                                        PQfnumber(res, "collation")));
+       /* print subtype_opclass only if not default for subtype */
+       if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
+       {
+               char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
+               char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
+
+               /* always schema-qualify, don't try to be smart */
+               appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
+                                                 fmtId(nspname));
+               appendPQExpBuffer(q, "%s", fmtId(opcname));
+       }
+
+       collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
        if (OidIsValid(collationOid))
        {
-               CollInfo   *coll;
+               CollInfo   *coll = findCollationByOid(collationOid);
 
-               coll = findCollationByOid(collationOid);
                if (coll)
                {
                        /* always schema-qualify, don't try to be smart */
-                       appendPQExpBuffer(q, ",\n    COLLATION = %s.",
+                       appendPQExpBuffer(q, ",\n    collation = %s.",
                                                          fmtId(coll->dobj.namespace->dobj.name));
                        appendPQExpBuffer(q, "%s",
                                                          fmtId(coll->dobj.name));
                }
        }
 
-       /* SUBTYPE_OPCLASS */
-       opclassOid = atooid(PQgetvalue(res, 0,
-                                                                  PQfnumber(res, "rngsubopc")));
-       if (OidIsValid(opclassOid))
-       {
-               char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
-               char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
+       procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
+       if (strcmp(procname, "-") != 0)
+               appendPQExpBuffer(q, ",\n    canonical = %s", procname);
 
-               /* always schema-qualify, don't try to be smart */
-               appendPQExpBuffer(q, ",\n    SUBTYPE_OPCLASS = %s.",
-                                                 fmtId(nspname));
-               appendPQExpBuffer(q, "%s", fmtId(opcname));
-       }
+       procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
+       if (strcmp(procname, "-") != 0)
+               appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
 
-       /* ANALYZE */
-       analyzeOid = atooid(PQgetvalue(res, 0,
-                                                                  PQfnumber(res, "typanalyzeoid")));
-       if (OidIsValid(analyzeOid))
-               appendPQExpBuffer(q, ",\n    ANALYZE = %s",
-                                                 PQgetvalue(res, 0, PQfnumber(res, "typanalyze")));
-
-       /* CANONICAL */
-       canonicalOid = atooid(PQgetvalue(res, 0,
-                                                                        PQfnumber(res, "rngcanonicaloid")));
-       if (OidIsValid(canonicalOid))
-               appendPQExpBuffer(q, ",\n    CANONICAL = %s",
-                                                 PQgetvalue(res, 0, PQfnumber(res, "rngcanonical")));
-
-       /* SUBTYPE_DIFF */
-       subdiffOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "rngsubdiffoid")));
-       if (OidIsValid(subdiffOid))
-               appendPQExpBuffer(q, ",\n    SUBTYPE_DIFF = %s",
-                                                 PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff")));
+       procname = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
+       if (strcmp(procname, "-") != 0)
+               appendPQExpBuffer(q, ",\n    analyze = %s", procname);
 
        appendPQExpBuffer(q, "\n);\n");
 
index 6449eca52d9ebb305c2a399f26c85908d1e415c0..9e277c5a1e45316aeaa18a87c6c3ee889f243294 100644 (file)
@@ -2241,28 +2241,28 @@ typedef struct CreateEnumStmt
 } CreateEnumStmt;
 
 /* ----------------------
- *             Alter Type Statement, enum types
+ *             Create Type Statement, range types
  * ----------------------
  */
-typedef struct AlterEnumStmt
+typedef struct CreateRangeStmt
 {
        NodeTag         type;
        List       *typeName;           /* qualified name (list of Value strings) */
-       char       *newVal;                     /* new enum value's name */
-       char       *newValNeighbor; /* neighboring enum value, if specified */
-       bool            newValIsAfter;  /* place new enum value after neighbor? */
-} AlterEnumStmt;
+       List       *params;                     /* range parameters (list of DefElem) */
+} CreateRangeStmt;
 
 /* ----------------------
- *             Create Type Statement, range types
+ *             Alter Type Statement, enum types
  * ----------------------
  */
-typedef struct CreateRangeStmt
+typedef struct AlterEnumStmt
 {
        NodeTag         type;
        List       *typeName;           /* qualified name (list of Value strings) */
-       List       *params;                     /* range parameters (list of DefElem) */
-} CreateRangeStmt;
+       char       *newVal;                     /* new enum value's name */
+       char       *newValNeighbor; /* neighboring enum value, if specified */
+       bool            newValIsAfter;  /* place new enum value after neighbor? */
+} AlterEnumStmt;
 
 /* ----------------------
  *             Create View Statement
index 8a1c82ef72f4454d9394a8b16a80e76590811ff4..47a14125c48fc384b5d5c8d77abad99cec114e22 100644 (file)
@@ -502,6 +502,8 @@ 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 anyrange_in(PG_FUNCTION_ARGS);
+extern Datum anyrange_out(PG_FUNCTION_ARGS);
 extern Datum void_in(PG_FUNCTION_ARGS);
 extern Datum void_out(PG_FUNCTION_ARGS);
 extern Datum void_recv(PG_FUNCTION_ARGS);
index 585d32134c066c75abc9a5d4a9700a104bdfab8b..7d826d552109498cabf056b667f4e149e3a108cf 100644 (file)
@@ -73,9 +73,7 @@ typedef struct
  * prototypes for functions defined in rangetypes.c
  */
 
-/* IO */
-extern Datum anyrange_in(PG_FUNCTION_ARGS);
-extern Datum anyrange_out(PG_FUNCTION_ARGS);
+/* I/O */
 extern Datum range_in(PG_FUNCTION_ARGS);
 extern Datum range_out(PG_FUNCTION_ARGS);
 extern Datum range_recv(PG_FUNCTION_ARGS);
index 04d8b532c3960d364d212783c2ea7b29cdffbbd0..275cad7b5c95ae880fba595ca7ae99bc4938ab02 100644 (file)
@@ -2378,7 +2378,7 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
 /*
  * This is the same as the standard resolve_polymorphic_argtypes() function,
  * but with a special case for validation: assume that polymorphic arguments
- * are integer, integer-range or integer-array.  Also, we go ahead and report
+ * are integer, integer-array or integer-range.  Also, we go ahead and report
  * the error if we can't resolve the types.
  */
 static void
@@ -2412,12 +2412,12 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
                                case ANYENUMOID:                /* XXX dubious */
                                        argtypes[i] = INT4OID;
                                        break;
-                               case ANYRANGEOID:
-                                       argtypes[i] = INT4RANGEOID;
-                                       break;
                                case ANYARRAYOID:
                                        argtypes[i] = INT4ARRAYOID;
                                        break;
+                               case ANYRANGEOID:
+                                       argtypes[i] = INT4RANGEOID;
+                                       break;
                                default:
                                        break;
                        }