Commit b985d487 authored by Tom Lane's avatar Tom Lane

Further code review for range types patch.

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