1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Support range data types.

Selectivity estimation functions are missing for some range type operators,
which is a TODO.

Jeff Davis
This commit is contained in:
Heikki Linnakangas
2011-11-03 13:16:28 +02:00
parent 4334289186
commit 4429f6a9e3
58 changed files with 6718 additions and 103 deletions

View File

@ -158,7 +158,8 @@ coerce_type(ParseState *pstate, Node *node,
return node;
}
if (targetTypeId == ANYARRAYOID ||
targetTypeId == ANYENUMOID)
targetTypeId == ANYENUMOID ||
targetTypeId == ANYRANGEOID)
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
@ -1275,9 +1276,11 @@ coerce_to_common_type(ParseState *pstate, Node *node,
* 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.
* 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.
@ -1311,6 +1314,8 @@ check_generic_type_consistency(Oid *actual_arg_types,
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid array_typelem;
Oid range_typeid = InvalidOid;
Oid range_typelem;
bool have_anyelement = false;
bool have_anynonarray = false;
bool have_anyenum = false;
@ -1348,6 +1353,15 @@ check_generic_type_consistency(Oid *actual_arg_types,
return false;
array_typeid = actual_type;
}
else if (decl_type == ANYRANGEOID)
{
if (actual_type == UNKNOWNOID)
continue;
actual_type = getBaseType(actual_type);
if (OidIsValid(range_typeid) && actual_type != range_typeid)
return false;
range_typeid = actual_type;
}
}
/* Get the element type based on the array type, if we have one */
@ -1393,6 +1407,27 @@ check_generic_type_consistency(Oid *actual_arg_types,
return false;
}
/* Get the element type based on the range type, if we have one */
if (OidIsValid(range_typeid))
{
range_typelem = get_range_subtype(range_typeid);
if (!OidIsValid(range_typelem))
return false; /* should be a range, but isn't */
if (!OidIsValid(elem_typeid))
{
/*
* if we don't have an element type yet, use the one we just got
*/
elem_typeid = range_typelem;
}
else if (range_typelem != elem_typeid)
{
/* otherwise, they better match */
return false;
}
}
/* Looks valid */
return true;
}
@ -1416,23 +1451,28 @@ 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.
* 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.
* 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. This condition is prevented by CREATE FUNCTION
* and is therefore not expected here.
* 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, use the actual type of the argument to determine
* the function's return type, i.e. the array type's corresponding
* element type.
* 6) If return type is ANYELEMENT, no argument is ANYARRAY or ANYELEMENT,
* generate an ERROR. This condition is prevented by CREATE FUNCTION
* and is therefore not expected here.
* 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.
@ -1441,9 +1481,10 @@ check_generic_type_consistency(Oid *actual_arg_types,
* (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 arguments, and are immediately flattened
* to their base type. (In particular, if the return type is also ANYARRAY,
* we'll set it to the base type not the domain type.)
* 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.)
*
* 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
@ -1473,7 +1514,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
bool have_unknowns = false;
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid range_typeid = InvalidOid;
Oid array_typelem;
Oid range_typelem;
bool have_anyelement = (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
rettype == ANYENUMOID);
@ -1534,6 +1577,26 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
format_type_be(actual_type))));
array_typeid = actual_type;
}
else if (decl_type == ANYRANGEOID)
{
have_generics = true;
if (actual_type == UNKNOWNOID)
{
have_unknowns = true;
continue;
}
if (allow_poly && decl_type == actual_type)
continue; /* no new information here */
actual_type = getBaseType(actual_type); /* flatten domains */
if (OidIsValid(range_typeid) && actual_type != range_typeid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("arguments declared \"anyrange\" are not all alike"),
errdetail("%s versus %s",
format_type_be(range_typeid),
format_type_be(actual_type))));
range_typeid = actual_type;
}
}
/*
@ -1579,6 +1642,34 @@ 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))
{
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 we don't have an element type yet, use the one we just got
*/
elem_typeid = range_typelem;
}
else if (range_typelem != elem_typeid)
{
/* otherwise, they better match */
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared \"anyrange\" is not consistent with argument declared \"anyelement\""),
errdetail("%s versus %s",
format_type_be(range_typeid),
format_type_be(elem_typeid))));
}
}
else if (!OidIsValid(elem_typeid))
{
if (allow_poly)
@ -1645,6 +1736,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
}
declared_arg_types[j] = array_typeid;
}
else if (decl_type == ANYRANGEOID)
{
if (!OidIsValid(range_typeid))
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find range type for data type %s",
format_type_be(elem_typeid))));
}
declared_arg_types[j] = range_typeid;
}
}
}
@ -1663,6 +1765,19 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
return array_typeid;
}
/* if we return ANYRANGE use the appropriate argument type */
if (rettype == ANYRANGEOID)
{
if (!OidIsValid(range_typeid))
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find range type for data type %s",
format_type_be(elem_typeid))));
}
return range_typeid;
}
/* if we return ANYELEMENT use the appropriate argument type */
if (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
@ -1711,7 +1826,8 @@ resolve_generic_type(Oid declared_type,
}
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
context_declared_type == ANYENUMOID)
context_declared_type == ANYENUMOID ||
context_declared_type == ANYRANGEOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
@ -1726,7 +1842,8 @@ resolve_generic_type(Oid declared_type,
}
else if (declared_type == ANYELEMENTOID ||
declared_type == ANYNONARRAYOID ||
declared_type == ANYENUMOID)
declared_type == ANYENUMOID ||
declared_type == ANYRANGEOID)
{
if (context_declared_type == ANYARRAYOID)
{
@ -1741,6 +1858,18 @@ resolve_generic_type(Oid declared_type,
format_type_be(context_base_type))));
return array_typelem;
}
else if (context_declared_type == ANYRANGEOID)
{
/* Use the element type corresponding to actual type */
Oid range_typelem = get_range_subtype(context_actual_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))));
return range_typelem;
}
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
context_declared_type == ANYENUMOID)
@ -1854,6 +1983,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (type_is_enum(srctype))
return true;
/* Also accept any range type as coercible to ANYRANGE */
if (targettype == ANYRANGEOID)
if (type_is_range(srctype))
return true;
/* Also accept any composite type as coercible to RECORD */
if (targettype == RECORDOID)
if (ISCOMPLEX(srctype))