Further cleanups for type coercion: treat the locution typename(argument)
authorTom Lane
Sun, 20 Feb 2000 23:04:06 +0000 (23:04 +0000)
committerTom Lane
Sun, 20 Feb 2000 23:04:06 +0000 (23:04 +0000)
as representing a type coercion request in more cases than we did before.
It will work now whenever no underlying function is required, ie if the
coercion is binary-compatible or if the argument is a previously untyped
string constant.  Otherwise, you still need a real function to exist.

src/backend/parser/parse_func.c

index 71cda760874d7ac40ac481ddaf93a8b922101d9e..1eeeb17c6257ef12f3e7b2688439e60200a01f69 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.71 2000/02/20 21:32:10 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.72 2000/02/20 23:04:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -292,9 +292,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
        /* Is it a plain Relation name from the parser? */
        if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
        {
+           Ident      *ident = (Ident *) first_arg;
            RangeTblEntry *rte;
            AttrNumber attnum;
-           Ident      *ident = (Ident *) first_arg;
 
            /*
             * first arg is a relation. This could be a projection.
@@ -479,11 +479,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
    }
 
    /*
-    * See if this is a single argument function with the function
-    * name also a type name and the input argument and type name
-    * binary compatible.  If so, we do not need to do any real
-    * conversion, but we do need to build a RelabelType node
-    * so that exprType() sees the result as being of the output type.
+    * See if this is really a type-coercion request: single-argument
+    * function call where the function name is a type name.  If so,
+    * and if we can do the coercion trivially, just go ahead and do it
+    * without requiring there to be a real function for it.  "Trivial"
+    * coercions are ones that involve binary-compatible types and ones
+    * that are coercing a previously-unknown-type literal constant
+    * to a specific type.
     */
    if (nargs == 1)
    {
@@ -492,16 +494,21 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
        tp = SearchSysCacheTuple(TYPENAME,
                                 PointerGetDatum(funcname),
                                 0, 0, 0);
-       if (HeapTupleIsValid(tp) &&
-           IS_BINARY_COMPATIBLE(typeTypeId(tp), exprType(lfirst(fargs))))
+       if (HeapTupleIsValid(tp))
        {
-           RelabelType *relabel = makeNode(RelabelType);
+           Oid     targetType = typeTypeId(tp);
+           Node   *arg1 = lfirst(fargs);
+           Oid     sourceType = exprType(arg1);
 
-           relabel->arg = (Node *) lfirst(fargs);
-           relabel->resulttype = typeTypeId(tp);
-           relabel->resulttypmod = -1;
-
-           return (Node *) relabel;
+           if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
+               sourceType == targetType ||
+               IS_BINARY_COMPATIBLE(sourceType, targetType))
+           {
+               /*
+                * coerce_type can handle these cases, so why duplicate code...
+                */
+               return coerce_type(pstate, arg1, sourceType, targetType, -1);
+           }
        }
    }
 
@@ -516,17 +523,17 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
    nargs = 0;
    foreach(i, fargs)
    {
-       int         vnum;
-       RangeTblEntry *rte;
-       Node       *pair = lfirst(i);
+       Node       *arg = lfirst(i);
 
-       if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)
+       if (IsA(arg, Ident) && ((Ident *) arg)->isRel)
        {
+           RangeTblEntry *rte;
+           int         vnum;
 
            /*
             * a relation
             */
-           refname = ((Ident *) pair)->name;
+           refname = ((Ident *) arg)->name;
 
            rte = refnameRangeTableEntry(pstate, refname);
            if (rte == NULL)
@@ -554,22 +561,15 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
             */
            toid = typeTypeId(typenameType(relname));
            /* replace it in the arg list */
-           lfirst(fargs) = makeVar(vnum, 0, toid, -1, 0);
+           lfirst(i) = makeVar(vnum, 0, toid, -1, 0);
        }
        else if (!attisset)
-       {                       /* set functions don't have parameters */
-
-           /*
-            * any function args which are typed "unknown", but aren't
-            * constants, we don't know what to do with, because we can't
-            * cast them    - jolly
-            */
-           if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))
-               elog(ERROR, "There is no function '%s'"
-                    " with argument #%d of type UNKNOWN",
-                    funcname, nargs+1);
-           else
-               toid = exprType(pair);
+       {
+           toid = exprType(arg);
+       }
+       else
+       {
+           /* if attisset is true, we already set toid for the single arg */
        }
 
        /* Most of the rest of the parser just assumes that functions do not