diff options
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 139 |
1 files changed, 83 insertions, 56 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index df1bb3f2c21..026c66168ba 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.21 1999/07/17 20:17:23 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.22 1999/08/05 02:33:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,74 +35,101 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 atttypmod) { Node *result = NULL; - Type targetType; - Oid infunc; - Datum val; - if (targetTypeId == InvalidOid) + if (targetTypeId == InvalidOid || + targetTypeId == inputTypeId) + { + /* no conversion needed */ result = node; - else if (inputTypeId != targetTypeId) + } + else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId)) { - - /* - * one of the known-good transparent conversions? then drop - * through... + /* no work if one of the known-good transparent conversions */ + result = node; + } + else if (inputTypeId == UNKNOWNOID && IsA(node, Const)) + { + /* Input is a string constant with previously undetermined type. + * Apply the target type's typinput function to it to produce + * a constant of the target type. + * + * NOTE: this case cannot be folded together with the other + * constant-input case, since the typinput function does not + * necessarily behave the same as a type conversion function. + * For example, int4's typinput function will reject "1.2", + * whereas float-to-int type conversion will round to integer. */ - if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId)) - result = node; + Const *con = (Const *) node; + Type targetType = typeidType(targetTypeId); + char *val; + /* We know the source constant is really of type 'text' */ + val = textout((text *) con->constvalue); + + /* now make a new const node */ + con = makeNode(Const); + con->consttype = targetTypeId; + con->constlen = typeLen(targetType); + con->constvalue = stringTypeDatum(targetType, val, atttypmod); + con->constisnull = false; + con->constbyval = typeByVal(targetType); + con->constisset = false; + + pfree(val); + + result = (Node *) con; + } + else + { /* - * if not unknown input type, try for explicit conversion using - * functions... + * Otherwise, find the appropriate type conversion function + * (caller should have determined that there is one), and + * generate an expression tree representing run-time + * application of the conversion function. */ - else if (inputTypeId != UNKNOWNOID) - { + FuncCall *n = makeNode(FuncCall); + Type targetType = typeidType(targetTypeId); - /* - * We already know there is a function which will do this, so - * let's use it - */ - FuncCall *n = makeNode(FuncCall); + n->funcname = typeTypeName(targetType); + n->args = lcons(node, NIL); - n->funcname = typeidTypeName(targetTypeId); - n->args = lcons(node, NIL); + result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST); - result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST); - } - else + /* + * If the input is a constant, apply the type conversion function + * now instead of delaying to runtime. (This could someday be + * done in a downstream constant-expression-simplifier, but we + * can save cycles in the rewriter if we do it here.) + * + * XXX there are cases where we probably shouldn't do this, + * such as coercing text 'now' to datetime? Need a way to + * know whether type conversion function is cacheable... + */ + if (IsA(node, Const)) { - if (nodeTag(node) == T_Const) - { - Const *con = (Const *) node; - - val = (Datum) textout((struct varlena *) con->constvalue); - targetType = typeidType(targetTypeId); - infunc = typeInfunc(targetType); - con = makeNode(Const); - con->consttype = targetTypeId; - con->constlen = typeLen(targetType); - - /* - * Use "-1" for varchar() type. For char(), we need to pad - * out the type with the proper number of spaces. This - * was a major problem for DEFAULT string constants to - * char() types. - */ - con->constvalue = (Datum) fmgr(infunc, - val, - typeTypElem(targetType), - (targetTypeId != BPCHAROID) ? -1 : atttypmod); - con->constisnull = false; - con->constbyval = typeByVal(targetType); - con->constisset = false; - result = (Node *) con; - } - else - result = node; + Const *con = (Const *) node; + Oid convertFuncid; + Datum val; + + Assert(IsA(result, Expr) && + ((Expr *) result)->opType == FUNC_EXPR); + + /* Convert the given constant */ + convertFuncid = ((Func *) (((Expr *) result)->oper))->funcid; + val = (Datum) fmgr(convertFuncid, con->constvalue); + + /* now make a new const node */ + con = makeNode(Const); + con->consttype = targetTypeId; + con->constlen = typeLen(targetType); + con->constvalue = val; + con->constisnull = false; + con->constbyval = typeByVal(targetType); + con->constisset = false; + + result = (Node *) con; } } - else - result = node; return result; } |