summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane2000-02-20 21:32:16 +0000
committerTom Lane2000-02-20 21:32:16 +0000
commit57b30e8e226014c8d06bae0158e0c7fc679f700b (patch)
tree172a3052e6c88922d63726bacd092afac6bf053c /src/backend/optimizer
parentbd8e071482e3c33876295aae5523fe57ce35025b (diff)
Create a new expression node type RelabelType, which exists solely to
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.
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/util/clauses.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 664a0dfaaa5..4bb84f15214 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -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;