diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index fe59a1c7763..152ef2f0378 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4506,6 +4506,12 @@ SELECT * FROM pg_attribute
Indicates that a function accepts any input data type.
+
+ anyelement>
+ Indicates that a function accepts any data type
+ (see ).
+
+
anyarray>
Indicates that a function accepts any array data type
@@ -4513,8 +4519,8 @@ SELECT * FROM pg_attribute
- anyelement>
- Indicates that a function accepts any data type
+ anynonarray>
+ Indicates that a function accepts any non-array data type
(see ).
@@ -4532,12 +4538,6 @@ SELECT * FROM pg_attribute
).
-
- anynonarray>
- Indicates that a function accepts any non-array data type
- (see ).
-
-
cstring>
Indicates that a function accepts or returns a null-terminated C string.
@@ -4595,9 +4595,9 @@ SELECT * FROM pg_attribute
languages all forbid use of a pseudo-type as argument type, and allow
only void> and record> as a result type (plus
trigger> when the function is used as a trigger). Some also
- support polymorphic functions using the types anyarray>,
- anyelement>, anyenum>, anyrange>, and
- anynonarray>.
+ support polymorphic functions using the types anyelement>,
+ anyarray>, anynonarray>, anyenum>, and
+ anyrange>.
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 8378c360b97..a70a2aaecea 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -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;
}
}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a1628bc0985..8ffbc52fdef 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -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;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index a461ac9aef1..c07232544aa 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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 */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index cc8f32d4cea..6f88c476ada 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -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;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 1b4d26d6593..ceca0e3ede0 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -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)
{
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 71b09abb232..043030bd70f 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -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,
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 3cc2a7ee075..d19be870855 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -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 */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d2005c1e809..41114ac4da9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -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");
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6449eca52d9..9e277c5a1e4 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2240,6 +2240,17 @@ typedef struct CreateEnumStmt
List *vals; /* enum values (list of Value strings) */
} CreateEnumStmt;
+/* ----------------------
+ * Create Type Statement, range types
+ * ----------------------
+ */
+typedef struct CreateRangeStmt
+{
+ NodeTag type;
+ List *typeName; /* qualified name (list of Value strings) */
+ List *params; /* range parameters (list of DefElem) */
+} CreateRangeStmt;
+
/* ----------------------
* Alter Type Statement, enum types
* ----------------------
@@ -2253,17 +2264,6 @@ typedef struct AlterEnumStmt
bool newValIsAfter; /* place new enum value after neighbor? */
} AlterEnumStmt;
-/* ----------------------
- * Create Type Statement, range types
- * ----------------------
- */
-typedef struct CreateRangeStmt
-{
- NodeTag type;
- List *typeName; /* qualified name (list of Value strings) */
- List *params; /* range parameters (list of DefElem) */
-} CreateRangeStmt;
-
/* ----------------------
* Create View Statement
* ----------------------
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 8a1c82ef72f..47a14125c48 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -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);
diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h
index 585d32134c0..7d826d55210 100644
--- a/src/include/utils/rangetypes.h
+++ b/src/include/utils/rangetypes.h
@@ -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);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 04d8b532c39..275cad7b5c9 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -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;
}