]> granicus.if.org Git - postgresql/commitdiff
Revise parse_coerce() to handle coercion of int and float
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Aug 1999 02:33:54 +0000 (02:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Aug 1999 02:33:54 +0000 (02:33 +0000)
constants, not only string constants, at parse time.  Get rid of
parser_typecast2(), which is bogus and redundant...

src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_type.c
src/include/parser/parse_expr.h
src/include/parser/parse_type.h

index df1bb3f2c21d14f9e16b9f75d06d0a1fcd7daa5e..026c66168ba18bc60da5cf3c10e5a2826c286edb 100644 (file)
@@ -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;
 }
index e9a6745334242cf082540109c71c22b90acc208f..0ecee29f52d8b7ed989a5a1546f21692cd28d5af 100644 (file)
@@ -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);
 
index 33d93fc9eb88c3b6625c89cda4527e15e6db0801..65f177885d4349d4744770e2332938120531dfbd 100644 (file)
@@ -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),
index ae826adcd90eea5dcc59bbcb5bf4c0da110df463..38cf29d636c649f1c825da57ca4ce054f80adad8 100644 (file)
@@ -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;
+}
index 3bd4d3fb47c6b53e3b7bb57d23288a61ce7c94a8..52d723db1cf2cdd2f6dd03a053d6377ce768b2a4 100644 (file)
@@ -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 */
index 5ca8f9b34c558db5964b3abac5dd91930e77f29c..3b722af6f13b18fcbbfdbb853374917b91da578f 100644 (file)
@@ -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 */