📄 parse_coerce.c
字号:
* both types in different categories? then not much hope... */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), /* * translator: first %s is name of a SQL construct, eg CASE */ errmsg("%s types %s and %s cannot be matched", context, format_type_be(ptype), format_type_be(ntype)))); } else if (!IsPreferredType(pcategory, ptype) && can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) && !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT)) { /* * take new type if can coerce to it implicitly but not the * other way; but if we have a preferred type, stay on it. */ ptype = ntype; pcategory = TypeCategory(ptype); } } } /* * If all the inputs were UNKNOWN type --- ie, unknown-type literals --- * then resolve as type TEXT. This situation comes up with constructs * like SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END); SELECT 'foo' * UNION SELECT 'bar'; It might seem desirable to leave the construct's * output type as UNKNOWN, but that really doesn't work, because we'd * probably end up needing a runtime coercion from UNKNOWN to something * else, and we usually won't have it. We need to coerce the unknown * literals while they are still literals, so a decision has to be made * now. */ if (ptype == UNKNOWNOID) ptype = TEXTOID; return ptype;}/* coerce_to_common_type() * Coerce an expression to the given type. * * This is used following select_common_type() to coerce the individual * expressions to the desired type. 'context' is a phrase to use in the * error message if we fail to coerce. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Node *coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context){ Oid inputTypeId = exprType(node); if (inputTypeId == targetTypeId) return node; /* no work */ if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT)) node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), /* translator: first %s is name of a SQL construct, eg CASE */ errmsg("%s could not convert type %s to %s", context, format_type_be(inputTypeId), format_type_be(targetTypeId)))); return node;}/* * check_generic_type_consistency() * Are the actual arguments potentially compatible with a * polymorphic function? * * 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. * * If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT * or ANYARRAY argument, assume it is okay. * * If an input is of type ANYARRAY (ie, we know it's an array, but not * what element type), we will accept it as a match to an argument declared * ANYARRAY, so long as we don't have to determine an element type --- * that is, so long as there is no use of ANYELEMENT. This is mostly for * backwards compatibility with the pre-7.4 behavior of ANYARRAY. * * We do not ereport here, but just return FALSE if a rule is violated. */boolcheck_generic_type_consistency(Oid *actual_arg_types, Oid *declared_arg_types, int nargs){ int j; Oid elem_typeid = InvalidOid; Oid array_typeid = InvalidOid; Oid array_typelem; bool have_anyelement = false; /* * Loop through the arguments to see if we have any that are ANYARRAY or * ANYELEMENT. If so, require the actual types to be self-consistent */ for (j = 0; j < nargs; j++) { Oid actual_type = actual_arg_types[j]; if (declared_arg_types[j] == ANYELEMENTOID) { have_anyelement = true; if (actual_type == UNKNOWNOID) continue; if (OidIsValid(elem_typeid) && actual_type != elem_typeid) return false; elem_typeid = actual_type; } else if (declared_arg_types[j] == ANYARRAYOID) { if (actual_type == UNKNOWNOID) continue; if (OidIsValid(array_typeid) && actual_type != array_typeid) return false; array_typeid = actual_type; } } /* Get the element type based on the array type, if we have one */ if (OidIsValid(array_typeid)) { if (array_typeid == ANYARRAYOID) { /* Special case for ANYARRAY input: okay iff no ANYELEMENT */ if (have_anyelement) return false; return true; } array_typelem = get_element_type(array_typeid); if (!OidIsValid(array_typelem)) return false; /* should be an array, but isn't */ if (!OidIsValid(elem_typeid)) { /* * if we don't have an element type yet, use the one we just got */ elem_typeid = array_typelem; } else if (array_typelem != elem_typeid) { /* otherwise, they better match */ return false; } } /* Looks valid */ return true;}/* * enforce_generic_type_consistency() * Make sure a polymorphic function is legally callable, and * deduce actual argument and result types. * * If ANYARRAY or ANYELEMENT is used for 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 * check_generic_type_consistency(). * * If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT * or ANYARRAY argument, we attempt to deduce the actual type it should * have. If successful, we alter that position of declared_arg_types[] * so that make_fn_arguments will coerce the literal to the right thing. * * Rules are applied to the function's return type (possibly altering it) * if it is declared ANYARRAY or ANYELEMENT: * * 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. * 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. * 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. */Oidenforce_generic_type_consistency(Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype){ int j; bool have_generics = false; bool have_unknowns = false; Oid elem_typeid = InvalidOid; Oid array_typeid = InvalidOid; Oid array_typelem; bool have_anyelement = (rettype == ANYELEMENTOID); /* * Loop through the arguments to see if we have any that are ANYARRAY or * ANYELEMENT. If so, require the actual types to be self-consistent */ for (j = 0; j < nargs; j++) { Oid actual_type = actual_arg_types[j]; if (declared_arg_types[j] == ANYELEMENTOID) { have_generics = have_anyelement = true; if (actual_type == UNKNOWNOID) { have_unknowns = true; continue; } if (OidIsValid(elem_typeid) && actual_type != elem_typeid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("arguments declared \"anyelement\" are not all alike"), errdetail("%s versus %s", format_type_be(elem_typeid), format_type_be(actual_type)))); elem_typeid = actual_type; } else if (declared_arg_types[j] == ANYARRAYOID) { have_generics = true; if (actual_type == UNKNOWNOID) { have_unknowns = true; continue; } if (OidIsValid(array_typeid) && actual_type != array_typeid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("arguments declared \"anyarray\" are not all alike"), errdetail("%s versus %s", format_type_be(array_typeid), format_type_be(actual_type)))); array_typeid = actual_type; } } /* * Fast Track: if none of the arguments are ANYARRAY or ANYELEMENT, return * the unmodified rettype. */ if (!have_generics) return rettype; /* Get the element type based on the array type, if we have one */ if (OidIsValid(array_typeid)) { if (array_typeid == ANYARRAYOID && !have_anyelement) { /* Special case for ANYARRAY input: okay iff no ANYELEMENT */ array_typelem = InvalidOid; } else { array_typelem = get_element_type(array_typeid); if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("argument declared \"anyarray\" is not an array but type %s", format_type_be(array_typeid)))); } if (!OidIsValid(elem_typeid)) { /* * if we don't have an element type yet, use the one we just got */ elem_typeid = array_typelem; } else if (array_typelem != elem_typeid) { /* otherwise, they better match */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("argument declared \"anyarray\" is not consistent with argument declared \"anyelement\""), errdetail("%s versus %s", format_type_be(array_typeid), format_type_be(elem_typeid)))); } } else if (!OidIsValid(elem_typeid)) { /* Only way to get here is if all the generic args are UNKNOWN */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("could not determine anyarray/anyelement type because input has type \"unknown\""))); } /* * If we had any unknown inputs, re-scan to assign correct types */ if (have_unknowns) { for (j = 0; j < nargs; j++) { Oid actual_type = actual_arg_types[j]; if (actual_type != UNKNOWNOID) continue; if (declared_arg_types[j] == ANYELEMENTOID) declared_arg_types[j] = elem_typeid; else if (declared_arg_types[j] == ANYARRAYOID) { if (!OidIsValid(array_typeid)) { array_typeid = get_array_type(elem_typeid); if (!OidIsValid(array_typeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(elem_typeid)))); } declared_arg_types[j] = array_typeid; } } } /* if we return ANYARRAYOID use the appropriate argument type */ if (rettype == ANYARRAYOID) { if (!OidIsValid(array_typeid)) { array_typeid = get_array_type(elem_typeid); if (!OidIsValid(array_typeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(elem_typeid)))); } return array_typeid; } /* if we return ANYELEMENTOID use the appropriate argument type */ if (rettype == ANYELEMENTOID) return elem_typeid; /* we don't return a generic type; send back the original return type */ return rettype;}/* * resolve_generic_type() * Deduce an individual actual datatype on the assumption that * the rules for ANYARRAY/ANYELEMENT are being followed. * * declared_type is the declared datatype we want to resolve. * context_actual_type is the actual input datatype to some argument * that has declared datatype context_declared_type. * * If declared_type isn't polymorphic, we just return it. Otherwise, * context_declared_type must be polymorphic, and we deduce the correct * return type based on the relationship of the two polymorphic types. */Oidresolve_generic_type(Oid declared_type, Oid context_actual_type, Oid context_declared_type){ if (declared_type == ANYARRAYOID) { if (context_declared_type == ANYARRAYOID) { /* Use actual type, but it must be an array */ Oid array_typelem = get_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("argument declared \"anyarray\" is not an array but type %s", format_type_be(context_actual_type)))); return context_actual_type; } else if (context_declared_type == ANYELEMENTOID) { /* Use the array type corresponding to actual type */ Oid array_typeid = get_array_type(context_actual_type); if (!OidIsValid(array_typeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(context_actual_type)))); return array_typeid; } } else if (declared_type == ANYELEMENTOID) { if (context_declared_type == ANYARRAYOID) { /* Use the element type corresponding to actual type */ Oid array_typelem = get_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("argument declared \"anyarray\" is not an array but type %s", format_type_be(context_actual_type)))); return array_typelem; } else if (context_declared_type == ANYELEMENTOID) { /* Use the actual type; it doesn't matter if array or not */ return context_actual_type; } } else { /* declared_type isn't polymorphic, so return it as-is */ return declared_type; } /* If we get here, declared_type is polymorphic and context isn't */ /* NB: this is a calling-code logic error, not a user error */ elog(ERROR, "could not determine ANYARRAY/ANYELEMENT type because context isn't polymorphic"); return InvalidOid; /* keep compiler quiet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -