aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c266
1 files changed, 162 insertions, 104 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 4257b91a8e9..3c14cf1b527 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.232 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -63,8 +63,7 @@ static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
char *relname, int location);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
-static Node *typecast_expression(ParseState *pstate, Node *expr,
- TypeName *typename);
+static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
List *largs, List *rargs, int location);
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -123,7 +122,7 @@ transformExpr(ParseState *pstate, Node *expr)
A_Const *con = (A_Const *) expr;
Value *val = &con->val;
- result = (Node *) make_const(val);
+ result = (Node *) make_const(val, con->location);
break;
}
@@ -145,7 +144,6 @@ transformExpr(ParseState *pstate, Node *expr)
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
- Node *arg;
/*
* If the subject of the typecast is an ARRAY[] construct
@@ -179,8 +177,7 @@ transformExpr(ParseState *pstate, Node *expr)
*/
}
- arg = transformExpr(pstate, tc->arg);
- result = typecast_expression(pstate, arg, tc->typename);
+ result = transformTypeCast(pstate, tc);
break;
}
@@ -425,6 +422,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
strcmp(name, "value") == 0)
{
node = (Node *) copyObject(pstate->p_value_substitute);
+
+ /*
+ * Try to propagate location knowledge. This should
+ * be extended if p_value_substitute can ever take on
+ * other node types.
+ */
+ if (IsA(node, CoerceToDomainValue))
+ ((CoerceToDomainValue *) node)->location = cref->location;
break;
}
@@ -631,6 +636,7 @@ transformParamRef(ParseState *pstate, ParamRef *pref)
param->paramid = paramno;
param->paramtype = *pptype;
param->paramtypmod = -1;
+ param->location = pref->location;
return (Node *) param;
}
@@ -691,6 +697,7 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
s->subLinkType = ROWCOMPARE_SUBLINK;
s->testexpr = lexpr;
s->operName = a->name;
+ s->location = a->location;
result = transformExpr(pstate, (Node *) s);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
@@ -734,7 +741,8 @@ transformAExprAnd(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "AND");
return (Node *) makeBoolExpr(AND_EXPR,
- list_make2(lexpr, rexpr));
+ list_make2(lexpr, rexpr),
+ a->location);
}
static Node *
@@ -747,7 +755,8 @@ transformAExprOr(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "OR");
return (Node *) makeBoolExpr(OR_EXPR,
- list_make2(lexpr, rexpr));
+ list_make2(lexpr, rexpr),
+ a->location);
}
static Node *
@@ -758,7 +767,8 @@ transformAExprNot(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
return (Node *) makeBoolExpr(NOT_EXPR,
- list_make1(rexpr));
+ list_make1(rexpr),
+ a->location);
}
static Node *
@@ -849,6 +859,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
* in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate, a->lexpr);
+ Const *result;
ListCell *telem;
Oid ltype,
rtype;
@@ -870,7 +881,12 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
if (strcmp(strVal(linitial(a->name)), "<>") == 0)
matched = (!matched);
- return makeBoolConst(matched, false);
+ result = (Const *) makeBoolConst(matched, false);
+
+ /* Make the result have the original input's parse location */
+ result->location = exprLocation((Node *) a);
+
+ return (Node *) result;
}
static Node *
@@ -878,7 +894,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
{
Node *lexpr;
List *rexprs;
- List *typeids;
bool useOr;
bool haveRowExpr;
Node *result;
@@ -903,7 +918,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
*/
lexpr = transformExpr(pstate, a->lexpr);
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
- typeids = list_make1_oid(exprType(lexpr));
rexprs = NIL;
foreach(l, (List *) a->rexpr)
{
@@ -911,7 +925,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
rexprs = lappend(rexprs, rexpr);
- typeids = lappend_oid(typeids, exprType(rexpr));
}
/*
@@ -922,6 +935,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
*/
if (!haveRowExpr && list_length(rexprs) != 1)
{
+ List *allexprs;
Oid scalar_type;
Oid array_type;
@@ -929,8 +943,11 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
* Select a common type for the array elements. Note that since the
* LHS' type is first in the list, it will be preferred when there is
* doubt (eg, when all the RHS items are unknown literals).
+ *
+ * Note: use list_concat here not lcons, to avoid damaging rexprs.
*/
- scalar_type = select_common_type(typeids, "IN");
+ allexprs = list_concat(list_make1(lexpr), rexprs);
+ scalar_type = select_common_type(pstate, allexprs, "IN", NULL);
/* Do we have an array type to use? */
array_type = get_array_type(scalar_type);
@@ -958,6 +975,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
newa->element_typeid = scalar_type;
newa->elements = aexprs;
newa->multidims = false;
+ newa->location = -1;
return (Node *) make_scalar_array_op(pstate,
a->name,
@@ -1003,7 +1021,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
result = cmp;
else
result = (Node *) makeBoolExpr(useOr ? OR_EXPR : AND_EXPR,
- list_make2(result, cmp));
+ list_make2(result, cmp),
+ a->location);
}
return result;
@@ -1041,7 +1060,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
Node *arg;
CaseTestExpr *placeholder;
List *newargs;
- List *typeids;
+ List *resultexprs;
ListCell *l;
Node *defresult;
Oid ptype;
@@ -1079,7 +1098,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
/* transform the list of arguments */
newargs = NIL;
- typeids = NIL;
+ resultexprs = NIL;
foreach(l, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
@@ -1095,7 +1114,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
warg,
- -1);
+ w->location);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
@@ -1105,9 +1124,10 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
warg = (Node *) w->result;
neww->result = (Expr *) transformExpr(pstate, warg);
+ neww->location = w->location;
newargs = lappend(newargs, neww);
- typeids = lappend_oid(typeids, exprType((Node *) neww->result));
+ resultexprs = lappend(resultexprs, neww->result);
}
newc->args = newargs;
@@ -1119,6 +1139,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
+ n->location = -1;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
@@ -1128,9 +1149,9 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
* determining preferred type. This is how the code worked before, but it
* seems a little bogus to me --- tgl
*/
- typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
+ resultexprs = lcons(newc->defresult, resultexprs);
- ptype = select_common_type(typeids, "CASE");
+ ptype = select_common_type(pstate, resultexprs, "CASE", NULL);
Assert(OidIsValid(ptype));
newc->casetype = ptype;
@@ -1153,6 +1174,8 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
"CASE/WHEN");
}
+ newc->location = c->location;
+
return (Node *) newc;
}
@@ -1196,13 +1219,15 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return a column")));
+ errmsg("subquery must return a column"),
+ parser_errposition(pstate, sublink->location)));
while ((tlist_item = lnext(tlist_item)) != NULL)
{
if (!((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return only one column")));
+ errmsg("subquery must return only one column"),
+ parser_errposition(pstate, sublink->location)));
}
/*
@@ -1247,6 +1272,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
param->paramid = tent->resno;
param->paramtype = exprType((Node *) tent->expr);
param->paramtypmod = exprTypmod((Node *) tent->expr);
+ param->location = -1;
right_list = lappend(right_list, param);
}
@@ -1259,11 +1285,13 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
if (list_length(left_list) < list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too many columns")));
+ errmsg("subquery has too many columns"),
+ parser_errposition(pstate, sublink->location)));
if (list_length(left_list) > list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too few columns")));
+ errmsg("subquery has too few columns"),
+ parser_errposition(pstate, sublink->location)));
/*
* Identify the combining operator(s) and generate a suitable
@@ -1273,7 +1301,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
sublink->operName,
left_list,
right_list,
- -1);
+ sublink->location);
}
return result;
@@ -1293,7 +1321,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
- List *typeids = NIL;
ListCell *element;
Oid coerce_type;
bool coerce_hard;
@@ -1309,7 +1336,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
{
Node *e = (Node *) lfirst(element);
Node *newe;
- Oid newe_type;
/*
* If an element is itself an A_ArrayExpr, recurse directly so that
@@ -1322,25 +1348,22 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
array_type,
element_type,
typmod);
- newe_type = exprType(newe);
/* we certainly have an array here */
- Assert(array_type == InvalidOid || array_type == newe_type);
+ Assert(array_type == InvalidOid || array_type == exprType(newe));
newa->multidims = true;
}
else
{
newe = transformExpr(pstate, e);
- newe_type = exprType(newe);
/*
* Check for sub-array expressions, if we haven't already
* found one.
*/
- if (!newa->multidims && type_is_array(newe_type))
+ if (!newa->multidims && type_is_array(exprType(newe)))
newa->multidims = true;
}
newelems = lappend(newelems, newe);
- typeids = lappend_oid(typeids, newe_type);
}
/*
@@ -1359,15 +1382,16 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
else
{
/* Can't handle an empty array without a target type */
- if (typeids == NIL)
+ if (newelems == NIL)
ereport(ERROR,
(errcode(ERRCODE_INDETERMINATE_DATATYPE),
errmsg("cannot determine type of empty array"),
errhint("Explicitly cast to the desired type, "
- "for example ARRAY[]::integer[].")));
+ "for example ARRAY[]::integer[]."),
+ parser_errposition(pstate, a->location)));
/* Select a common type for the elements */
- coerce_type = select_common_type(typeids, "ARRAY");
+ coerce_type = select_common_type(pstate, newelems, "ARRAY", NULL);
if (newa->multidims)
{
@@ -1414,13 +1438,15 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
coerce_type,
typmod,
COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST);
+ COERCE_EXPLICIT_CAST,
+ -1);
if (newe == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(exprType(e)),
- format_type_be(coerce_type))));
+ format_type_be(coerce_type)),
+ parser_errposition(pstate, exprLocation(e))));
}
else
newe = coerce_to_common_type(pstate, e,
@@ -1432,6 +1458,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
+ newa->location = a->location;
return (Node *) newa;
}
@@ -1447,6 +1474,7 @@ transformRowExpr(ParseState *pstate, RowExpr *r)
/* Barring later casting, we consider the type RECORD */
newr->row_typeid = RECORDOID;
newr->row_format = COERCE_IMPLICIT_CAST;
+ newr->location = r->location;
return (Node *) newr;
}
@@ -1457,7 +1485,6 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
CoalesceExpr *newc = makeNode(CoalesceExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
- List *typeids = NIL;
ListCell *args;
foreach(args, c->args)
@@ -1467,10 +1494,9 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
- typeids = lappend_oid(typeids, exprType(newe));
}
- newc->coalescetype = select_common_type(typeids, "COALESCE");
+ newc->coalescetype = select_common_type(pstate, newargs, "COALESCE", NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
@@ -1485,6 +1511,7 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
}
newc->args = newcoercedargs;
+ newc->location = c->location;
return (Node *) newc;
}
@@ -1494,7 +1521,7 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
MinMaxExpr *newm = makeNode(MinMaxExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
- List *typeids = NIL;
+ const char *funcname = (m->op == IS_GREATEST) ? "GREATEST" : "LEAST";
ListCell *args;
newm->op = m->op;
@@ -1505,10 +1532,9 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
- typeids = lappend_oid(typeids, exprType(newe));
}
- newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST");
+ newm->minmaxtype = select_common_type(pstate, newargs, funcname, NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
@@ -1518,11 +1544,12 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
newe = coerce_to_common_type(pstate, e,
newm->minmaxtype,
- "GREATEST/LEAST");
+ funcname);
newcoercedargs = lappend(newcoercedargs, newe);
}
newm->args = newcoercedargs;
+ newm->location = m->location;
return (Node *) newm;
}
@@ -1538,6 +1565,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newx->name = map_sql_identifier_to_xml_name(x->name, false, false);
else
newx->name = NULL;
+ newx->xmloption = x->xmloption;
+ newx->location = x->location;
/*
* gram.y built the named args as a list of ResTarget. Transform each,
@@ -1566,31 +1595,30 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
x->op == IS_XMLELEMENT
- ? errmsg("unnamed XML attribute value must be a column reference")
- : errmsg("unnamed XML element value must be a column reference")));
+ ? errmsg("unnamed XML attribute value must be a column reference")
+ : errmsg("unnamed XML element value must be a column reference"),
+ parser_errposition(pstate, r->location)));
argname = NULL; /* keep compiler quiet */
}
- newx->named_args = lappend(newx->named_args, expr);
- newx->arg_names = lappend(newx->arg_names, makeString(argname));
- }
-
- newx->xmloption = x->xmloption;
-
- if (x->op == IS_XMLELEMENT)
- {
- foreach(lc, newx->arg_names)
+ /* reject duplicate argnames in XMLELEMENT only */
+ if (x->op == IS_XMLELEMENT)
{
ListCell *lc2;
- for_each_cell(lc2, lnext(lc))
+ foreach(lc2, newx->arg_names)
{
- if (strcmp(strVal(lfirst(lc)), strVal(lfirst(lc2))) == 0)
+ if (strcmp(argname, strVal(lfirst(lc2))) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("XML attribute name \"%s\" appears more than once", strVal(lfirst(lc)))));
+ errmsg("XML attribute name \"%s\" appears more than once",
+ argname),
+ parser_errposition(pstate, r->location)));
}
}
+
+ newx->named_args = lappend(newx->named_args, expr);
+ newx->arg_names = lappend(newx->arg_names, makeString(argname));
}
/* The other arguments are of varying types depending on the function */
@@ -1639,6 +1667,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
break;
case IS_XMLSERIALIZE:
/* not handled here */
+ Assert(false);
break;
case IS_DOCUMENT:
newe = coerce_to_specific_type(pstate, newe, XMLOID,
@@ -1655,9 +1684,10 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
static Node *
transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
{
+ Node *result;
+ XmlExpr *xexpr;
Oid targetType;
int32 targetTypmod;
- XmlExpr *xexpr;
xexpr = makeNode(XmlExpr);
xexpr->op = IS_XMLSERIALIZE;
@@ -1669,6 +1699,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
targetType = typenameTypeId(pstate, xs->typename, &targetTypmod);
xexpr->xmloption = xs->xmloption;
+ xexpr->location = xs->location;
/* We actually only need these to be able to parse back the expression. */
xexpr->type = targetType;
xexpr->typmod = targetTypmod;
@@ -1679,8 +1710,18 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
* from text. This way, user-defined text-like data types automatically
* fit in.
*/
- return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ result = coerce_to_target_type(pstate, (Node *) xexpr,
+ TEXTOID, targetType, targetTypmod,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (result == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_CANNOT_COERCE),
+ errmsg("cannot cast XMLSERIALIZE result to %s",
+ format_type_be(targetType)),
+ parser_errposition(pstate, xexpr->location)));
+ return result;
}
static Node *
@@ -1773,7 +1814,7 @@ static Node *
transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
int location)
{
- Node *result;
+ Var *result;
RangeTblEntry *rte;
int vnum;
int sublevels_up;
@@ -1800,22 +1841,22 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
if (!OidIsValid(toid))
elog(ERROR, "could not find type OID for relation %u",
rte->relid);
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
break;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
if (type_is_rowtype(toid))
{
/* func returns composite; same as relation case */
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
}
else
{
@@ -1825,21 +1866,21 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
* seems a tad inconsistent, especially if "f.*" was
* explicitly written ...)
*/
- result = (Node *) makeVar(vnum,
- 1,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ 1,
+ toid,
+ -1,
+ sublevels_up);
}
break;
case RTE_VALUES:
toid = RECORDOID;
/* returns composite; same as relation case */
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
break;
default:
@@ -1849,48 +1890,64 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
* expanded to a RowExpr during planning, but that is not our
* concern here.)
*/
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- RECORDOID,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ RECORDOID,
+ -1,
+ sublevels_up);
break;
}
- return result;
+ /* location is not filled in by makeVar */
+ result->location = location;
+
+ return (Node *) result;
}
/*
* Handle an explicit CAST construct.
*
- * The given expr has already been transformed, but we need to lookup
- * the type name and then apply any necessary coercion function(s).
+ * Transform the argument, then look up the type name and apply any necessary
+ * coercion function(s).
*/
static Node *
-typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
+transformTypeCast(ParseState *pstate, TypeCast *tc)
{
+ Node *result;
+ Node *expr = transformExpr(pstate, tc->arg);
Oid inputType = exprType(expr);
Oid targetType;
int32 targetTypmod;
+ int location;
- targetType = typenameTypeId(pstate, typename, &targetTypmod);
+ targetType = typenameTypeId(pstate, tc->typename, &targetTypmod);
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
- expr = coerce_to_target_type(pstate, expr, inputType,
- targetType, targetTypmod,
- COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST);
- if (expr == NULL)
+ /*
+ * Location of the coercion is preferentially the location of the :: or
+ * CAST symbol, but if there is none then use the location of the type
+ * name (this can happen in TypeName 'string' syntax, for instance).
+ */
+ location = tc->location;
+ if (location < 0)
+ location = tc->typename->location;
+
+ result = coerce_to_target_type(pstate, expr, inputType,
+ targetType, targetTypmod,
+ COERCION_EXPLICIT,
+ COERCE_EXPLICIT_CAST,
+ location);
+ if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(inputType),
format_type_be(targetType)),
- parser_errposition(pstate, typename->location)));
+ parser_coercion_errposition(pstate, location, expr)));
- return expr;
+ return result;
}
/*
@@ -2043,9 +2100,9 @@ make_row_comparison_op(ParseState *pstate, List *opname,
* the system thinks BoolExpr is N-argument anyway.
*/
if (rctype == ROWCOMPARE_EQ)
- return (Node *) makeBoolExpr(AND_EXPR, opexprs);
+ return (Node *) makeBoolExpr(AND_EXPR, opexprs, location);
if (rctype == ROWCOMPARE_NE)
- return (Node *) makeBoolExpr(OR_EXPR, opexprs);
+ return (Node *) makeBoolExpr(OR_EXPR, opexprs, location);
/*
* Otherwise we need to choose exactly which opfamily to associate with
@@ -2138,7 +2195,8 @@ make_row_distinct_op(ParseState *pstate, List *opname,
result = cmp;
else
result = (Node *) makeBoolExpr(OR_EXPR,
- list_make2(result, cmp));
+ list_make2(result, cmp),
+ location);
}
if (result == NULL)