diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-20 23:50:27 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-20 23:50:27 -0500 |
commit | b985d48779146b7ba969b0963614ad7683589bc8 (patch) | |
tree | 5e0a9e2f5263d04012919feb6b0a4319ecbc1a12 /src/backend/parser | |
parent | 40d35036bb160d5724305454d41c68ab1637ee6f (diff) | |
download | postgresql-b985d48779146b7ba969b0963614ad7683589bc8.tar.gz postgresql-b985d48779146b7ba969b0963614ad7683589bc8.zip |
Further code review for range types patch.
Fix some bugs in coercion logic and pg_dump; more comment cleanup;
minor cosmetic improvements.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 196 |
1 files changed, 109 insertions, 87 deletions
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 */ |