From f245c4eb1a0d8520c1a217d18d3e965042a1cb2f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 6 Nov 2004 17:46:38 +0000 Subject: [PATCH] When implementing a coercion to a domain type with a combined type-and-length coercion function, make sure that the coercion function is told the correct typmod. Fixes Kris Jurka's example of a domain over bit(N). --- src/backend/commands/copy.c | 4 +-- src/backend/optimizer/prep/preptlist.c | 3 +- src/backend/parser/parse_coerce.c | 47 +++++++++++++++++--------- src/backend/rewrite/rewriteHandler.c | 3 +- src/include/parser/parse_coerce.h | 5 +-- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index c2b2b205aa..7ad6de5db3 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.233 2004/10/29 19:18:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.234 2004/11/06 17:46:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1596,7 +1596,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, node = coerce_to_domain((Node *) prm, prm->paramtype, attr[attnum - 1]->atttypid, - COERCE_IMPLICIT_CAST, false); + COERCE_IMPLICIT_CAST, false, false); constraintexprs[attnum - 1] = ExecPrepareExpr((Expr *) node, estate); diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index f10b87b117..bcf33d9830 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.70 2004/08/29 04:12:34 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.71 2004/11/06 17:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -200,6 +200,7 @@ expand_targetlist(List *tlist, int command_type, InvalidOid, atttype, COERCE_IMPLICIT_CAST, + false, false); } else diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index ff513a0c13..4ac4ec84ec 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.123 2004/08/29 05:06:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.124 2004/11/06 17:46:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -191,7 +191,7 @@ coerce_type(ParseState *pstate, Node *node, /* If target is a domain, apply constraints. */ if (targetTyptype == 'd') result = coerce_to_domain(result, InvalidOid, targetTypeId, - cformat, false); + cformat, false, false); ReleaseSysCache(targetType); @@ -253,23 +253,33 @@ coerce_type(ParseState *pstate, Node *node, * Generate an expression tree representing run-time * application of the conversion function. If we are dealing * with a domain target type, the conversion function will - * yield the base type (and we assume targetTypeMod must be - * -1). + * yield the base type, and we need to extract the correct + * typmod to use from the domain's typtypmod. */ Oid baseTypeId = getBaseType(targetTypeId); + int32 baseTypeMod; + + if (targetTypeId != baseTypeId) + baseTypeMod = get_typtypmod(targetTypeId); + else + baseTypeMod = targetTypeMod; result = build_coercion_expression(node, funcId, - baseTypeId, targetTypeMod, + baseTypeId, baseTypeMod, cformat, (cformat != COERCE_IMPLICIT_CAST)); /* * If domain, coerce to the domain type and relabel with - * domain type ID + * domain type ID. We can skip the internal length-coercion + * step if the selected coercion function was a type-and-length + * coercion. */ if (targetTypeId != baseTypeId) result = coerce_to_domain(result, baseTypeId, targetTypeId, - cformat, true); + cformat, true, + exprIsLengthCoercion(result, + NULL)); } else { @@ -284,7 +294,7 @@ coerce_type(ParseState *pstate, Node *node, * then we won't need a RelabelType node. */ result = coerce_to_domain(node, InvalidOid, targetTypeId, - cformat, false); + cformat, false, false); if (result == node) { /* @@ -425,15 +435,16 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, * 'typeId': target type to coerce to * 'cformat': coercion format * 'hideInputCoercion': if true, hide the input coercion under this one. + * 'lengthCoercionDone': if true, caller already accounted for length. * * If the target type isn't a domain, the given 'arg' is returned as-is. */ Node * coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, - CoercionForm cformat, bool hideInputCoercion) + CoercionForm cformat, bool hideInputCoercion, + bool lengthCoercionDone) { CoerceToDomain *result; - int32 typmod; /* Get the base type if it hasn't been supplied */ if (baseTypeId == InvalidOid) @@ -461,12 +472,16 @@ coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, * 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, baseTypeId, typmod, - COERCE_IMPLICIT_CAST, - (cformat != COERCE_IMPLICIT_CAST), - false); + if (!lengthCoercionDone) + { + int32 typmod = get_typtypmod(typeId); + + if (typmod >= 0) + arg = coerce_type_typmod(arg, baseTypeId, typmod, + COERCE_IMPLICIT_CAST, + (cformat != COERCE_IMPLICIT_CAST), + false); + } /* * Now build the domain coercion node. This represents run-time diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 08012b315a..c901fb30e1 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.144 2004/08/29 05:06:47 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.145 2004/11/06 17:46:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -374,6 +374,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation) InvalidOid, att_tup->atttypid, COERCE_IMPLICIT_CAST, + false, false); } } diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 02dc926588..67133a5a85 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.58 2004/08/29 04:13:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.59 2004/11/06 17:46:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -50,7 +50,8 @@ extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, CoercionContext ccontext, CoercionForm cformat); extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, - CoercionForm cformat, bool hideInputCoercion); + CoercionForm cformat, bool hideInputCoercion, + bool lengthCoercionDone); extern Node *coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName); -- GitLab