*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
bool *isNull,
bool *isDone)
{
- Datum retDatum = 0;
+ Datum retDatum;
*isNull = false;
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:
{
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/* ----------------
+ * _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
* ----------------
*/
case T_SubLink:
retval = _copySubLink(from);
break;
+ case T_RelabelType:
+ retval = _copyRelabelType(from);
+ break;
case T_CaseExpr:
retval = _copyCaseExpr(from);
break;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
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)
case T_SubLink:
retval = _equalSubLink(a, b);
break;
+ case T_RelabelType:
+ retval = _equalRelabelType(a, b);
+ break;
case T_Func:
retval = _equalFunc(a, b);
break;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/* ----------------
+ * _freeRelabelType
+ * ----------------
+ */
+static void
+_freeRelabelType(RelabelType *node)
+{
+ /* ----------------
+ * free remainder of node
+ * ----------------
+ */
+ freeObject(node->arg);
+
+ pfree(node);
+}
+
+/* ----------------
* _freeCaseExpr
* ----------------
*/
case T_SubLink:
_freeSubLink(node);
break;
+ case T_RelabelType:
+ _freeRelabelType(node);
+ break;
case T_CaseExpr:
_freeCaseExpr(node);
break;
* 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
}
/*
+ * 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
case T_SubLink:
_outSubLink(str, obj);
break;
+ case T_RelabelType:
+ _outRelabelType(str, obj);
+ break;
case T_Array:
_outArray(str, obj);
break;
*
*
* 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
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
*/
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)
*
*
* 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
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))
{
/*
return true;
}
break;
+ case T_RelabelType:
+ return walker(((RelabelType *) node)->arg, context);
case T_CaseExpr:
{
CaseExpr *caseexpr = (CaseExpr *) node;
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;
/*-------------------------------------------------------------------------
*
* 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 $
*
*-------------------------------------------------------------------------
*/
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
Oid targetTypeId, int32 atttypmod)
{
- Node *result = NULL;
+ Node *result;
if (targetTypeId == InvalidOid ||
targetTypeId == 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))
{
/*
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
{
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
case T_Param:
case T_Aggref:
case T_ArrayRef:
+ case T_RelabelType:
{
result = (Node *) expr;
break;
case T_Param:
type = ((Param *) expr)->paramtype;
break;
+ case T_RelabelType:
+ type = ((RelabelType *) expr)->resulttype;
+ break;
case T_SubLink:
{
SubLink *sublink = (SubLink *) expr;
}
}
break;
+ case T_RelabelType:
+ return ((RelabelType *) expr)->resulttypmod;
+ break;
default:
break;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
} /* 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)
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)
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;
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() */
/*
* 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)
{
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;
}
}
* 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
* 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
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,
* 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.
*
appendStringInfo(buf, "%s",
quote_identifier(strVal(lfirst(col))));
}
- appendStringInfo(buf, ")");
+ appendStringInfoChar(buf, ')');
}
}
}
sep = ", ";
get_tle_expr(tle, context);
}
- appendStringInfo(buf, ")");
+ appendStringInfoChar(buf, ')');
}
else
get_select_query_def(query, context);
switch (expr->opType)
{
case OP_EXPR:
- appendStringInfo(buf, "(");
+ appendStringInfoChar(buf, '(');
if (length(args) == 2)
{
/* binary operator */
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:
appendStringInfo(buf, "*");
else
get_rule_expr(aggref->target, context);
- appendStringInfo(buf, ")");
+ appendStringInfoChar(buf, ')');
}
break;
}
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;
{
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;
sep = ", ";
get_rule_expr((Node *) lfirst(l), context);
}
- appendStringInfo(buf, ")");
+ appendStringInfoChar(buf, ')');
}
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)
if (need_paren)
appendStringInfo(buf, ") ");
else
- appendStringInfo(buf, " ");
+ appendStringInfoChar(buf, ' ');
}
need_paren = true;
}
if (need_paren)
- appendStringInfo(buf, "(");
+ appendStringInfoChar(buf, '(');
get_query_def(query, buf, context->rangetables);
if (need_paren)
appendStringInfo(buf, "))");
else
- appendStringInfo(buf, ")");
+ appendStringInfoChar(buf, ')');
}
/* ----------
* 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 $
*
*-------------------------------------------------------------------------
*/
T_Array,
T_ArrayRef,
T_Iter,
+ T_RelabelType,
/*---------------------
* TAGS FOR PLANNER NODES (relation.h)
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */