OSDN Git Service

Create a new expression node type RelabelType, which exists solely to
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 Feb 2000 21:32:16 +0000 (21:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 Feb 2000 21:32:16 +0000 (21:32 +0000)
represent the result of a binary-compatible type coercion.  At runtime
it just evaluates its argument --- but during type resolution, exprType
will pick up the output type of the RelabelType node instead of the type
of the argument.  This solves some longstanding problems with dropped
type coercions, an example being 'select now()::abstime::int4' which
used to produce date-formatted output, not an integer, because the
coercion to int4 was dropped on the floor.

13 files changed:
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/freefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/nodes.h
src/include/nodes/primnodes.h

index 91dbde6..a319e2c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.67 2000/01/26 05:56:21 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.68 2000/02/20 21:32:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1176,7 +1176,7 @@ ExecEvalExpr(Node *expression,
                         bool *isNull,
                         bool *isDone)
 {
-       Datum           retDatum = 0;
+       Datum           retDatum;
 
        *isNull = false;
 
@@ -1200,36 +1200,33 @@ ExecEvalExpr(Node *expression,
        switch (nodeTag(expression))
        {
                case T_Var:
-                       retDatum = (Datum) ExecEvalVar((Var *) expression, econtext, isNull);
+                       retDatum = ExecEvalVar((Var *) expression, econtext, isNull);
                        break;
                case T_Const:
                        {
                                Const      *con = (Const *) expression;
 
-                               if (con->constisnull)
-                                       *isNull = true;
                                retDatum = con->constvalue;
+                               *isNull = con->constisnull;
                                break;
                        }
                case T_Param:
-                       retDatum = (Datum) ExecEvalParam((Param *) expression, econtext, isNull);
+                       retDatum = ExecEvalParam((Param *) expression, econtext, isNull);
                        break;
                case T_Iter:
-                       retDatum = (Datum) ExecEvalIter((Iter *) expression,
-                                                                                       econtext,
-                                                                                       isNull,
-                                                                                       isDone);
+                       retDatum = ExecEvalIter((Iter *) expression,
+                                                                       econtext,
+                                                                       isNull,
+                                                                       isDone);
                        break;
                case T_Aggref:
-                       retDatum = (Datum) ExecEvalAggref((Aggref *) expression,
-                                                                                         econtext,
-                                                                                         isNull);
+                       retDatum = ExecEvalAggref((Aggref *) expression, econtext, isNull);
                        break;
                case T_ArrayRef:
-                       retDatum = (Datum) ExecEvalArrayRef((ArrayRef *) expression,
-                                                                                               econtext,
-                                                                                               isNull,
-                                                                                               isDone);
+                       retDatum = ExecEvalArrayRef((ArrayRef *) expression,
+                                                                               econtext,
+                                                                               isNull,
+                                                                               isDone);
                        break;
                case T_Expr:
                        {
@@ -1238,37 +1235,48 @@ ExecEvalExpr(Node *expression,
                                switch (expr->opType)
                                {
                                        case OP_EXPR:
-                                               retDatum = (Datum) ExecEvalOper(expr, econtext, isNull);
+                                               retDatum = ExecEvalOper(expr, econtext, isNull);
                                                break;
                                        case FUNC_EXPR:
-                                               retDatum = (Datum) ExecEvalFunc(expr, econtext, isNull, isDone);
+                                               retDatum = ExecEvalFunc(expr, econtext,
+                                                                                               isNull, isDone);
                                                break;
                                        case OR_EXPR:
-                                               retDatum = (Datum) ExecEvalOr(expr, econtext, isNull);
+                                               retDatum = ExecEvalOr(expr, econtext, isNull);
                                                break;
                                        case AND_EXPR:
-                                               retDatum = (Datum) ExecEvalAnd(expr, econtext, isNull);
+                                               retDatum = ExecEvalAnd(expr, econtext, isNull);
                                                break;
                                        case NOT_EXPR:
-                                               retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
+                                               retDatum = ExecEvalNot(expr, econtext, isNull);
                                                break;
                                        case SUBPLAN_EXPR:
-                                               retDatum = (Datum) ExecSubPlan((SubPlan *) expr->oper,
-                                                                                                          expr->args, econtext,
-                                                                                                          isNull);
+                                               retDatum = ExecSubPlan((SubPlan *) expr->oper,
+                                                                                          expr->args, econtext,
+                                                                                          isNull);
                                                break;
                                        default:
-                                               elog(ERROR, "ExecEvalExpr: unknown expression type %d", expr->opType);
+                                               elog(ERROR, "ExecEvalExpr: unknown expression type %d",
+                                                        expr->opType);
+                                               retDatum = 0; /* keep compiler quiet */
                                                break;
                                }
                                break;
                        }
+               case T_RelabelType:
+                       retDatum = ExecEvalExpr(((RelabelType *) expression)->arg,
+                                                                       econtext,
+                                                                       isNull,
+                                                                       isDone);
+                       break;
                case T_CaseExpr:
-                       retDatum = (Datum) ExecEvalCase((CaseExpr *) expression, econtext, isNull);
+                       retDatum = ExecEvalCase((CaseExpr *) expression, econtext, isNull);
                        break;
 
                default:
-                       elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression));
+                       elog(ERROR, "ExecEvalExpr: unknown expression type %d",
+                                nodeTag(expression));
+                       retDatum = 0;           /* keep compiler quiet */
                        break;
        }
 
index 5bf01e2..fbef91b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.106 2000/02/15 20:49:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.107 2000/02/20 21:32:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -874,6 +874,26 @@ _copySubLink(SubLink *from)
 }
 
 /* ----------------
+ *             _copyRelabelType
+ * ----------------
+ */
+static RelabelType *
+_copyRelabelType(RelabelType *from)
+{
+       RelabelType    *newnode = makeNode(RelabelType);
+
+       /* ----------------
+        *      copy remainder of node
+        * ----------------
+        */
+       Node_Copy(from, newnode, arg);
+       newnode->resulttype = from->resulttype;
+       newnode->resulttypmod = from->resulttypmod;
+
+       return newnode;
+}
+
+/* ----------------
  *             _copyCaseExpr
  * ----------------
  */
@@ -1617,6 +1637,9 @@ copyObject(void *from)
                case T_SubLink:
                        retval = _copySubLink(from);
                        break;
+               case T_RelabelType:
+                       retval = _copyRelabelType(from);
+                       break;
                case T_CaseExpr:
                        retval = _copyCaseExpr(from);
                        break;
index fadc282..b4f5fc6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.61 2000/02/15 20:49:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.62 2000/02/20 21:32:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -263,6 +263,18 @@ _equalSubLink(SubLink *a, SubLink *b)
 }
 
 static bool
+_equalRelabelType(RelabelType *a, RelabelType *b)
+{
+       if (!equal(a->arg, b->arg))
+               return false;
+       if (a->resulttype != b->resulttype)
+               return false;
+       if (a->resulttypmod != b->resulttypmod)
+               return false;
+       return true;
+}
+
+static bool
 _equalArray(Array *a, Array *b)
 {
        if (a->arrayelemtype != b->arrayelemtype)
@@ -806,6 +818,9 @@ equal(void *a, void *b)
                case T_SubLink:
                        retval = _equalSubLink(a, b);
                        break;
+               case T_RelabelType:
+                       retval = _equalRelabelType(a, b);
+                       break;
                case T_Func:
                        retval = _equalFunc(a, b);
                        break;
index 8eed80e..daca4a6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.36 2000/02/15 20:49:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.37 2000/02/20 21:32:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -651,6 +651,22 @@ _freeSubLink(SubLink *node)
 }
 
 /* ----------------
+ *             _freeRelabelType
+ * ----------------
+ */
+static void
+_freeRelabelType(RelabelType *node)
+{
+       /* ----------------
+        *      free remainder of node
+        * ----------------
+        */
+       freeObject(node->arg);
+
+       pfree(node);
+}
+
+/* ----------------
  *             _freeCaseExpr
  * ----------------
  */
@@ -1241,6 +1257,9 @@ freeObject(void *node)
                case T_SubLink:
                        _freeSubLink(node);
                        break;
+               case T_RelabelType:
+                       _freeRelabelType(node);
+                       break;
                case T_CaseExpr:
                        _freeCaseExpr(node);
                        break;
index c40ca9f..db785af 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.108 2000/02/15 20:49:09 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.109 2000/02/20 21:32:05 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -771,6 +771,19 @@ _outSubLink(StringInfo str, SubLink *node)
 }
 
 /*
+ *     RelabelType
+ */
+static void
+_outRelabelType(StringInfo str, RelabelType *node)
+{
+       appendStringInfo(str, " RELABELTYPE :arg ");
+       _outNode(str, node->arg);
+
+       appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
+                                        node->resulttype, node->resulttypmod);
+}
+
+/*
  *     Array is a subclass of Expr
  */
 static void
@@ -1496,6 +1509,9 @@ _outNode(StringInfo str, void *obj)
                        case T_SubLink:
                                _outSubLink(str, obj);
                                break;
+                       case T_RelabelType:
+                               _outRelabelType(str, obj);
+                               break;
                        case T_Array:
                                _outArray(str, obj);
                                break;
index 7d1e0b4..dfbdbef 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.84 2000/02/15 20:49:12 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.85 2000/02/20 21:32:05 tgl Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -1191,6 +1191,35 @@ _readSubLink()
        return local_node;
 }
 
+/* ----------------
+ *             _readRelabelType
+ *
+ *     RelabelType is a subclass of Node
+ * ----------------
+ */
+static RelabelType *
+_readRelabelType()
+{
+       RelabelType *local_node;
+       char       *token;
+       int                     length;
+
+       local_node = makeNode(RelabelType);
+
+       token = lsptok(NULL, &length);          /* eat :arg */
+       local_node->arg = nodeRead(true);       /* now read it */
+
+       token = lsptok(NULL, &length);          /* eat :resulttype */
+       token = lsptok(NULL, &length);          /* get resulttype */
+       local_node->resulttype = (Oid) atol(token);
+
+       token = lsptok(NULL, &length);          /* eat :resulttypmod */
+       token = lsptok(NULL, &length);          /* get resulttypmod */
+       local_node->resulttypmod = atoi(token);
+
+       return local_node;
+}
+
 /*
  *     Stuff from execnodes.h
  */
@@ -1820,6 +1849,8 @@ parsePlanString(void)
                return_value = _readAggref();
        else if (length == 7 && strncmp(token, "SUBLINK", length) == 0)
                return_value = _readSubLink();
+       else if (length == 11 && strncmp(token, "RELABELTYPE", length) == 0)
+               return_value = _readRelabelType();
        else if (length == 3 && strncmp(token, "AGG", length) == 0)
                return_value = _readAgg();
        else if (length == 4 && strncmp(token, "HASH", length) == 0)
index 664a0df..4bb84f1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.59 2000/02/15 03:37:36 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.60 2000/02/20 21:32:06 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -1150,6 +1150,37 @@ eval_const_expressions_mutator (Node *node, void *context)
         newexpr->args = args;
         return (Node *) newexpr;
        }
+       if (IsA(node, RelabelType))
+       {
+               /*
+                * If we can simplify the input to a constant, then we don't need
+                * the RelabelType node anymore: just change the type field of
+                * the Const node.  Otherwise keep the RelabelType node.
+                *
+                * XXX if relabel has a nondefault resulttypmod, do we need to
+                * keep it to show that?  At present I don't think so.
+                */
+               RelabelType *relabel = (RelabelType *) node;
+               Node       *arg;
+
+               arg = eval_const_expressions_mutator(relabel->arg, context);
+               if (arg && IsA(arg, Const))
+               {
+                       Const  *con = (Const *) arg;
+
+                       con->consttype = relabel->resulttype;
+                       return (Node *) con;
+               }
+               else
+               {
+                       RelabelType *newrelabel = makeNode(RelabelType);
+
+                       newrelabel->arg = arg;
+                       newrelabel->resulttype = relabel->resulttype;
+                       newrelabel->resulttypmod = relabel->resulttypmod;
+                       return (Node *) newrelabel;
+               }
+       }
        if (IsA(node, CaseExpr))
        {
                /*
@@ -1392,6 +1423,8 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
                                        return true;
                        }
                        break;
+               case T_RelabelType:
+                       return walker(((RelabelType *) node)->arg, context);
                case T_CaseExpr:
                        {
                                CaseExpr   *caseexpr = (CaseExpr *) node;
@@ -1603,6 +1636,16 @@ expression_tree_mutator(Node *node, Node * (*mutator) (), void *context)
                                return (Node *) newnode;
                        }
                        break;
+               case T_RelabelType:
+                       {
+                               RelabelType *relabel = (RelabelType *) node;
+                               RelabelType *newnode;
+
+                               FLATCOPY(newnode, relabel, RelabelType);
+                               MUTATE(newnode->arg, relabel->arg, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_CaseExpr:
                        {
                                CaseExpr   *caseexpr = (CaseExpr *) node;
index dbb6cbc..646f1a0 100644 (file)
@@ -1,14 +1,14 @@
 /*-------------------------------------------------------------------------
  *
  * parse_coerce.c
- *             handle type coersions/conversions for parser
+ *             handle type coercions/conversions for parser
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.31 2000/02/20 06:28:42 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.32 2000/02/20 21:32:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ Node *
 coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                        Oid targetTypeId, int32 atttypmod)
 {
-       Node       *result = NULL;
+       Node       *result;
 
        if (targetTypeId == InvalidOid ||
                targetTypeId == inputTypeId)
@@ -44,11 +44,6 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                /* no conversion needed */
                result = node;
        }
-       else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
-       {
-               /* no work if one of the known-good transparent conversions */
-               result = node;
-       }
        else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
        {
                /*
@@ -87,6 +82,27 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 
                result = (Node *) newcon;
        }
+       else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
+       {
+               /*
+                * We don't really need to do a conversion, but we do need to attach
+                * a RelabelType node so that the expression will be seen to have
+                * the intended type when inspected by higher-level code.
+                */
+               RelabelType *relabel = makeNode(RelabelType);
+
+               relabel->arg = node;
+               relabel->resulttype = targetTypeId;
+               /*
+                * XXX could we label result with exprTypmod(node) instead of
+                * default -1 typmod, to save a possible length-coercion later?
+                * Would work if both types have same interpretation of typmod,
+                * which is likely but not certain.
+                */
+               relabel->resulttypmod = -1;
+
+               result = (Node *) relabel;
+       }
        else
        {
                /*
index 365378f..3fd3370 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.68 2000/02/15 03:37:47 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.69 2000/02/20 21:32:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -516,6 +516,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                case T_Param:
                case T_Aggref:
                case T_ArrayRef:
+               case T_RelabelType:
                        {
                                result = (Node *) expr;
                                break;
@@ -627,6 +628,9 @@ exprType(Node *expr)
                case T_Param:
                        type = ((Param *) expr)->paramtype;
                        break;
+               case T_RelabelType:
+                       type = ((RelabelType *) expr)->resulttype;
+                       break;
                case T_SubLink:
                        {
                                SubLink    *sublink = (SubLink *) expr;
@@ -697,6 +701,9 @@ exprTypmod(Node *expr)
                                }
                        }
                        break;
+               case T_RelabelType:
+                       return ((RelabelType *) expr)->resulttypmod;
+                       break;
                default:
                        break;
        }
index 939d7a9..71cda76 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.70 2000/02/20 06:35:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.71 2000/02/20 21:32:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -163,7 +163,10 @@ agg_get_candidates(char *aggname,
 }      /* agg_get_candidates() */
 
 /* agg_select_candidate()
- * Try to choose only one candidate aggregate function from a list of possibles.
+ *
+ * Try to choose only one candidate aggregate function from a list of
+ * possible matches.  Return value is Oid of input type of aggregate
+ * if successful, else InvalidOid.
  */
 static Oid
 agg_select_candidate(Oid typeid, CandidateList candidates)
@@ -175,10 +178,12 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
        CATEGORY        category,
                                current_category;
 
-/*
- * First look for exact matches or binary compatible matches.
- * (Of course exact matches shouldn't even get here, but anyway.)
- */
+       /*
+        * First look for exact matches or binary compatible matches.
+        * (Of course exact matches shouldn't even get here, but anyway.)
+        */
+       ncandidates = 0;
+       last_candidate = NULL;
        for (current_candidate = candidates;
                 current_candidate != NULL;
                 current_candidate = current_candidate->next)
@@ -188,15 +193,17 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
                if (current_typeid == typeid
             || IS_BINARY_COMPATIBLE(current_typeid, typeid))
                {
-            /* we're home free */
-            return current_typeid;
+                       last_candidate = current_candidate;
+                       ncandidates++;
         }
     }
+       if (ncandidates == 1)
+               return last_candidate->args[0];
 
-/*
* If no luck that way, look for candidates which allow coersion
- * and have a preferred type. Keep all candidates if none match.
- */
+       /*
       * If no luck that way, look for candidates which allow coercion
       * and have a preferred type. Keep all candidates if none match.
       */
        category = TypeCategory(typeid);
        ncandidates = 0;
        last_candidate = NULL;
@@ -232,7 +239,10 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
        if (last_candidate)                     /* terminate rebuilt list */
                last_candidate->next = NULL;
 
-       return ((ncandidates == 1) ? candidates->args[0] : 0);
+       if (ncandidates == 1)
+               return candidates->args[0];
+
+       return InvalidOid;
 }      /* agg_select_candidate() */
 
 
@@ -471,10 +481,9 @@ 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... This means that you are trying for a
-        * type conversion which does not need to take place, so we'll
-        * just pass through the argument itself. (make this clearer
-        * with some extra brackets - thomas 1998-12-05)
+        * 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.
         */
        if (nargs == 1)
        {
@@ -486,8 +495,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                if (HeapTupleIsValid(tp) &&
                        IS_BINARY_COMPATIBLE(typeTypeId(tp), exprType(lfirst(fargs))))
                {
-                       /* XXX FIXME: probably need to change expression's marked type? */
-                       return (Node *) lfirst(fargs);
+                       RelabelType *relabel = makeNode(RelabelType);
+
+                       relabel->arg = (Node *) lfirst(fargs);
+                       relabel->resulttype = typeTypeId(tp);
+                       relabel->resulttypmod = -1;
+
+                       return (Node *) relabel;
                }
        }
 
@@ -1128,7 +1142,7 @@ func_get_detail(char *funcname,
  *                                              inheritance properties of the supplied argv.
  *
  *             This function is used to disambiguate among functions with the
- *             same name but different signatures.  It takes an array of eight
+ *             same name but different signatures.  It takes an array of input
  *             type ids.  For each type id in the array that's a complex type
  *             (a class), it walks up the inheritance tree, finding all
  *             superclasses of that type.      A vector of new Oid type arrays
@@ -1342,7 +1356,7 @@ gen_cross_product(InhPaths *arginh, int nargs)
  *     2) the input type can be typecast into the function type
  * Right now, we only typecast unknowns, and that is all we check for.
  *
- * func_get_detail() now can find coersions for function arguments which
+ * func_get_detail() now can find coercions for function arguments which
  *     will make this function executable. So, we need to recover these
  *     results here too.
  * - thomas 1998-03-25
@@ -1361,7 +1375,7 @@ make_arguments(ParseState *pstate,
                 i < nargs;
                 i++, current_fargs = lnext(current_fargs))
        {
-               /* types don't match? then force coersion using a function call... */
+               /* types don't match? then force coercion using a function call... */
                if (input_typeids[i] != function_typeids[i])
                {
                        lfirst(current_fargs) = coerce_type(pstate,
index d18cff2..0267fc2 100644 (file)
@@ -3,7 +3,7 @@
  *                       out of its tuple
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.41 2000/02/15 08:24:12 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.42 2000/02/20 21:32:12 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1006,7 +1006,7 @@ get_select_query_def(Query *query, deparse_context *context)
                                                appendStringInfo(buf, "%s",
                                                                                 quote_identifier(strVal(lfirst(col))));
                                        }
-                                       appendStringInfo(buf, ")");
+                                       appendStringInfoChar(buf, ')');
                                }
                        }
                }
@@ -1127,7 +1127,7 @@ get_insert_query_def(Query *query, deparse_context *context)
                        sep = ", ";
                        get_tle_expr(tle, context);
                }
-               appendStringInfo(buf, ")");
+               appendStringInfoChar(buf, ')');
        }
        else
                get_select_query_def(query, context);
@@ -1281,7 +1281,7 @@ get_rule_expr(Node *node, deparse_context *context)
                                switch (expr->opType)
                                {
                                        case OP_EXPR:
-                                               appendStringInfo(buf, "(");
+                                               appendStringInfoChar(buf, '(');
                                                if (length(args) == 2)
                                                {
                                                        /* binary operator */
@@ -1320,35 +1320,35 @@ get_rule_expr(Node *node, deparse_context *context)
                                                                        elog(ERROR, "get_rule_expr: bogus oprkind");
                                                        }
                                                }
-                                               appendStringInfo(buf, ")");
+                                               appendStringInfoChar(buf, ')');
                                                break;
 
                                        case OR_EXPR:
-                                               appendStringInfo(buf, "(");
+                                               appendStringInfoChar(buf, '(');
                                                get_rule_expr((Node *) lfirst(args), context);
                                                while ((args = lnext(args)) != NIL)
                                                {
                                                        appendStringInfo(buf, " OR ");
                                                        get_rule_expr((Node *) lfirst(args), context);
                                                }
-                                               appendStringInfo(buf, ")");
+                                               appendStringInfoChar(buf, ')');
                                                break;
 
                                        case AND_EXPR:
-                                               appendStringInfo(buf, "(");
+                                               appendStringInfoChar(buf, '(');
                                                get_rule_expr((Node *) lfirst(args), context);
                                                while ((args = lnext(args)) != NIL)
                                                {
                                                        appendStringInfo(buf, " AND ");
                                                        get_rule_expr((Node *) lfirst(args), context);
                                                }
-                                               appendStringInfo(buf, ")");
+                                               appendStringInfoChar(buf, ')');
                                                break;
 
                                        case NOT_EXPR:
                                                appendStringInfo(buf, "(NOT ");
                                                get_rule_expr((Node *) lfirst(args), context);
-                                               appendStringInfo(buf, ")");
+                                               appendStringInfoChar(buf, ')');
                                                break;
 
                                        case FUNC_EXPR:
@@ -1373,7 +1373,7 @@ get_rule_expr(Node *node, deparse_context *context)
                                        appendStringInfo(buf, "*");
                                else
                                        get_rule_expr(aggref->target, context);
-                               appendStringInfo(buf, ")");
+                               appendStringInfoChar(buf, ')');
                        }
                        break;
 
@@ -1405,6 +1405,28 @@ get_rule_expr(Node *node, deparse_context *context)
                        }
                        break;
 
+               case T_RelabelType:
+                       {
+                               RelabelType *relabel = (RelabelType *) node;
+                               HeapTuple       typetup;
+                               Form_pg_type typeStruct;
+                               char       *extval;
+
+                               appendStringInfoChar(buf, '(');
+                               get_rule_expr(relabel->arg, context);
+                               typetup = SearchSysCacheTuple(TYPEOID,
+                                                                       ObjectIdGetDatum(relabel->resulttype),
+                                                                                         0, 0, 0);
+                               if (!HeapTupleIsValid(typetup))
+                                       elog(ERROR, "cache lookup of type %u failed",
+                                                relabel->resulttype);
+                               typeStruct = (Form_pg_type) GETSTRUCT(typetup);
+                               extval = pstrdup(NameStr(typeStruct->typname));
+                               appendStringInfo(buf, ")::%s", quote_identifier(extval));
+                               pfree(extval);
+                       }
+                       break;
+
                case T_CaseExpr:
                        {
                                CaseExpr   *caseexpr = (CaseExpr *) node;
@@ -1474,14 +1496,14 @@ get_func_expr(Expr *expr, deparse_context *context)
        {
                if (!strcmp(proname, "nullvalue"))
                {
-                       appendStringInfo(buf, "(");
+                       appendStringInfoChar(buf, '(');
                        get_rule_expr((Node *) lfirst(expr->args), context);
                        appendStringInfo(buf, " ISNULL)");
                        return;
                }
                if (!strcmp(proname, "nonnullvalue"))
                {
-                       appendStringInfo(buf, "(");
+                       appendStringInfoChar(buf, '(');
                        get_rule_expr((Node *) lfirst(expr->args), context);
                        appendStringInfo(buf, " NOTNULL)");
                        return;
@@ -1500,7 +1522,7 @@ get_func_expr(Expr *expr, deparse_context *context)
                sep = ", ";
                get_rule_expr((Node *) lfirst(l), context);
        }
-       appendStringInfo(buf, ")");
+       appendStringInfoChar(buf, ')');
 }
 
 
@@ -1712,13 +1734,13 @@ get_sublink_expr(Node *node, deparse_context *context)
        Oper       *oper;
        bool            need_paren;
 
-       appendStringInfo(buf, "(");
+       appendStringInfoChar(buf, '(');
 
        if (sublink->lefthand != NIL)
        {
                need_paren = (length(sublink->lefthand) > 1);
                if (need_paren)
-                       appendStringInfo(buf, "(");
+                       appendStringInfoChar(buf, '(');
 
                sep = "";
                foreach(l, sublink->lefthand)
@@ -1731,7 +1753,7 @@ get_sublink_expr(Node *node, deparse_context *context)
                if (need_paren)
                        appendStringInfo(buf, ") ");
                else
-                       appendStringInfo(buf, " ");
+                       appendStringInfoChar(buf, ' ');
        }
 
        need_paren = true;
@@ -1768,14 +1790,14 @@ get_sublink_expr(Node *node, deparse_context *context)
        }
 
        if (need_paren)
-               appendStringInfo(buf, "(");
+               appendStringInfoChar(buf, '(');
 
        get_query_def(query, buf, context->rangetables);
 
        if (need_paren)
                appendStringInfo(buf, "))");
        else
-               appendStringInfo(buf, ")");
+               appendStringInfoChar(buf, ')');
 }
 
 /* ----------
index 8dd893e..f42f615 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.65 2000/02/18 09:29:43 inoue Exp $
+ * $Id: nodes.h,v 1.66 2000/02/20 21:32:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,6 +67,7 @@ typedef enum NodeTag
        T_Array,
        T_ArrayRef,
        T_Iter,
+       T_RelabelType,
 
        /*---------------------
         * TAGS FOR PLANNER NODES (relation.h)
index bdeff73..7c3e0c6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.39 2000/01/26 05:58:16 momjian Exp $
+ * $Id: primnodes.h,v 1.40 2000/02/20 21:32:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -467,4 +467,28 @@ typedef struct ArrayRef
        Node       *refassgnexpr;
 } ArrayRef;
 
+/* ----------------
+ * RelabelType
+ *             arg                             - input expression
+ *             resulttype              - output type of coercion expression
+ *             resulttypmod    - output typmod (usually -1)
+ *
+ * RelabelType represents a "dummy" type coercion between two binary-
+ * compatible datatypes, such as reinterpreting the result of an OID
+ * expression as an int4.  It is a no-op at runtime; we only need it
+ * to provide a place to store the correct type to be attributed to
+ * the expression result during type resolution.  (We can't get away
+ * with just overwriting the type field of the input expression node,
+ * so we need a separate node to show the coercion's result type.)
+ * ----------------
+ */
+
+typedef struct RelabelType
+{
+       NodeTag         type;
+       Node       *arg;
+       Oid                     resulttype;
+       int32           resulttypmod;
+} RelabelType;
+
 #endif  /* PRIMNODES_H */