aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c64
-rw-r--r--src/backend/nodes/copyfuncs.c25
-rw-r--r--src/backend/nodes/equalfuncs.c17
-rw-r--r--src/backend/nodes/freefuncs.c21
-rw-r--r--src/backend/nodes/outfuncs.c18
-rw-r--r--src/backend/nodes/readfuncs.c33
-rw-r--r--src/backend/optimizer/util/clauses.c45
-rw-r--r--src/backend/parser/parse_coerce.c32
-rw-r--r--src/backend/parser/parse_expr.c9
-rw-r--r--src/backend/parser/parse_func.c58
-rw-r--r--src/backend/utils/adt/ruleutils.c60
-rw-r--r--src/include/nodes/nodes.h3
-rw-r--r--src/include/nodes/primnodes.h26
13 files changed, 325 insertions, 86 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 91dbde63419..a319e2c2b37 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -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;
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5bf01e22722..fbef91b35d8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fadc282d1ad..b4f5fc6285c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c
index 8eed80e61ab..daca4a6d96a 100644
--- a/src/backend/nodes/freefuncs.c
+++ b/src/backend/nodes/freefuncs.c
@@ -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;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c40ca9ff9cb..db785afab9f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 7d1e0b4cccf..dfbdbef9884 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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)
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;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index dbb6cbc5816..646f1a046b3 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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
{
/*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 365378f4072..3fd3370672f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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;
}
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 939d7a91ec3..71cda760874 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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,
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index d18cff2789c..0267fc2c576 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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, ')');
}
/* ----------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 8dd893e3f13..f42f615c7a6 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -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)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index bdeff737b63..7c3e0c6c4b8 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -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 */