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

Support enum data types. Along the way, use macros for the values of

pg_type.typtype whereever practical.  Tom Dunstan, with some kibitzing
from Tom Lane.
This commit is contained in:
Tom Lane
2007-04-02 03:49:42 +00:00
parent a482a3e58b
commit 57690c6803
74 changed files with 2398 additions and 332 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.152 2007/03/27 23:21:10 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.153 2007/04/02 03:49:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -132,7 +132,8 @@ coerce_type(ParseState *pstate, Node *node,
}
if (targetTypeId == ANYOID ||
targetTypeId == ANYELEMENTOID ||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID))
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
@ -143,7 +144,8 @@ coerce_type(ParseState *pstate, Node *node,
* since an UNKNOWN value is still a perfectly valid Datum. However
* an UNKNOWN value is definitely *not* an array, and so we mustn't
* accept it for ANYARRAY. (Instead, we will call anyarray_in below,
* which will produce an error.)
* which will produce an error.) Likewise, UNKNOWN input is no good
* for ANYENUM.
*
* NB: we do NOT want a RelabelType here.
*/
@ -406,9 +408,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
if (targetTypeId == ANYOID)
continue;
/* accept if target is ANYARRAY or ANYELEMENT, for now */
if (targetTypeId == ANYARRAYOID ||
targetTypeId == ANYELEMENTOID)
/* accept if target is polymorphic, for now */
if (IsPolymorphicType(targetTypeId))
{
have_generics = true; /* do more checking later */
continue;
@ -1048,6 +1049,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
* 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.
* 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.
*
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
* or ANYARRAY argument, assume it is okay.
@ -1070,6 +1074,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
Oid array_typeid = InvalidOid;
Oid array_typelem;
bool have_anyelement = false;
bool have_anyenum = false;
/*
* Loop through the arguments to see if we have any that are ANYARRAY or
@ -1079,9 +1084,12 @@ check_generic_type_consistency(Oid *actual_arg_types,
{
Oid actual_type = actual_arg_types[j];
if (declared_arg_types[j] == ANYELEMENTOID)
if (declared_arg_types[j] == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID)
{
have_anyelement = true;
if (declared_arg_types[j] == ANYENUMOID)
have_anyenum = true;
if (actual_type == UNKNOWNOID)
continue;
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
@ -1127,6 +1135,13 @@ check_generic_type_consistency(Oid *actual_arg_types,
}
}
if (have_anyenum)
{
/* require the element type to be an enum */
if (!type_is_enum(elem_typeid))
return false;
}
/* Looks valid */
return true;
}
@ -1136,18 +1151,18 @@ check_generic_type_consistency(Oid *actual_arg_types,
* 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
* If ANYARRAY, ANYELEMENT, or ANYENUM 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.
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
* 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:
* 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.
@ -1167,6 +1182,9 @@ check_generic_type_consistency(Oid *actual_arg_types,
* 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.
* 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.
*/
Oid
enforce_generic_type_consistency(Oid *actual_arg_types,
@ -1180,7 +1198,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid array_typelem;
bool have_anyelement = (rettype == ANYELEMENTOID);
bool have_anyelement = (rettype == ANYELEMENTOID ||
rettype == ANYENUMOID);
bool have_anyenum = (rettype == ANYENUMOID);
/*
* Loop through the arguments to see if we have any that are ANYARRAY or
@ -1190,9 +1210,12 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
{
Oid actual_type = actual_arg_types[j];
if (declared_arg_types[j] == ANYELEMENTOID)
if (declared_arg_types[j] == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID)
{
have_generics = have_anyelement = true;
if (declared_arg_types[j] == ANYENUMOID)
have_anyenum = true;
if (actual_type == UNKNOWNOID)
{
have_unknowns = true;
@ -1227,8 +1250,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
}
/*
* Fast Track: if none of the arguments are ANYARRAY or ANYELEMENT, return
* the unmodified rettype.
* Fast Track: if none of the arguments are polymorphic, return the
* unmodified rettype. We assume it can't be polymorphic either.
*/
if (!have_generics)
return rettype;
@ -1274,7 +1297,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
/* 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\"")));
errmsg("could not determine polymorphic type because input has type \"unknown\"")));
}
if (have_anyenum)
{
/* require the element type to be an enum */
if (!type_is_enum(elem_typeid))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type matched to anyenum is not an enum type: %s",
format_type_be(elem_typeid))));
}
/*
@ -1289,7 +1322,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
if (actual_type != UNKNOWNOID)
continue;
if (declared_arg_types[j] == ANYELEMENTOID)
if (declared_arg_types[j] == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID)
declared_arg_types[j] = elem_typeid;
else if (declared_arg_types[j] == ANYARRAYOID)
{
@ -1307,7 +1341,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
}
}
/* if we return ANYARRAYOID use the appropriate argument type */
/* if we return ANYARRAY use the appropriate argument type */
if (rettype == ANYARRAYOID)
{
if (!OidIsValid(array_typeid))
@ -1322,8 +1356,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
return array_typeid;
}
/* if we return ANYELEMENTOID use the appropriate argument type */
if (rettype == ANYELEMENTOID)
/* if we return ANYELEMENT use the appropriate argument type */
if (rettype == ANYELEMENTOID || rettype == ANYENUMOID)
return elem_typeid;
/* we don't return a generic type; send back the original return type */
@ -1333,7 +1367,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
/*
* resolve_generic_type()
* Deduce an individual actual datatype on the assumption that
* the rules for ANYARRAY/ANYELEMENT are being followed.
* the rules for polymorphic types are being followed.
*
* declared_type is the declared datatype we want to resolve.
* context_actual_type is the actual input datatype to some argument
@ -1362,7 +1396,8 @@ resolve_generic_type(Oid declared_type,
format_type_be(context_actual_type))));
return context_actual_type;
}
else if (context_declared_type == ANYELEMENTOID)
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYENUMOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
@ -1375,7 +1410,7 @@ resolve_generic_type(Oid declared_type,
return array_typeid;
}
}
else if (declared_type == ANYELEMENTOID)
else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
{
if (context_declared_type == ANYARRAYOID)
{
@ -1389,7 +1424,8 @@ resolve_generic_type(Oid declared_type,
format_type_be(context_actual_type))));
return array_typelem;
}
else if (context_declared_type == ANYELEMENTOID)
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYENUMOID)
{
/* Use the actual type; it doesn't matter if array or not */
return context_actual_type;
@ -1402,7 +1438,7 @@ resolve_generic_type(Oid 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");
elog(ERROR, "could not determine polymorphic type because context isn't polymorphic");
return InvalidOid; /* keep compiler quiet */
}
@ -1502,6 +1538,7 @@ TypeCategory(Oid inType)
case (INTERNALOID):
case (OPAQUEOID):
case (ANYELEMENTOID):
case (ANYENUMOID):
result = GENERIC_TYPE;
break;
@ -1647,6 +1684,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (get_element_type(srctype) != InvalidOid)
return true;
/* Also accept any enum type as coercible to ANYENUM */
if (targettype == ANYENUMOID)
if (type_is_enum(srctype))
return true;
/* Else look in pg_cast */
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(srctype),
@ -1777,6 +1819,22 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
result = true;
}
}
/*
* If we still haven't found a possibility, check for enums,
* and retry looking for a cast to or from ANYENUM. But don't
* mistakenly conclude that ANYENUM-to-some-enum-type is a
* trivial cast.
*/
if (!result)
{
if (type_is_enum(sourceTypeId))
result = find_coercion_pathway(targetTypeId, ANYENUMOID,
ccontext, funcid, arrayCoerce);
else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId))
result = find_coercion_pathway(ANYENUMOID, sourceTypeId,
ccontext, funcid, arrayCoerce);
}
}
return result;
@ -1813,7 +1871,7 @@ find_typmod_coercion_function(Oid typeId,
/* Check for a varlena array type (and not a domain) */
if (typeForm->typelem != InvalidOid &&
typeForm->typlen == -1 &&
typeForm->typtype != 'd')
typeForm->typtype != TYPTYPE_DOMAIN)
{
/* Yes, switch our attention to the element type */
typeId = typeForm->typelem;