Revise parse_coerce() to handle coercion of int and float
authorTom Lane
Thu, 5 Aug 1999 02:33:54 +0000 (02:33 +0000)
committerTom Lane
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 */