diff options
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 131 |
1 files changed, 79 insertions, 52 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 1016c782d29..397bd4b8b07 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.80 2002/08/22 00:01:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.81 2002/08/31 22:10:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,7 +35,7 @@ static Node *build_func_call(Oid funcid, Oid rettype, List *args); static Oid find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit); static Oid find_typmod_coercion_function(Oid typeId); -static Node *TypeConstraints(Node *arg, Oid typeId); + /* coerce_type() * Convert a function argument to a different type. @@ -49,7 +49,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, if (targetTypeId == inputTypeId || node == NULL) { - /* no conversion needed, but constraints may need to be applied */ + /* no conversion needed */ result = node; } else if (inputTypeId == UNKNOWNOID && IsA(node, Const)) @@ -69,11 +69,12 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, * postpone evaluation of the function call until runtime. But * there is no way to represent a typinput function call as an * expression tree, because C-string values are not Datums. + * (XXX This *is* possible as of 7.3, do we want to do it?) */ Const *con = (Const *) node; Const *newcon = makeNode(Const); Type targetType = typeidType(targetTypeId); - Oid baseTypeId = getBaseType(targetTypeId); + char targetTyptype = typeTypType(targetType); newcon->consttype = targetTypeId; newcon->constlen = typeLen(targetType); @@ -85,16 +86,31 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, { char *val = DatumGetCString(DirectFunctionCall1(unknownout, con->constvalue)); + + /* + * If target is a domain, use the typmod it applies to the base + * type. Note that we call stringTypeDatum using the domain's + * pg_type row, though. This works because the domain row has + * the same typinput and typelem as the base type --- ugly... + */ + if (targetTyptype == 'd') + atttypmod = getBaseTypeMod(targetTypeId, atttypmod); + newcon->constvalue = stringTypeDatum(targetType, val, atttypmod); pfree(val); } - ReleaseSysCache(targetType); - - /* Test for domain, and apply appropriate constraints */ result = (Node *) newcon; - if (targetTypeId != baseTypeId) - result = (Node *) TypeConstraints(result, targetTypeId); + + /* + * If target is a domain, apply constraints (except for typmod, + * which we assume the input routine took care of). + */ + if (targetTyptype == 'd') + result = coerce_type_constraints(pstate, result, targetTypeId, + false); + + ReleaseSysCache(targetType); } else if (targetTypeId == ANYOID || targetTypeId == ANYARRAYOID) @@ -109,21 +125,18 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, * attach a RelabelType node so that the expression will be seen * to have the intended type when inspected by higher-level code. * + * Also, domains may have value restrictions beyond the base type + * that must be accounted for. + */ + result = coerce_type_constraints(pstate, node, targetTypeId, true); + /* * XXX could we label result with exprTypmod(node) instead of * default -1 typmod, to save a possible length-coercion later? * Would work if both types have same interpretation of typmod, - * which is likely but not certain. - * - * Domains may have value restrictions beyond the base type that - * must be accounted for. + * which is likely but not certain (wrong if target is a domain, + * in any case). */ - Oid baseTypeId = getBaseType(targetTypeId); - result = node; - if (targetTypeId != baseTypeId) - result = (Node *) TypeConstraints(result, targetTypeId); - result = (Node *) makeRelabelType(result, targetTypeId, -1); - } else if (typeInheritsFrom(inputTypeId, targetTypeId)) { @@ -144,8 +157,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, * * For domains, we use the coercion function for the base type. */ - Oid funcId; Oid baseTypeId = getBaseType(targetTypeId); + Oid funcId; funcId = find_coercion_function(baseTypeId, getBaseType(inputTypeId), @@ -157,11 +170,15 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, result = build_func_call(funcId, baseTypeId, makeList1(node)); /* - * If domain, relabel with domain type ID and test against domain - * constraints + * If domain, test against domain constraints and relabel with + * domain type ID */ if (targetTypeId != baseTypeId) - result = (Node *) TypeConstraints(result, targetTypeId); + { + result = coerce_type_constraints(pstate, result, targetTypeId, + true); + result = (Node *) makeRelabelType(result, targetTypeId, -1); + } /* * If the input is a constant, apply the type conversion function @@ -306,28 +323,21 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids, * function should be invoked to do that. * * "bpchar" (ie, char(N)) and "numeric" are examples of such types. + * + * This mechanism may seem pretty grotty and in need of replacement by + * something in pg_cast, but since typmod is only interesting for datatypes + * that have special handling in the grammar, there's not really much + * percentage in making it any easier to apply such coercions ... + * + * NOTE: this does not need to work on domain types, because any typmod + * coercion for a domain is considered to be part of the type coercion + * needed to produce the domain value in the first place. */ Node * coerce_type_typmod(ParseState *pstate, Node *node, Oid targetTypeId, int32 atttypmod) { - Oid baseTypeId; Oid funcId; - int32 domainTypMod; - - /* If given type is a domain, use base type instead */ - baseTypeId = getBaseTypeTypeMod(targetTypeId, &domainTypMod); - - - /* - * Use the domain typmod rather than what was supplied if the - * domain was empty. atttypmod will always be -1 if domains are in use. - */ - if (baseTypeId != targetTypeId) - { - Assert(atttypmod < 0); - atttypmod = domainTypMod; - } /* * A negative typmod is assumed to mean that no coercion is wanted. @@ -335,7 +345,8 @@ coerce_type_typmod(ParseState *pstate, Node *node, if (atttypmod < 0 || atttypmod == exprTypmod(node)) return node; - funcId = find_typmod_coercion_function(baseTypeId); + funcId = find_typmod_coercion_function(targetTypeId); + if (OidIsValid(funcId)) { Const *cons; @@ -348,7 +359,7 @@ coerce_type_typmod(ParseState *pstate, Node *node, false, false); - node = build_func_call(funcId, baseTypeId, makeList2(node, cons)); + node = build_func_call(funcId, targetTypeId, makeList2(node, cons)); } return node; @@ -869,12 +880,15 @@ build_func_call(Oid funcid, Oid rettype, List *args) /* * Create an expression tree to enforce the constraints (if any) - * which should be applied by the type. + * that should be applied by the type. Currently this is only + * interesting for domain types. */ -static Node * -TypeConstraints(Node *arg, Oid typeId) +Node * +coerce_type_constraints(ParseState *pstate, Node *arg, + Oid typeId, bool applyTypmod) { char *notNull = NULL; + int32 typmod = -1; for (;;) { @@ -885,12 +899,13 @@ TypeConstraints(Node *arg, Oid typeId) ObjectIdGetDatum(typeId), 0, 0, 0); if (!HeapTupleIsValid(tup)) - elog(ERROR, "getBaseType: failed to lookup type %u", typeId); + elog(ERROR, "coerce_type_constraints: failed to lookup type %u", + typeId); typTup = (Form_pg_type) GETSTRUCT(tup); /* Test for NOT NULL Constraint */ if (typTup->typnotnull && notNull == NULL) - notNull = NameStr(typTup->typname); + notNull = pstrdup(NameStr(typTup->typname)); /* TODO: Add CHECK Constraints to domains */ @@ -901,20 +916,32 @@ TypeConstraints(Node *arg, Oid typeId) break; } + Assert(typmod < 0); + typeId = typTup->typbasetype; + typmod = typTup->typtypmod; ReleaseSysCache(tup); } /* + * If domain applies a typmod to its base type, do length coercion. + */ + if (applyTypmod && typmod >= 0) + arg = coerce_type_typmod(pstate, arg, typeId, typmod); + + /* * Only need to add one NOT NULL check regardless of how many - * domains in the tree request it. + * domains in the stack request it. The topmost domain that + * requested it is used as the constraint name. */ - if (notNull != NULL) { - Constraint *r = makeNode(Constraint); + if (notNull) + { + ConstraintTest *r = makeNode(ConstraintTest); - r->raw_expr = arg; - r->contype = CONSTR_NOTNULL; - r->name = notNull; + r->arg = arg; + r->testtype = CONSTR_TEST_NOTNULL; + r->name = notNull; + r->check_expr = NULL; arg = (Node *) r; } |