diff options
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 212 |
1 files changed, 70 insertions, 142 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index af184eca6d1..46d191a9158 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,18 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.91 2002/12/12 20:35:13 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.92 2003/02/03 21:15:44 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "access/genam.h" -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/indexing.h" #include "catalog/pg_cast.h" -#include "catalog/pg_constraint.h" #include "catalog/pg_proc.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" @@ -35,7 +30,7 @@ static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat); + CoercionForm cformat, bool isExplicit); static Oid PreferredType(CATEGORY category, Oid type); static Node *build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat); @@ -103,7 +98,9 @@ coerce_to_target_type(Node *expr, Oid exprtype, * as well as a type coercion. */ if (expr != NULL) - expr = coerce_type_typmod(expr, targettype, targettypmod, cformat); + expr = coerce_type_typmod(expr, targettype, targettypmod, + cformat, + (cformat != COERCE_IMPLICIT_CAST)); return expr; } @@ -119,7 +116,7 @@ coerce_to_target_type(Node *expr, Oid exprtype, * No coercion to a typmod (length) is performed here. The caller must * call coerce_type_typmod as well, if a typmod constraint is wanted. * (But if the target type is a domain, it may internally contain a - * typmod constraint, which will be applied inside coerce_type_constraints.) + * typmod constraint, which will be applied inside coerce_to_domain.) */ Node * coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, @@ -186,15 +183,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, /* If target is a domain, apply constraints. */ if (targetTyptype == 'd') - { - result = coerce_type_constraints(result, targetTypeId, - cformat); - /* We might now need a RelabelType. */ - if (exprType(result) != targetTypeId) - result = (Node *) makeRelabelType((Expr *) result, - targetTypeId, -1, - cformat); - } + result = coerce_to_domain(result, InvalidOid, targetTypeId, + cformat); ReleaseSysCache(targetType); } @@ -222,17 +212,12 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, cformat); /* - * If domain, test against domain constraints and relabel with + * If domain, coerce to the domain type and relabel with * domain type ID */ if (targetTypeId != baseTypeId) - { - result = coerce_type_constraints(result, targetTypeId, - cformat); - result = (Node *) makeRelabelType((Expr *) result, - targetTypeId, -1, - cformat); - } + result = coerce_to_domain(result, baseTypeId, targetTypeId, + cformat); /* * If the input is a constant, apply the type conversion @@ -257,21 +242,23 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, * higher-level code. * * Also, domains may have value restrictions beyond the base type - * that must be accounted for. + * that must be accounted for. If the destination is a domain + * then we won't need a RelabelType node. */ - result = coerce_type_constraints(node, targetTypeId, - cformat); - - /* - * 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 (wrong if target is - * a domain, in any case). - */ - result = (Node *) makeRelabelType((Expr *) result, - targetTypeId, -1, - cformat); + result = coerce_to_domain(node, InvalidOid, targetTypeId, + cformat); + if (result == node) + { + /* + * 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. + */ + result = (Node *) makeRelabelType((Expr *) result, + targetTypeId, -1, + cformat); + } } } else if (typeInheritsFrom(inputTypeId, targetTypeId)) @@ -392,120 +379,61 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, /* - * Create an expression tree to enforce the constraints (if any) - * that should be applied by the type. Currently this is only - * interesting for domain types. + * Create an expression tree to represent coercion to a domain type. + * + * 'arg': input expression + * 'baseTypeId': base type of domain, if known (pass InvalidOid if caller + * has not bothered to look this up) + * 'typeId': target type to coerce to + * 'cformat': coercion format * - * NOTE: result tree is not guaranteed to show the correct exprType() for - * the domain; it may show the base type. Caller must relabel if needed. + * If the target type isn't a domain, the given 'arg' is returned as-is. */ Node * -coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat) +coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, CoercionForm cformat) { - char *notNull = NULL; - int32 typmod = -1; - - for (;;) - { - HeapTuple tup; - HeapTuple conTup; - Form_pg_type typTup; - - ScanKeyData key[1]; - int nkeys = 0; - SysScanDesc scan; - Relation conRel; - - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typeId), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - 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 = pstrdup(NameStr(typTup->typname)); - - /* Add CHECK Constraints to domains */ - conRel = heap_openr(ConstraintRelationName, RowShareLock); - - ScanKeyEntryInitialize(&key[nkeys++], 0x0, - Anum_pg_constraint_contypid, F_OIDEQ, - ObjectIdGetDatum(typeId)); - - scan = systable_beginscan(conRel, ConstraintTypidIndex, true, - SnapshotNow, nkeys, key); - - while (HeapTupleIsValid(conTup = systable_getnext(scan))) - { - Datum val; - bool isNull; - ConstraintTest *r = makeNode(ConstraintTest); - Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup); - - /* Not expecting conbin to be NULL, but we'll test for it anyway */ - val = fastgetattr(conTup, - Anum_pg_constraint_conbin, - conRel->rd_att, &isNull); - - if (isNull) - elog(ERROR, "coerce_type_constraints: domain %s constraint %s has NULL conbin", - NameStr(typTup->typname), NameStr(c->conname)); - - r->arg = (Expr *) arg; - r->testtype = CONSTR_TEST_CHECK; - r->name = NameStr(c->conname); - r->domname = NameStr(typTup->typname); - r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout, - val))); - - arg = (Node *) r; - } - - systable_endscan(scan); - heap_close(conRel, RowShareLock); - - if (typTup->typtype != 'd') - { - /* Not a domain, so done */ - ReleaseSysCache(tup); - break; - } + CoerceToDomain *result; + int32 typmod; - Assert(typmod < 0); + /* Get the base type if it hasn't been supplied */ + if (baseTypeId == InvalidOid) + baseTypeId = getBaseType(typeId); - typeId = typTup->typbasetype; - typmod = typTup->typtypmod; - ReleaseSysCache(tup); - } + /* If it isn't a domain, return the node as it was passed in */ + if (baseTypeId == typeId) + return arg; /* - * If domain applies a typmod to its base type, do length coercion. + * If the domain applies a typmod to its base type, build the appropriate + * coercion step. Mark it implicit for display purposes, because we don't + * want it shown separately by ruleutils.c; but the isExplicit flag passed + * to the conversion function depends on the manner in which the domain + * coercion is invoked, so that the semantics of implicit and explicit + * coercion differ. (Is that really the behavior we want?) + * + * NOTE: because we apply this as part of the fixed expression structure, + * ALTER DOMAIN cannot alter the typtypmod. But it's unclear that that + * would be safe to do anyway, without lots of knowledge about what the + * base type thinks the typmod means. */ + typmod = get_typtypmod(typeId); if (typmod >= 0) - arg = coerce_type_typmod(arg, typeId, typmod, cformat); + arg = coerce_type_typmod(arg, baseTypeId, typmod, + COERCE_IMPLICIT_CAST, + (cformat != COERCE_IMPLICIT_CAST)); /* - * Only need to add one NOT NULL check regardless of how many domains - * in the stack request it. The topmost domain that requested it is - * used as the constraint name. + * Now build the domain coercion node. This represents run-time checking + * of any constraints currently attached to the domain. This also + * ensures that the expression is properly labeled as to result type. */ - if (notNull) - { - ConstraintTest *r = makeNode(ConstraintTest); - - r->arg = (Expr *) arg; - r->testtype = CONSTR_TEST_NOTNULL; - r->name = "NOT NULL"; - r->domname = notNull; - r->check_expr = NULL; - - arg = (Node *) r; - } + result = makeNode(CoerceToDomain); + result->arg = (Expr *) arg; + result->resulttype = typeId; + result->resulttypmod = -1; /* currently, always -1 for domains */ + result->coercionformat = cformat; - return arg; + return (Node *) result; } @@ -526,7 +454,7 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat) */ static Node * coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat) + CoercionForm cformat, bool isExplicit) { Oid funcId; int nargs; @@ -559,7 +487,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, /* Pass it a boolean isExplicit parameter, too */ cons = makeConst(BOOLOID, sizeof(bool), - BoolGetDatum(cformat != COERCE_IMPLICIT_CAST), + BoolGetDatum(isExplicit), false, true); |