From fd19a350ea0a69f26ac2f8cdc28fdd4ff9264adb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 5 Aug 1999 02:33:54 +0000 Subject: [PATCH] Revise parse_coerce() to handle coercion of int and float constants, not only string constants, at parse time. Get rid of parser_typecast2(), which is bogus and redundant... --- src/backend/parser/parse_coerce.c | 139 ++++++++++++++++++------------- src/backend/parser/parse_expr.c | 170 +++----------------------------------- src/backend/parser/parse_func.c | 17 +--- src/backend/parser/parse_type.c | 19 ++++- src/include/parser/parse_expr.h | 3 +- src/include/parser/parse_type.h | 5 +- 6 files changed, 114 insertions(+), 239 deletions(-) diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index df1bb3f2c2..026c66168b 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; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index e9a6745334..0ecee29f52 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.55 1999/07/19 00:26:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.56 1999/08/05 02:33:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -631,16 +631,16 @@ exprTypmod(Node *expr) return -1; } +/* + * Produce an appropriate Const node from a constant value produced + * by the parser and an explicit type name to cast to. + */ static Node * parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) { - /* check for passing non-ints */ Const *adt; Datum lcp; Type tp; - char type_string[NAMEDATALEN]; - int32 len; - char *cp = NULL; char *const_string = NULL; bool string_palloced = false; @@ -659,180 +659,30 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) break; default: elog(ERROR, - "parser_typecast: cannot cast this expression to type '%s'", + "parser_typecast: cannot cast this expression to type '%s'", typename->name); } if (typename->arrayBounds != NIL) { + char type_string[NAMEDATALEN+2]; + sprintf(type_string, "_%s", typename->name); tp = (Type) typenameType(type_string); } else tp = (Type) typenameType(typename->name); - len = typeLen(tp); - - cp = stringTypeString(tp, const_string, atttypmod); - - if (!typeByVal(tp)) - lcp = PointerGetDatum(cp); - else - { - switch (len) - { - case 1: - lcp = Int8GetDatum(cp); - break; - case 2: - lcp = Int16GetDatum(cp); - break; - case 4: - lcp = Int32GetDatum(cp); - break; - default: - lcp = PointerGetDatum(cp); - break; - } - } - - adt = makeConst(typeTypeId(tp), - len, - (Datum) lcp, - false, - typeByVal(tp), - false, /* not a set */ - true /* is cast */ ); - - if (string_palloced) - pfree(const_string); - - return (Node *) adt; -} - - -/* parser_typecast2() - * Convert (only) constants to specified type. - */ -Node * -parser_typecast2(Node *expr, Oid exprType, Type tp, int32 atttypmod) -{ - /* check for passing non-ints */ - Const *adt; - Datum lcp; - int32 len = typeLen(tp); - char *cp = NULL; - - char *const_string = NULL; - bool string_palloced = false; - - Assert(IsA(expr, Const)); - - switch (exprType) - { - case 0: /* NULL */ - break; - case INT4OID: /* int4 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%d", - (int) ((Const *) expr)->constvalue); - break; - case NAMEOID: /* name */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%s", - (char *) ((Const *) expr)->constvalue); - break; - case CHAROID: /* char */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%c", - (char) ((Const *) expr)->constvalue); - break; - case FLOAT4OID: /* float4 */ - { - float32 floatVal = DatumGetFloat32(((Const *) expr)->constvalue); - - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%f", *floatVal); - break; - } - case FLOAT8OID: /* float8 */ - { - float64 floatVal = DatumGetFloat64(((Const *) expr)->constvalue); - - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%f", *floatVal); - break; - } - case CASHOID: /* money */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%ld", - (long) ((Const *) expr)->constvalue); - break; - case TEXTOID: /* text */ - const_string = DatumGetPointer(((Const *) expr)->constvalue); - const_string = (char *) textout((struct varlena *) const_string); - break; - case UNKNOWNOID: /* unknown */ - const_string = DatumGetPointer(((Const *) expr)->constvalue); - const_string = (char *) textout((struct varlena *) const_string); - break; - default: - elog(ERROR, "unknown type %u", exprType); - } - - if (!exprType) - { - adt = makeConst(typeTypeId(tp), - (Size) 0, - (Datum) NULL, - true, /* isnull */ - false, /* was omitted */ - false, /* not a set */ - true /* is cast */ ); - return (Node *) adt; - } - - cp = stringTypeString(tp, const_string, atttypmod); - - if (!typeByVal(tp)) - lcp = PointerGetDatum(cp); - else - { - switch (len) - { - case 1: - lcp = Int8GetDatum(cp); - break; - case 2: - lcp = Int16GetDatum(cp); - break; - case 4: - lcp = Int32GetDatum(cp); - break; - default: - lcp = PointerGetDatum(cp); - break; - } - } + lcp = stringTypeDatum(tp, const_string, atttypmod); adt = makeConst(typeTypeId(tp), - (Size) len, + typeLen(tp), (Datum) lcp, false, typeByVal(tp), false, /* not a set */ true /* is cast */ ); - /* - * printf("adt %s : %u %d %d\n",CString(expr),typeTypeId(tp) , - * len,cp); - */ if (string_palloced) pfree(const_string); diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 33d93fc9eb..65f177885d 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.50 1999/07/17 20:17:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.51 1999/08/05 02:33:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1278,21 +1278,8 @@ make_arguments(ParseState *pstate, i < nargs; i++, current_fargs = lnext(current_fargs)) { - - /* - * unspecified type for string constant? then use heuristics for - * conversion... - */ - if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid) - { - lfirst(current_fargs) = parser_typecast2(lfirst(current_fargs), - input_typeids[i], - typeidType(function_typeids[i]), - -1); - } - /* types don't match? then force coersion using a function call... */ - else if (input_typeids[i] != function_typeids[i]) + if (input_typeids[i] != function_typeids[i]) { lfirst(current_fargs) = coerce_type(pstate, lfirst(current_fargs), diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index ae826adcd9..38cf29d636 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.24 1999/07/17 20:17:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.25 1999/08/05 02:33:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -133,8 +133,8 @@ typeTypeFlag(Type t) /* Given a type structure and a string, returns the internal form of that string */ -char * -stringTypeString(Type tp, char *string, int32 atttypmod) +Datum +stringTypeDatum(Type tp, char *string, int32 atttypmod) { Oid op; Oid typelem; @@ -142,7 +142,7 @@ stringTypeString(Type tp, char *string, int32 atttypmod) op = ((Form_pg_type) GETSTRUCT(tp))->typinput; typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem; /* XXX - used for * array_in */ - return (char *) fmgr(op, string, typelem, atttypmod); + return (Datum) fmgr(op, string, typelem, atttypmod); } /* Given a type id, returns the out-conversion function of the type */ @@ -242,3 +242,14 @@ typeInfunc(Type typ) return typtup->typinput; } + +/* Given a type structure, return the out-conversion function of the type */ +Oid +typeOutfunc(Type typ) +{ + Form_pg_type typtup; + + typtup = (Form_pg_type) GETSTRUCT(typ); + + return typtup->typoutput; +} diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h index 3bd4d3fb47..52d723db1c 100644 --- a/src/include/parser/parse_expr.h +++ b/src/include/parser/parse_expr.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parse_expr.h,v 1.14 1999/07/19 00:26:16 tgl Exp $ + * $Id: parse_expr.h,v 1.15 1999/08/05 02:33:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,5 @@ extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence); extern Oid exprType(Node *expr); extern int32 exprTypmod(Node *expr); -extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod); #endif /* PARSE_EXPR_H */ diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index 5ca8f9b34c..3b722af6f1 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parse_type.h,v 1.10 1999/05/29 03:17:19 tgl Exp $ + * $Id: parse_type.h,v 1.11 1999/08/05 02:33:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,11 +26,12 @@ extern int16 typeLen(Type t); extern bool typeByVal(Type t); extern char *typeTypeName(Type t); extern char typeTypeFlag(Type t); -extern char *stringTypeString(Type tp, char *string, int32 atttypmod); +extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod); extern Oid typeidTypeRelid(Oid type_id); extern Oid typeTypeRelid(Type typ); extern Oid typeTypElem(Type typ); extern Oid GetArrayElementType(Oid typearray); extern Oid typeInfunc(Type typ); +extern Oid typeOutfunc(Type typ); #endif /* PARSE_TYPE_H */ -- 2.11.0