aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/heap.c5
-rw-r--r--src/backend/commands/prepare.c5
-rw-r--r--src/backend/commands/tablecmds.c11
-rw-r--r--src/backend/commands/typecmds.c3
-rw-r--r--src/backend/nodes/copyfuncs.c47
-rw-r--r--src/backend/nodes/equalfuncs.c56
-rw-r--r--src/backend/nodes/makefuncs.c11
-rw-r--r--src/backend/nodes/nodeFuncs.c312
-rw-r--r--src/backend/nodes/outfuncs.c46
-rw-r--r--src/backend/nodes/readfuncs.c39
-rw-r--r--src/backend/optimizer/plan/createplan.c3
-rw-r--r--src/backend/optimizer/plan/subselect.c5
-rw-r--r--src/backend/optimizer/prep/prepqual.c4
-rw-r--r--src/backend/optimizer/prep/preptlist.c3
-rw-r--r--src/backend/optimizer/prep/prepunion.c5
-rw-r--r--src/backend/optimizer/util/clauses.c17
-rw-r--r--src/backend/optimizer/util/var.c3
-rw-r--r--src/backend/parser/analyze.c169
-rw-r--r--src/backend/parser/gram.y300
-rw-r--r--src/backend/parser/parse_agg.c5
-rw-r--r--src/backend/parser/parse_clause.c28
-rw-r--r--src/backend/parser/parse_coerce.c235
-rw-r--r--src/backend/parser/parse_expr.c266
-rw-r--r--src/backend/parser/parse_func.c10
-rw-r--r--src/backend/parser/parse_node.c43
-rw-r--r--src/backend/parser/parse_oper.c4
-rw-r--r--src/backend/parser/parse_relation.c6
-rw-r--r--src/backend/parser/parse_target.c13
-rw-r--r--src/backend/parser/parse_utilcmd.c4
-rw-r--r--src/backend/rewrite/rewriteHandler.c7
-rw-r--r--src/backend/rewrite/rewriteManip.c4
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/nodes/makefuncs.h4
-rw-r--r--src/include/nodes/nodeFuncs.h4
-rw-r--r--src/include/nodes/parsenodes.h22
-rw-r--r--src/include/nodes/primnodes.h42
-rw-r--r--src/include/parser/parse_coerce.h17
-rw-r--r--src/include/parser/parse_node.h7
-rw-r--r--src/test/regress/expected/arrays.out2
-rw-r--r--src/test/regress/expected/select_implicit.out2
-rw-r--r--src/test/regress/expected/select_implicit_1.out2
-rw-r--r--src/test/regress/expected/select_implicit_2.out2
-rw-r--r--src/test/regress/expected/xml.out6
-rw-r--r--src/test/regress/expected/xml_1.out2
44 files changed, 1289 insertions, 496 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 499929ef102..5b26b91b697 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.338 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.339 2008/08/28 23:09:45 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -2121,7 +2121,8 @@ cookDefault(ParseState *pstate,
expr = coerce_to_target_type(pstate, expr, type_id,
atttypid, atttypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 2fca3a5e813..dee994c5509 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.90 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.91 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -353,7 +353,8 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
expr = coerce_to_target_type(pstate, expr, given_type_id,
expected_type_id, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a8ae2e4be12..6f2303f62ce 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.263 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.264 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3649,7 +3649,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeOid,
typmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (defval == NULL) /* should not happen */
elog(ERROR, "failed to coerce base type to domain");
}
@@ -5509,7 +5510,8 @@ ATPrepAlterColumnType(List **wqueue,
transform, exprType(transform),
targettype, targettypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (transform == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -5607,7 +5609,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
defaultexpr, exprType(defaultexpr),
targettype, targettypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (defaultexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index ee30d32704a..c0dc74bee79 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.122 2008/07/31 16:27:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.123 2008/08/28 23:09:45 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -2135,6 +2135,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
domVal = makeNode(CoerceToDomainValue);
domVal->typeId = baseTypeOid;
domVal->typeMod = typMod;
+ domVal->location = -1; /* will be set when/if used */
pstate->p_value_substitute = (Node *) domVal;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 4a30a3d8228..4e984719d3d 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.401 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.402 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -58,6 +58,10 @@
memcpy(newnode->fldname, from->fldname, _size); \
} while (0)
+/* Copy a parse location field (for Copy, this is same as scalar case) */
+#define COPY_LOCATION_FIELD(fldname) \
+ (newnode->fldname = from->fldname)
+
/* ****************************************************************
* plannodes.h copy functions
@@ -761,6 +765,7 @@ _copyVar(Var *from)
COPY_SCALAR_FIELD(varlevelsup);
COPY_SCALAR_FIELD(varnoold);
COPY_SCALAR_FIELD(varoattno);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -797,6 +802,7 @@ _copyConst(Const *from)
COPY_SCALAR_FIELD(constisnull);
COPY_SCALAR_FIELD(constbyval);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -813,6 +819,7 @@ _copyParam(Param *from)
COPY_SCALAR_FIELD(paramid);
COPY_SCALAR_FIELD(paramtype);
COPY_SCALAR_FIELD(paramtypmod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -831,6 +838,7 @@ _copyAggref(Aggref *from)
COPY_SCALAR_FIELD(agglevelsup);
COPY_SCALAR_FIELD(aggstar);
COPY_SCALAR_FIELD(aggdistinct);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -867,6 +875,7 @@ _copyFuncExpr(FuncExpr *from)
COPY_SCALAR_FIELD(funcretset);
COPY_SCALAR_FIELD(funcformat);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -884,6 +893,7 @@ _copyOpExpr(OpExpr *from)
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -901,6 +911,7 @@ _copyDistinctExpr(DistinctExpr *from)
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -917,6 +928,7 @@ _copyScalarArrayOpExpr(ScalarArrayOpExpr *from)
COPY_SCALAR_FIELD(opfuncid);
COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -931,6 +943,7 @@ _copyBoolExpr(BoolExpr *from)
COPY_SCALAR_FIELD(boolop);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -947,6 +960,7 @@ _copySubLink(SubLink *from)
COPY_NODE_FIELD(testexpr);
COPY_NODE_FIELD(operName);
COPY_NODE_FIELD(subselect);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1032,6 +1046,7 @@ _copyRelabelType(RelabelType *from)
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(relabelformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1047,6 +1062,7 @@ _copyCoerceViaIO(CoerceViaIO *from)
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(coerceformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1065,6 +1081,7 @@ _copyArrayCoerceExpr(ArrayCoerceExpr *from)
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(isExplicit);
COPY_SCALAR_FIELD(coerceformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1080,6 +1097,7 @@ _copyConvertRowtypeExpr(ConvertRowtypeExpr *from)
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(convertformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1096,6 +1114,7 @@ _copyCaseExpr(CaseExpr *from)
COPY_NODE_FIELD(arg);
COPY_NODE_FIELD(args);
COPY_NODE_FIELD(defresult);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1110,6 +1129,7 @@ _copyCaseWhen(CaseWhen *from)
COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(result);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1140,6 +1160,7 @@ _copyArrayExpr(ArrayExpr *from)
COPY_SCALAR_FIELD(element_typeid);
COPY_NODE_FIELD(elements);
COPY_SCALAR_FIELD(multidims);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1155,6 +1176,7 @@ _copyRowExpr(RowExpr *from)
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(row_typeid);
COPY_SCALAR_FIELD(row_format);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1186,6 +1208,7 @@ _copyCoalesceExpr(CoalesceExpr *from)
COPY_SCALAR_FIELD(coalescetype);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1201,6 +1224,7 @@ _copyMinMaxExpr(MinMaxExpr *from)
COPY_SCALAR_FIELD(minmaxtype);
COPY_SCALAR_FIELD(op);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1221,6 +1245,7 @@ _copyXmlExpr(XmlExpr *from)
COPY_SCALAR_FIELD(xmloption);
COPY_SCALAR_FIELD(type);
COPY_SCALAR_FIELD(typmod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1238,6 +1263,7 @@ _copyNullIfExpr(NullIfExpr *from)
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1282,6 +1308,7 @@ _copyCoerceToDomain(CoerceToDomain *from)
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(coercionformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1296,6 +1323,7 @@ _copyCoerceToDomainValue(CoerceToDomainValue *from)
COPY_SCALAR_FIELD(typeId);
COPY_SCALAR_FIELD(typeMod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1310,6 +1338,7 @@ _copySetToDefault(SetToDefault *from)
COPY_SCALAR_FIELD(typeId);
COPY_SCALAR_FIELD(typeMod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1595,7 +1624,7 @@ _copyAExpr(A_Expr *from)
COPY_NODE_FIELD(name);
COPY_NODE_FIELD(lexpr);
COPY_NODE_FIELD(rexpr);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1606,7 +1635,7 @@ _copyColumnRef(ColumnRef *from)
ColumnRef *newnode = makeNode(ColumnRef);
COPY_NODE_FIELD(fields);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1617,6 +1646,7 @@ _copyParamRef(ParamRef *from)
ParamRef *newnode = makeNode(ParamRef);
COPY_SCALAR_FIELD(number);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1647,6 +1677,8 @@ _copyAConst(A_Const *from)
break;
}
+ COPY_LOCATION_FIELD(location);
+
return newnode;
}
@@ -1660,7 +1692,7 @@ _copyFuncCall(FuncCall *from)
COPY_SCALAR_FIELD(agg_star);
COPY_SCALAR_FIELD(agg_distinct);
COPY_SCALAR_FIELD(func_variadic);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1693,6 +1725,7 @@ _copyA_ArrayExpr(A_ArrayExpr *from)
A_ArrayExpr *newnode = makeNode(A_ArrayExpr);
COPY_NODE_FIELD(elements);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1705,7 +1738,7 @@ _copyResTarget(ResTarget *from)
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(indirection);
COPY_NODE_FIELD(val);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1722,7 +1755,7 @@ _copyTypeName(TypeName *from)
COPY_NODE_FIELD(typmods);
COPY_SCALAR_FIELD(typemod);
COPY_NODE_FIELD(arrayBounds);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1770,6 +1803,7 @@ _copyTypeCast(TypeCast *from)
COPY_NODE_FIELD(arg);
COPY_NODE_FIELD(typename);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
@@ -1852,6 +1886,7 @@ _copyXmlSerialize(XmlSerialize *from)
COPY_SCALAR_FIELD(xmloption);
COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(typename);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3a25111c60c..3d130c9524a 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -13,12 +13,16 @@
* Currently, in fact, equal() doesn't know how to compare Plan trees
* either. This might need to be fixed someday.
*
+ * NOTE: it is intentional that parse location fields (in nodes that have
+ * one) are not compared. This is because we want, for example, a variable
+ * "x" to be considered equal() to another reference to "x" in the query.
+ *
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.328 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.329 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -75,6 +79,10 @@
return false; \
} while (0)
+/* Compare a parse location field (this is a no-op, per note above) */
+#define COMPARE_LOCATION_FIELD(fldname) \
+ ((void) 0)
+
/*
* Stuff from primnodes.h
@@ -131,6 +139,7 @@ _equalVar(Var *a, Var *b)
COMPARE_SCALAR_FIELD(varlevelsup);
COMPARE_SCALAR_FIELD(varnoold);
COMPARE_SCALAR_FIELD(varoattno);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -143,6 +152,7 @@ _equalConst(Const *a, Const *b)
COMPARE_SCALAR_FIELD(constlen);
COMPARE_SCALAR_FIELD(constisnull);
COMPARE_SCALAR_FIELD(constbyval);
+ COMPARE_LOCATION_FIELD(location);
/*
* We treat all NULL constants of the same type as equal. Someday this
@@ -161,6 +171,7 @@ _equalParam(Param *a, Param *b)
COMPARE_SCALAR_FIELD(paramid);
COMPARE_SCALAR_FIELD(paramtype);
COMPARE_SCALAR_FIELD(paramtypmod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -174,6 +185,7 @@ _equalAggref(Aggref *a, Aggref *b)
COMPARE_SCALAR_FIELD(agglevelsup);
COMPARE_SCALAR_FIELD(aggstar);
COMPARE_SCALAR_FIELD(aggdistinct);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -209,6 +221,7 @@ _equalFuncExpr(FuncExpr *a, FuncExpr *b)
return false;
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -232,6 +245,7 @@ _equalOpExpr(OpExpr *a, OpExpr *b)
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -255,6 +269,7 @@ _equalDistinctExpr(DistinctExpr *a, DistinctExpr *b)
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -277,6 +292,7 @@ _equalScalarArrayOpExpr(ScalarArrayOpExpr *a, ScalarArrayOpExpr *b)
COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -286,6 +302,7 @@ _equalBoolExpr(BoolExpr *a, BoolExpr *b)
{
COMPARE_SCALAR_FIELD(boolop);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -297,6 +314,7 @@ _equalSubLink(SubLink *a, SubLink *b)
COMPARE_NODE_FIELD(testexpr);
COMPARE_NODE_FIELD(operName);
COMPARE_NODE_FIELD(subselect);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -366,6 +384,8 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
b->relabelformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -384,6 +404,8 @@ _equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b)
b->coerceformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -405,6 +427,8 @@ _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
b->coerceformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -423,6 +447,8 @@ _equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b)
b->convertformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -433,6 +459,7 @@ _equalCaseExpr(CaseExpr *a, CaseExpr *b)
COMPARE_NODE_FIELD(arg);
COMPARE_NODE_FIELD(args);
COMPARE_NODE_FIELD(defresult);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -442,6 +469,7 @@ _equalCaseWhen(CaseWhen *a, CaseWhen *b)
{
COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(result);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -462,6 +490,7 @@ _equalArrayExpr(ArrayExpr *a, ArrayExpr *b)
COMPARE_SCALAR_FIELD(element_typeid);
COMPARE_NODE_FIELD(elements);
COMPARE_SCALAR_FIELD(multidims);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -481,6 +510,8 @@ _equalRowExpr(RowExpr *a, RowExpr *b)
b->row_format != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -501,6 +532,7 @@ _equalCoalesceExpr(CoalesceExpr *a, CoalesceExpr *b)
{
COMPARE_SCALAR_FIELD(coalescetype);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -511,6 +543,7 @@ _equalMinMaxExpr(MinMaxExpr *a, MinMaxExpr *b)
COMPARE_SCALAR_FIELD(minmaxtype);
COMPARE_SCALAR_FIELD(op);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -526,6 +559,7 @@ _equalXmlExpr(XmlExpr *a, XmlExpr *b)
COMPARE_SCALAR_FIELD(xmloption);
COMPARE_SCALAR_FIELD(type);
COMPARE_SCALAR_FIELD(typmod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -549,6 +583,7 @@ _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -587,6 +622,8 @@ _equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
b->coercionformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
@@ -595,6 +632,7 @@ _equalCoerceToDomainValue(CoerceToDomainValue *a, CoerceToDomainValue *b)
{
COMPARE_SCALAR_FIELD(typeId);
COMPARE_SCALAR_FIELD(typeMod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -604,6 +642,7 @@ _equalSetToDefault(SetToDefault *a, SetToDefault *b)
{
COMPARE_SCALAR_FIELD(typeId);
COMPARE_SCALAR_FIELD(typeMod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1680,7 +1719,7 @@ _equalAExpr(A_Expr *a, A_Expr *b)
COMPARE_NODE_FIELD(name);
COMPARE_NODE_FIELD(lexpr);
COMPARE_NODE_FIELD(rexpr);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1689,7 +1728,7 @@ static bool
_equalColumnRef(ColumnRef *a, ColumnRef *b)
{
COMPARE_NODE_FIELD(fields);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1698,6 +1737,7 @@ static bool
_equalParamRef(ParamRef *a, ParamRef *b)
{
COMPARE_SCALAR_FIELD(number);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1707,6 +1747,7 @@ _equalAConst(A_Const *a, A_Const *b)
{
if (!equal(&a->val, &b->val)) /* hack for in-line Value field */
return false;
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1719,7 +1760,7 @@ _equalFuncCall(FuncCall *a, FuncCall *b)
COMPARE_SCALAR_FIELD(agg_star);
COMPARE_SCALAR_FIELD(agg_distinct);
COMPARE_SCALAR_FIELD(func_variadic);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1746,6 +1787,7 @@ static bool
_equalA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b)
{
COMPARE_NODE_FIELD(elements);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1756,7 +1798,7 @@ _equalResTarget(ResTarget *a, ResTarget *b)
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(indirection);
COMPARE_NODE_FIELD(val);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1771,7 +1813,7 @@ _equalTypeName(TypeName *a, TypeName *b)
COMPARE_NODE_FIELD(typmods);
COMPARE_SCALAR_FIELD(typemod);
COMPARE_NODE_FIELD(arrayBounds);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1781,6 +1823,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
{
COMPARE_NODE_FIELD(arg);
COMPARE_NODE_FIELD(typename);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
@@ -1941,6 +1984,7 @@ _equalXmlSerialize(XmlSerialize *a, XmlSerialize *b)
COMPARE_SCALAR_FIELD(xmloption);
COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(typename);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 228bf5ea915..5ab853c37bf 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.58 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.59 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -84,6 +84,9 @@ makeVar(Index varno,
var->varnoold = varno;
var->varoattno = varattno;
+ /* Likewise, we just set location to "unknown" here */
+ var->location = -1;
+
return var;
}
@@ -168,6 +171,7 @@ makeConst(Oid consttype,
cnst->constvalue = constvalue;
cnst->constisnull = constisnull;
cnst->constbyval = constbyval;
+ cnst->location = -1; /* "unknown" */
return cnst;
}
@@ -211,12 +215,13 @@ makeBoolConst(bool value, bool isnull)
* creates a BoolExpr node
*/
Expr *
-makeBoolExpr(BoolExprType boolop, List *args)
+makeBoolExpr(BoolExprType boolop, List *args, int location)
{
BoolExpr *b = makeNode(BoolExpr);
b->boolop = boolop;
b->args = args;
+ b->location = location;
return (Expr *) b;
}
@@ -251,6 +256,7 @@ makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
r->resulttype = rtype;
r->resulttypmod = rtypmod;
r->relabelformat = rformat;
+ r->location = -1;
return r;
}
@@ -336,6 +342,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
funcexpr->funcretset = false; /* only allowed case here */
funcexpr->funcformat = fformat;
funcexpr->args = args;
+ funcexpr->location = -1;
return funcexpr;
}
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 7944936ba6e..fa1bb347b90 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.30 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.31 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,6 +23,7 @@
static bool expression_returns_set_walker(Node *node, void *context);
+static int leftmostLoc(int loc1, int loc2);
/*
@@ -575,6 +576,315 @@ expression_returns_set_walker(Node *node, void *context)
/*
+ * exprLocation -
+ * returns the parse location of an expression tree, for error reports
+ *
+ * -1 is returned if the location can't be determined.
+ *
+ * For expressions larger than a single token, the intent here is to
+ * return the location of the expression's leftmost token, not necessarily
+ * the topmost Node's location field. For example, an OpExpr's location
+ * field will point at the operator name, but if it is not a prefix operator
+ * then we should return the location of the left-hand operand instead.
+ * The reason is that we want to reference the entire expression not just
+ * that operator, and pointing to its start seems to be the most natural way.
+ *
+ * The location is not perfect --- for example, since the grammar doesn't
+ * explicitly represent parentheses in the parsetree, given something that
+ * had been written "(a + b) * c" we are going to point at "a" not "(".
+ * But it should be plenty good enough for error reporting purposes.
+ *
+ * You might think that this code is overly general, for instance why check
+ * the operands of a FuncExpr node, when the function name can be expected
+ * to be to the left of them? There are a couple of reasons. The grammar
+ * sometimes builds expressions that aren't quite what the user wrote;
+ * for instance x IS NOT BETWEEN ... becomes a NOT-expression whose keyword
+ * pointer is to the right of its leftmost argument. Also, nodes that were
+ * inserted implicitly by parse analysis (such as FuncExprs for implicit
+ * coercions) will have location -1, and so we can have odd combinations of
+ * known and unknown locations in a tree.
+ */
+int
+exprLocation(Node *expr)
+{
+ int loc;
+
+ if (expr == NULL)
+ return -1;
+ switch (nodeTag(expr))
+ {
+ case T_Var:
+ loc = ((Var *) expr)->location;
+ break;
+ case T_Const:
+ loc = ((Const *) expr)->location;
+ break;
+ case T_Param:
+ loc = ((Param *) expr)->location;
+ break;
+ case T_Aggref:
+ /* function name should always be the first thing */
+ loc = ((Aggref *) expr)->location;
+ break;
+ case T_ArrayRef:
+ /* just use array argument's location */
+ loc = exprLocation((Node *) ((ArrayRef *) expr)->refexpr);
+ break;
+ case T_FuncExpr:
+ {
+ FuncExpr *fexpr = (FuncExpr *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(fexpr->location,
+ exprLocation((Node *) fexpr->args));
+ }
+ break;
+ case T_OpExpr:
+ case T_DistinctExpr: /* struct-equivalent to OpExpr */
+ case T_NullIfExpr: /* struct-equivalent to OpExpr */
+ {
+ OpExpr *opexpr = (OpExpr *) expr;
+
+ /* consider both operator name and leftmost arg */
+ loc = leftmostLoc(opexpr->location,
+ exprLocation((Node *) opexpr->args));
+ }
+ break;
+ case T_ScalarArrayOpExpr:
+ {
+ ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) expr;
+
+ /* consider both operator name and leftmost arg */
+ loc = leftmostLoc(saopexpr->location,
+ exprLocation((Node *) saopexpr->args));
+ }
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *bexpr = (BoolExpr *) expr;
+
+ /*
+ * Same as above, to handle either NOT or AND/OR. We can't
+ * special-case NOT because of the way that it's used for
+ * things like IS NOT BETWEEN.
+ */
+ loc = leftmostLoc(bexpr->location,
+ exprLocation((Node *) bexpr->args));
+ }
+ break;
+ case T_SubLink:
+ {
+ SubLink *sublink = (SubLink *) expr;
+
+ /* check the testexpr, if any, and the operator/keyword */
+ loc = leftmostLoc(exprLocation(sublink->testexpr),
+ sublink->location);
+ }
+ break;
+ case T_FieldSelect:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((FieldSelect *) expr)->arg);
+ break;
+ case T_FieldStore:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((FieldStore *) expr)->arg);
+ break;
+ case T_RelabelType:
+ {
+ RelabelType *rexpr = (RelabelType *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(rexpr->location,
+ exprLocation((Node *) rexpr->arg));
+ }
+ break;
+ case T_CoerceViaIO:
+ {
+ CoerceViaIO *cexpr = (CoerceViaIO *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *cexpr = (ArrayCoerceExpr *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_ConvertRowtypeExpr:
+ {
+ ConvertRowtypeExpr *cexpr = (ConvertRowtypeExpr *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_CaseExpr:
+ /* CASE keyword should always be the first thing */
+ loc = ((CaseExpr *) expr)->location;
+ break;
+ case T_CaseWhen:
+ /* WHEN keyword should always be the first thing */
+ loc = ((CaseWhen *) expr)->location;
+ break;
+ case T_ArrayExpr:
+ /* the location points at ARRAY or [, which must be leftmost */
+ loc = ((ArrayExpr *) expr)->location;
+ break;
+ case T_RowExpr:
+ /* the location points at ROW or (, which must be leftmost */
+ loc = ((RowExpr *) expr)->location;
+ break;
+ case T_RowCompareExpr:
+ /* just use leftmost argument's location */
+ loc = exprLocation((Node *) ((RowCompareExpr *) expr)->largs);
+ break;
+ case T_CoalesceExpr:
+ /* COALESCE keyword should always be the first thing */
+ loc = ((CoalesceExpr *) expr)->location;
+ break;
+ case T_MinMaxExpr:
+ /* GREATEST/LEAST keyword should always be the first thing */
+ loc = ((MinMaxExpr *) expr)->location;
+ break;
+ case T_XmlExpr:
+ {
+ XmlExpr *xexpr = (XmlExpr *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(xexpr->location,
+ exprLocation((Node *) xexpr->args));
+ }
+ break;
+ case T_NullTest:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((NullTest *) expr)->arg);
+ break;
+ case T_BooleanTest:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((BooleanTest *) expr)->arg);
+ break;
+ case T_CoerceToDomain:
+ {
+ CoerceToDomain *cexpr = (CoerceToDomain *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_CoerceToDomainValue:
+ loc = ((CoerceToDomainValue *) expr)->location;
+ break;
+ case T_SetToDefault:
+ loc = ((SetToDefault *) expr)->location;
+ break;
+ case T_TargetEntry:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((TargetEntry *) expr)->expr);
+ break;
+ case T_List:
+ {
+ /* report location of first list member that has a location */
+ ListCell *lc;
+
+ loc = -1; /* just to suppress compiler warning */
+ foreach(lc, (List *) expr)
+ {
+ loc = exprLocation((Node *) lfirst(lc));
+ if (loc >= 0)
+ break;
+ }
+ }
+ break;
+ case T_A_Expr:
+ {
+ A_Expr *aexpr = (A_Expr *) expr;
+
+ /* use leftmost of operator or left operand (if any) */
+ /* we assume right operand can't be to left of operator */
+ loc = leftmostLoc(aexpr->location,
+ exprLocation(aexpr->lexpr));
+ }
+ break;
+ case T_ColumnRef:
+ loc = ((ColumnRef *) expr)->location;
+ break;
+ case T_ParamRef:
+ loc = ((ParamRef *) expr)->location;
+ break;
+ case T_A_Const:
+ loc = ((A_Const *) expr)->location;
+ break;
+ case T_FuncCall:
+ {
+ FuncCall *fc = (FuncCall *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(fc->location,
+ exprLocation((Node *) fc->args));
+ }
+ break;
+ case T_A_ArrayExpr:
+ /* the location points at ARRAY or [, which must be leftmost */
+ loc = ((A_ArrayExpr *) expr)->location;
+ break;
+ case T_ResTarget:
+ /* we need not examine the contained expression (if any) */
+ loc = ((ResTarget *) expr)->location;
+ break;
+ case T_TypeCast:
+ {
+ TypeCast *tc = (TypeCast *) expr;
+
+ /*
+ * This could represent CAST(), ::, or TypeName 'literal',
+ * so any of the components might be leftmost.
+ */
+ loc = exprLocation(tc->arg);
+ loc = leftmostLoc(loc, tc->typename->location);
+ loc = leftmostLoc(loc, tc->location);
+ }
+ break;
+ case T_TypeName:
+ loc = ((TypeName *) expr)->location;
+ break;
+ case T_XmlSerialize:
+ /* XMLSERIALIZE keyword should always be the first thing */
+ loc = ((XmlSerialize *) expr)->location;
+ break;
+ default:
+ /* for any other node type it's just unknown... */
+ loc = -1;
+ break;
+ }
+ return loc;
+}
+
+/*
+ * leftmostLoc - support for exprLocation
+ *
+ * Take the minimum of two parse location values, but ignore unknowns
+ */
+static int
+leftmostLoc(int loc1, int loc2)
+{
+ if (loc1 < 0)
+ return loc2;
+ else if (loc2 < 0)
+ return loc1;
+ else
+ return Min(loc1, loc2);
+}
+
+
+/*
* Standard expression-tree walking support
*
* We used to have near-duplicate code in many different routines that
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 76f8da1babe..91fa30ae232 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.335 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.336 2008/08/28 23:09:46 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -79,6 +79,10 @@
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))
+/* Write a parse location field (actually same as INT case) */
+#define WRITE_LOCATION_FIELD(fldname) \
+ appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
+
/* Write a Node field */
#define WRITE_NODE_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
@@ -689,6 +693,7 @@ _outVar(StringInfo str, Var *node)
WRITE_UINT_FIELD(varlevelsup);
WRITE_UINT_FIELD(varnoold);
WRITE_INT_FIELD(varoattno);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -701,6 +706,7 @@ _outConst(StringInfo str, Const *node)
WRITE_INT_FIELD(constlen);
WRITE_BOOL_FIELD(constbyval);
WRITE_BOOL_FIELD(constisnull);
+ WRITE_LOCATION_FIELD(location);
appendStringInfo(str, " :constvalue ");
if (node->constisnull)
@@ -718,6 +724,7 @@ _outParam(StringInfo str, Param *node)
WRITE_INT_FIELD(paramid);
WRITE_OID_FIELD(paramtype);
WRITE_INT_FIELD(paramtypmod);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -731,6 +738,7 @@ _outAggref(StringInfo str, Aggref *node)
WRITE_UINT_FIELD(agglevelsup);
WRITE_BOOL_FIELD(aggstar);
WRITE_BOOL_FIELD(aggdistinct);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -757,6 +765,7 @@ _outFuncExpr(StringInfo str, FuncExpr *node)
WRITE_BOOL_FIELD(funcretset);
WRITE_ENUM_FIELD(funcformat, CoercionForm);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -769,6 +778,7 @@ _outOpExpr(StringInfo str, OpExpr *node)
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -781,6 +791,7 @@ _outDistinctExpr(StringInfo str, DistinctExpr *node)
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -792,6 +803,7 @@ _outScalarArrayOpExpr(StringInfo str, ScalarArrayOpExpr *node)
WRITE_OID_FIELD(opfuncid);
WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -818,6 +830,7 @@ _outBoolExpr(StringInfo str, BoolExpr *node)
_outToken(str, opstr);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -829,6 +842,7 @@ _outSubLink(StringInfo str, SubLink *node)
WRITE_NODE_FIELD(testexpr);
WRITE_NODE_FIELD(operName);
WRITE_NODE_FIELD(subselect);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -889,6 +903,7 @@ _outRelabelType(StringInfo str, RelabelType *node)
WRITE_OID_FIELD(resulttype);
WRITE_INT_FIELD(resulttypmod);
WRITE_ENUM_FIELD(relabelformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -899,6 +914,7 @@ _outCoerceViaIO(StringInfo str, CoerceViaIO *node)
WRITE_NODE_FIELD(arg);
WRITE_OID_FIELD(resulttype);
WRITE_ENUM_FIELD(coerceformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -912,6 +928,7 @@ _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node)
WRITE_INT_FIELD(resulttypmod);
WRITE_BOOL_FIELD(isExplicit);
WRITE_ENUM_FIELD(coerceformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -922,6 +939,7 @@ _outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node)
WRITE_NODE_FIELD(arg);
WRITE_OID_FIELD(resulttype);
WRITE_ENUM_FIELD(convertformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -933,6 +951,7 @@ _outCaseExpr(StringInfo str, CaseExpr *node)
WRITE_NODE_FIELD(arg);
WRITE_NODE_FIELD(args);
WRITE_NODE_FIELD(defresult);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -942,6 +961,7 @@ _outCaseWhen(StringInfo str, CaseWhen *node)
WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(result);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -962,6 +982,7 @@ _outArrayExpr(StringInfo str, ArrayExpr *node)
WRITE_OID_FIELD(element_typeid);
WRITE_NODE_FIELD(elements);
WRITE_BOOL_FIELD(multidims);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -972,6 +993,7 @@ _outRowExpr(StringInfo str, RowExpr *node)
WRITE_NODE_FIELD(args);
WRITE_OID_FIELD(row_typeid);
WRITE_ENUM_FIELD(row_format, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -993,6 +1015,7 @@ _outCoalesceExpr(StringInfo str, CoalesceExpr *node)
WRITE_OID_FIELD(coalescetype);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1003,6 +1026,7 @@ _outMinMaxExpr(StringInfo str, MinMaxExpr *node)
WRITE_OID_FIELD(minmaxtype);
WRITE_ENUM_FIELD(op, MinMaxOp);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1018,6 +1042,7 @@ _outXmlExpr(StringInfo str, XmlExpr *node)
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
WRITE_OID_FIELD(type);
WRITE_INT_FIELD(typmod);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1030,6 +1055,7 @@ _outNullIfExpr(StringInfo str, NullIfExpr *node)
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1059,6 +1085,7 @@ _outCoerceToDomain(StringInfo str, CoerceToDomain *node)
WRITE_OID_FIELD(resulttype);
WRITE_INT_FIELD(resulttypmod);
WRITE_ENUM_FIELD(coercionformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1068,6 +1095,7 @@ _outCoerceToDomainValue(StringInfo str, CoerceToDomainValue *node)
WRITE_OID_FIELD(typeId);
WRITE_INT_FIELD(typeMod);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1077,6 +1105,7 @@ _outSetToDefault(StringInfo str, SetToDefault *node)
WRITE_OID_FIELD(typeId);
WRITE_INT_FIELD(typeMod);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1626,7 +1655,7 @@ _outFuncCall(StringInfo str, FuncCall *node)
WRITE_BOOL_FIELD(agg_star);
WRITE_BOOL_FIELD(agg_distinct);
WRITE_BOOL_FIELD(func_variadic);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1656,6 +1685,7 @@ _outXmlSerialize(StringInfo str, XmlSerialize *node)
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(typename);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1685,7 +1715,7 @@ _outTypeName(StringInfo str, TypeName *node)
WRITE_NODE_FIELD(typmods);
WRITE_INT_FIELD(typemod);
WRITE_NODE_FIELD(arrayBounds);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1695,6 +1725,7 @@ _outTypeCast(StringInfo str, TypeCast *node)
WRITE_NODE_FIELD(arg);
WRITE_NODE_FIELD(typename);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1892,7 +1923,7 @@ _outAExpr(StringInfo str, A_Expr *node)
WRITE_NODE_FIELD(lexpr);
WRITE_NODE_FIELD(rexpr);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1936,7 +1967,7 @@ _outColumnRef(StringInfo str, ColumnRef *node)
WRITE_NODE_TYPE("COLUMNREF");
WRITE_NODE_FIELD(fields);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1945,6 +1976,7 @@ _outParamRef(StringInfo str, ParamRef *node)
WRITE_NODE_TYPE("PARAMREF");
WRITE_INT_FIELD(number);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1954,6 +1986,7 @@ _outAConst(StringInfo str, A_Const *node)
appendStringInfo(str, " :val ");
_outValue(str, &(node->val));
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1980,6 +2013,7 @@ _outA_ArrayExpr(StringInfo str, A_ArrayExpr *node)
WRITE_NODE_TYPE("A_ARRAYEXPR");
WRITE_NODE_FIELD(elements);
+ WRITE_LOCATION_FIELD(location);
}
static void
@@ -1990,7 +2024,7 @@ _outResTarget(StringInfo str, ResTarget *node)
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(indirection);
WRITE_NODE_FIELD(val);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index c46593d22c7..ee363502f69 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.212 2008/08/07 01:11:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.213 2008/08/28 23:09:46 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -16,6 +16,12 @@
* claimed to read them, but it was broken as well as unused.) We
* never read executor state trees, either.
*
+ * Parse location fields are written out by outfuncs.c, but only for
+ * possible debugging use. When reading a location field, we discard
+ * the stored value and set the location field to -1 (ie, "unknown").
+ * This is because nodes coming from a stored rule should not be thought
+ * to have a known location in the current query's text.
+ *
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -97,6 +103,12 @@
token = pg_strtok(&length); /* get field value */ \
local_node->fldname = nullable_string(token, length)
+/* Read a parse location field (and throw away the value, per notes above) */
+#define READ_LOCATION_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = -1 /* set field to "unknown" */
+
/* Read a Node field */
#define READ_NODE_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \
@@ -299,6 +311,7 @@ _readVar(void)
READ_UINT_FIELD(varlevelsup);
READ_UINT_FIELD(varnoold);
READ_INT_FIELD(varoattno);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -316,6 +329,7 @@ _readConst(void)
READ_INT_FIELD(constlen);
READ_BOOL_FIELD(constbyval);
READ_BOOL_FIELD(constisnull);
+ READ_LOCATION_FIELD(location);
token = pg_strtok(&length); /* skip :constvalue */
if (local_node->constisnull)
@@ -338,6 +352,7 @@ _readParam(void)
READ_INT_FIELD(paramid);
READ_OID_FIELD(paramtype);
READ_INT_FIELD(paramtypmod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -356,6 +371,7 @@ _readAggref(void)
READ_UINT_FIELD(agglevelsup);
READ_BOOL_FIELD(aggstar);
READ_BOOL_FIELD(aggdistinct);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -392,6 +408,7 @@ _readFuncExpr(void)
READ_BOOL_FIELD(funcretset);
READ_ENUM_FIELD(funcformat, CoercionForm);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -420,6 +437,7 @@ _readOpExpr(void)
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -448,6 +466,7 @@ _readDistinctExpr(void)
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -475,6 +494,7 @@ _readScalarArrayOpExpr(void)
READ_BOOL_FIELD(useOr);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -500,6 +520,7 @@ _readBoolExpr(void)
elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -516,6 +537,7 @@ _readSubLink(void)
READ_NODE_FIELD(testexpr);
READ_NODE_FIELD(operName);
READ_NODE_FIELD(subselect);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -568,6 +590,7 @@ _readRelabelType(void)
READ_OID_FIELD(resulttype);
READ_INT_FIELD(resulttypmod);
READ_ENUM_FIELD(relabelformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -583,6 +606,7 @@ _readCoerceViaIO(void)
READ_NODE_FIELD(arg);
READ_OID_FIELD(resulttype);
READ_ENUM_FIELD(coerceformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -601,6 +625,7 @@ _readArrayCoerceExpr(void)
READ_INT_FIELD(resulttypmod);
READ_BOOL_FIELD(isExplicit);
READ_ENUM_FIELD(coerceformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -616,6 +641,7 @@ _readConvertRowtypeExpr(void)
READ_NODE_FIELD(arg);
READ_OID_FIELD(resulttype);
READ_ENUM_FIELD(convertformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -632,6 +658,7 @@ _readCaseExpr(void)
READ_NODE_FIELD(arg);
READ_NODE_FIELD(args);
READ_NODE_FIELD(defresult);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -646,6 +673,7 @@ _readCaseWhen(void)
READ_NODE_FIELD(expr);
READ_NODE_FIELD(result);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -676,6 +704,7 @@ _readArrayExpr(void)
READ_OID_FIELD(element_typeid);
READ_NODE_FIELD(elements);
READ_BOOL_FIELD(multidims);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -691,6 +720,7 @@ _readRowExpr(void)
READ_NODE_FIELD(args);
READ_OID_FIELD(row_typeid);
READ_ENUM_FIELD(row_format, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -722,6 +752,7 @@ _readCoalesceExpr(void)
READ_OID_FIELD(coalescetype);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -737,6 +768,7 @@ _readMinMaxExpr(void)
READ_OID_FIELD(minmaxtype);
READ_ENUM_FIELD(op, MinMaxOp);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -757,6 +789,7 @@ _readXmlExpr(void)
READ_ENUM_FIELD(xmloption, XmlOptionType);
READ_OID_FIELD(type);
READ_INT_FIELD(typmod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -785,6 +818,7 @@ _readNullIfExpr(void)
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -829,6 +863,7 @@ _readCoerceToDomain(void)
READ_OID_FIELD(resulttype);
READ_INT_FIELD(resulttypmod);
READ_ENUM_FIELD(coercionformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -843,6 +878,7 @@ _readCoerceToDomainValue(void)
READ_OID_FIELD(typeId);
READ_INT_FIELD(typeMod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
@@ -857,6 +893,7 @@ _readSetToDefault(void)
READ_OID_FIELD(typeId);
READ_INT_FIELD(typeMod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index a0ca92bd73d..1a79c96dba4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.246 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.247 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1949,6 +1949,7 @@ get_switched_clauses(List *clauses, Relids outerrelids)
temp->opresulttype = clause->opresulttype;
temp->opretset = clause->opretset;
temp->args = list_copy(clause->args);
+ temp->location = clause->location;
/* Commute it --- note this modifies the temp node in-place. */
CommuteOpExpr(temp);
t_list = lappend(t_list, temp);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 42ac74e1a25..fe8be5b1bbb 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.139 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.140 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -140,6 +140,7 @@ replace_outer_var(PlannerInfo *root, Var *var)
retval->paramid = i;
retval->paramtype = var->vartype;
retval->paramtypmod = var->vartypmod;
+ retval->location = -1;
return retval;
}
@@ -179,6 +180,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg)
retval->paramid = i;
retval->paramtype = agg->aggtype;
retval->paramtypmod = -1;
+ retval->location = -1;
return retval;
}
@@ -199,6 +201,7 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
retval->paramid = list_length(root->glob->paramlist);
retval->paramtype = paramtype;
retval->paramtypmod = paramtypmod;
+ retval->location = -1;
pitem = makeNode(PlannerParamItem);
pitem->item = (Node *) retval;
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index f7a54056591..c87bb00381e 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -25,7 +25,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.58 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.59 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -219,6 +219,7 @@ push_nots(Expr *qual)
newopexpr->opresulttype = opexpr->opresulttype;
newopexpr->opretset = opexpr->opretset;
newopexpr->args = opexpr->args;
+ newopexpr->location = opexpr->location;
return (Expr *) newopexpr;
}
else
@@ -243,6 +244,7 @@ push_nots(Expr *qual)
newopexpr->opfuncid = InvalidOid;
newopexpr->useOr = !saopexpr->useOr;
newopexpr->args = saopexpr->args;
+ newopexpr->location = saopexpr->location;
return (Expr *) newopexpr;
}
else
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index de0218748d5..08b70c8ee58 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -16,7 +16,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.90 2008/06/19 00:46:04 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.91 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -292,6 +292,7 @@ expand_targetlist(List *tlist, int command_type,
InvalidOid, -1,
atttype,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index c07ca4434a3..7dc274797e5 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.154 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.155 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1410,6 +1410,7 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
r->arg = (Expr *) var;
r->resulttype = context->parent_reltype;
r->convertformat = COERCE_IMPLICIT_CAST;
+ r->location = -1;
/* Make sure the Var node has the right type ID, too */
var->vartype = context->child_reltype;
return (Node *) r;
@@ -1428,6 +1429,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
+
return (Node *) rowexpr;
}
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 55bafa2c969..254b86e0d96 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.265 2008/08/26 02:16:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.266 2008/08/28 23:09:46 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -135,6 +135,7 @@ make_opclause(Oid opno, Oid opresulttype, bool opretset,
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
+ expr->location = -1;
return (Expr *) expr;
}
@@ -201,6 +202,7 @@ make_notclause(Expr *notclause)
expr->boolop = NOT_EXPR;
expr->args = list_make1(notclause);
+ expr->location = -1;
return (Expr *) expr;
}
@@ -244,6 +246,7 @@ make_orclause(List *orclauses)
expr->boolop = OR_EXPR;
expr->args = orclauses;
+ expr->location = -1;
return (Expr *) expr;
}
@@ -277,6 +280,7 @@ make_andclause(List *andclauses)
expr->boolop = AND_EXPR;
expr->args = andclauses;
+ expr->location = -1;
return (Expr *) expr;
}
@@ -2014,6 +2018,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, OpExpr))
@@ -2071,6 +2076,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, DistinctExpr))
@@ -2162,6 +2168,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, BoolExpr))
@@ -2291,6 +2298,7 @@ eval_const_expressions_mutator(Node *node,
newrelabel->resulttype = relabel->resulttype;
newrelabel->resulttypmod = relabel->resulttypmod;
newrelabel->relabelformat = relabel->relabelformat;
+ newrelabel->location = relabel->location;
return (Node *) newrelabel;
}
}
@@ -2357,6 +2365,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->arg = arg;
newexpr->resulttype = expr->resulttype;
newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, ArrayCoerceExpr))
@@ -2379,6 +2388,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->resulttypmod = expr->resulttypmod;
newexpr->isExplicit = expr->isExplicit;
newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
/*
* If constant argument and it's a binary-coercible or immutable
@@ -2477,6 +2487,7 @@ eval_const_expressions_mutator(Node *node,
newcasewhen->expr = (Expr *) casecond;
newcasewhen->result = (Expr *) caseresult;
+ newcasewhen->location = oldcasewhen->location;
newargs = lappend(newargs, newcasewhen);
continue;
}
@@ -2506,6 +2517,7 @@ eval_const_expressions_mutator(Node *node,
newcase->arg = (Expr *) newarg;
newcase->args = newargs;
newcase->defresult = (Expr *) defresult;
+ newcase->location = caseexpr->location;
return (Node *) newcase;
}
if (IsA(node, CaseTestExpr))
@@ -2545,6 +2557,7 @@ eval_const_expressions_mutator(Node *node,
newarray->element_typeid = arrayexpr->element_typeid;
newarray->elements = newelems;
newarray->multidims = arrayexpr->multidims;
+ newarray->location = arrayexpr->location;
if (all_const)
return (Node *) evaluate_expr((Expr *) newarray,
@@ -2590,6 +2603,7 @@ eval_const_expressions_mutator(Node *node,
newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype;
newcoalesce->args = newargs;
+ newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
if (IsA(node, FieldSelect))
@@ -3206,6 +3220,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
newexpr->funcretset = false;
newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */
newexpr->args = args;
+ newexpr->location = -1;
return evaluate_expr((Expr *) newexpr, result_type, result_typmod);
}
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 85f34e49427..e9fd15e6f3f 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.77 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.78 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -624,6 +624,7 @@ flatten_join_alias_vars_mutator(Node *node,
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
return (Node *) rowexpr;
}
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 2086c3321f0..b513d61c071 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -17,7 +17,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.377 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.378 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,9 +53,8 @@ static List *transformInsertRow(ParseState *pstate, List *exprlist,
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
-static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
-static void getSetColTypes(ParseState *pstate, Node *node,
- List **colTypes, List **colTypmods);
+static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
+ List **colInfo);
static void applyColumnNames(List *dst, List *src);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
static List *transformReturningList(ParseState *pstate, List *returningList);
@@ -789,7 +788,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
{
Query *qry = makeNode(Query);
List *exprsLists = NIL;
- List **coltype_lists = NULL;
+ List **colexprs = NULL;
Oid *coltypes = NULL;
int sublist_length = -1;
List *newExprsLists;
@@ -831,8 +830,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
{
/* Remember post-transformation length of first sublist */
sublist_length = list_length(sublist);
- /* and allocate arrays for column-type info */
- coltype_lists = (List **) palloc0(sublist_length * sizeof(List *));
+ /* and allocate arrays for per-column info */
+ colexprs = (List **) palloc0(sublist_length * sizeof(List *));
coltypes = (Oid *) palloc0(sublist_length * sizeof(Oid));
}
else if (sublist_length != list_length(sublist))
@@ -844,6 +843,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
exprsLists = lappend(exprsLists, sublist);
+ /* Check for DEFAULT and build per-column expression lists */
i = 0;
foreach(lc2, sublist)
{
@@ -852,8 +852,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
if (IsA(col, SetToDefault))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("DEFAULT can only appear in a VALUES list within INSERT")));
- coltype_lists[i] = lappend_oid(coltype_lists[i], exprType(col));
+ errmsg("DEFAULT can only appear in a VALUES list within INSERT"),
+ parser_errposition(pstate, exprLocation(col))));
+ colexprs[i] = lappend(colexprs[i], col);
i++;
}
}
@@ -864,7 +865,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
*/
for (i = 0; i < sublist_length; i++)
{
- coltypes[i] = select_common_type(coltype_lists[i], "VALUES");
+ coltypes[i] = select_common_type(pstate, colexprs[i], "VALUES", NULL);
}
newExprsLists = NIL;
@@ -985,6 +986,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
int leftmostRTI;
Query *leftmostQuery;
SetOperationStmt *sostmt;
+ List *socolinfo;
List *intoColNames = NIL;
List *sortClause;
Node *limitOffset;
@@ -1047,7 +1049,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* Recursively transform the components of the tree.
*/
- sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt);
+ sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt,
+ &socolinfo);
Assert(sostmt && IsA(sostmt, SetOperationStmt));
qry->setOperations = (Node *) sostmt;
@@ -1191,9 +1194,17 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* transformSetOperationTree
* Recursively transform leaves and internal nodes of a set-op tree
+ *
+ * In addition to returning the transformed node, we return a list of
+ * expression nodes showing the type, typmod, and location (for error messages)
+ * of each output column of the set-op node. This is used only during the
+ * internal recursion of this function. We use SetToDefault nodes for
+ * this purpose, since they carry exactly the fields needed, but any other
+ * expression node type would do as well.
*/
static Node *
-transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
+transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
+ List **colInfo)
{
bool isLeaf;
@@ -1240,6 +1251,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
char selectName[32];
RangeTblEntry *rte;
RangeTblRef *rtr;
+ ListCell *tl;
/*
* Transform SelectStmt into a Query.
@@ -1265,6 +1277,24 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
}
/*
+ * Extract information about the result columns.
+ */
+ *colInfo = NIL;
+ foreach(tl, selectQuery->targetList)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(tl);
+ SetToDefault *cinfo;
+
+ if (tle->resjunk)
+ continue;
+ cinfo = makeNode(SetToDefault);
+ cinfo->typeId = exprType((Node *) tle->expr);
+ cinfo->typeMod = exprTypmod((Node *) tle->expr);
+ cinfo->location = exprLocation((Node *) tle->expr);
+ *colInfo = lappend(*colInfo, cinfo);
+ }
+
+ /*
* Make the leaf query be a subquery in the top-level rangetable.
*/
snprintf(selectName, sizeof(selectName), "*SELECT* %d",
@@ -1287,14 +1317,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
{
/* Process an internal node (set operation node) */
SetOperationStmt *op = makeNode(SetOperationStmt);
- List *lcoltypes;
- List *rcoltypes;
- List *lcoltypmods;
- List *rcoltypmods;
- ListCell *lct;
- ListCell *rct;
- ListCell *lcm;
- ListCell *rcm;
+ List *lcolinfo;
+ List *rcolinfo;
+ ListCell *lci;
+ ListCell *rci;
const char *context;
context = (stmt->op == SETOP_UNION ? "UNION" :
@@ -1307,46 +1333,66 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
/*
* Recursively transform the child nodes.
*/
- op->larg = transformSetOperationTree(pstate, stmt->larg);
- op->rarg = transformSetOperationTree(pstate, stmt->rarg);
+ op->larg = transformSetOperationTree(pstate, stmt->larg,
+ &lcolinfo);
+ op->rarg = transformSetOperationTree(pstate, stmt->rarg,
+ &rcolinfo);
/*
* Verify that the two children have the same number of non-junk
* columns, and determine the types of the merged output columns.
*/
- getSetColTypes(pstate, op->larg, &lcoltypes, &lcoltypmods);
- getSetColTypes(pstate, op->rarg, &rcoltypes, &rcoltypmods);
- if (list_length(lcoltypes) != list_length(rcoltypes))
+ if (list_length(lcolinfo) != list_length(rcolinfo))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("each %s query must have the same number of columns",
- context)));
- Assert(list_length(lcoltypes) == list_length(lcoltypmods));
- Assert(list_length(rcoltypes) == list_length(rcoltypmods));
+ context),
+ parser_errposition(pstate,
+ exprLocation((Node *) rcolinfo))));
+ *colInfo = NIL;
op->colTypes = NIL;
op->colTypmods = NIL;
op->groupClauses = NIL;
- /* don't have a "foreach4", so chase two of the lists by hand */
- lcm = list_head(lcoltypmods);
- rcm = list_head(rcoltypmods);
- forboth(lct, lcoltypes, rct, rcoltypes)
+ forboth(lci, lcolinfo, rci, rcolinfo)
{
- Oid lcoltype = lfirst_oid(lct);
- Oid rcoltype = lfirst_oid(rct);
- int32 lcoltypmod = lfirst_int(lcm);
- int32 rcoltypmod = lfirst_int(rcm);
+ SetToDefault *lcolinfo = (SetToDefault *) lfirst(lci);
+ SetToDefault *rcolinfo = (SetToDefault *) lfirst(rci);
+ Oid lcoltype = lcolinfo->typeId;
+ Oid rcoltype = rcolinfo->typeId;
+ int32 lcoltypmod = lcolinfo->typeMod;
+ int32 rcoltypmod = rcolinfo->typeMod;
+ Node *bestexpr;
+ SetToDefault *rescolinfo;
Oid rescoltype;
int32 rescoltypmod;
/* select common type, same as CASE et al */
- rescoltype = select_common_type(list_make2_oid(lcoltype, rcoltype),
- context);
+ rescoltype = select_common_type(pstate,
+ list_make2(lcolinfo, rcolinfo),
+ context,
+ &bestexpr);
/* if same type and same typmod, use typmod; else default */
if (lcoltype == rcoltype && lcoltypmod == rcoltypmod)
rescoltypmod = lcoltypmod;
else
rescoltypmod = -1;
+
+ /* verify the coercions are actually possible */
+ if (lcoltype != UNKNOWNOID)
+ (void) coerce_to_common_type(pstate, (Node *) lcolinfo,
+ rescoltype, context);
+ if (rcoltype != UNKNOWNOID)
+ (void) coerce_to_common_type(pstate, (Node *) rcolinfo,
+ rescoltype, context);
+
+ /* emit results */
+ rescolinfo = makeNode(SetToDefault);
+ rescolinfo->typeId = rescoltype;
+ rescolinfo->typeMod = rescoltypmod;
+ rescolinfo->location = ((SetToDefault *) bestexpr)->location;
+ *colInfo = lappend(*colInfo, rescolinfo);
+
op->colTypes = lappend_oid(op->colTypes, rescoltype);
op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
@@ -1374,9 +1420,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
op->groupClauses = lappend(op->groupClauses, grpcl);
}
-
- lcm = lnext(lcm);
- rcm = lnext(rcm);
}
return (Node *) op;
@@ -1384,50 +1427,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
}
/*
- * getSetColTypes
- * Get output column types/typmods of an (already transformed) set-op node
- */
-static void
-getSetColTypes(ParseState *pstate, Node *node,
- List **colTypes, List **colTypmods)
-{
- *colTypes = NIL;
- *colTypmods = NIL;
- if (IsA(node, RangeTblRef))
- {
- RangeTblRef *rtr = (RangeTblRef *) node;
- RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
- Query *selectQuery = rte->subquery;
- ListCell *tl;
-
- Assert(selectQuery != NULL);
- /* Get types of non-junk columns */
- foreach(tl, selectQuery->targetList)
- {
- TargetEntry *tle = (TargetEntry *) lfirst(tl);
-
- if (tle->resjunk)
- continue;
- *colTypes = lappend_oid(*colTypes,
- exprType((Node *) tle->expr));
- *colTypmods = lappend_int(*colTypmods,
- exprTypmod((Node *) tle->expr));
- }
- }
- else if (IsA(node, SetOperationStmt))
- {
- SetOperationStmt *op = (SetOperationStmt *) node;
-
- /* Result already computed during transformation of node */
- Assert(op->colTypes != NIL);
- *colTypes = op->colTypes;
- *colTypmods = op->colTypmods;
- }
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
-}
-
-/*
* Attach column names from a ColumnDef list to a TargetEntry list
* (for CREATE TABLE AS)
*/
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 39e52099f43..e908750f76a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.619 2008/08/28 23:09:47 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -90,15 +90,15 @@ static bool QueryIsRule = FALSE;
/*#define __YYSCLASS*/
static Node *makeColumnRef(char *relname, List *indirection, int location);
-static Node *makeTypeCast(Node *arg, TypeName *typename);
-static Node *makeStringConst(char *str);
-static Node *makeStringConstCast(char *str, TypeName *typename);
-static Node *makeIntConst(int val);
-static Node *makeFloatConst(char *str);
-static Node *makeBitStringConst(char *str);
-static Node *makeNullAConst(void);
-static Node *makeAConst(Value *v);
-static Node *makeBoolAConst(bool state);
+static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
+static Node *makeStringConst(char *str, int location);
+static Node *makeStringConstCast(char *str, int location, TypeName *typename);
+static Node *makeIntConst(int val, int location);
+static Node *makeFloatConst(char *str, int location);
+static Node *makeBitStringConst(char *str, int location);
+static Node *makeNullAConst(int location);
+static Node *makeAConst(Value *v, int location);
+static Node *makeBoolAConst(bool state, int location);
static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
static void check_qualified_name(List *names);
static List *check_func_name(List *names);
@@ -110,8 +110,9 @@ static void insertSelectOptions(SelectStmt *stmt,
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
-static Node *makeAArrayExpr(List *elements);
-static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
+static Node *makeAArrayExpr(List *elements, int location);
+static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
+ List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
static TypeName *TableFuncTypeName(List *columns);
@@ -1117,7 +1118,7 @@ set_rest: /* Generic SET syntaxes: */
n->kind = VAR_SET_VALUE;
n->name = "client_encoding";
if ($2 != NULL)
- n->args = list_make1(makeStringConst($2));
+ n->args = list_make1(makeStringConst($2, @2));
else
n->kind = VAR_SET_DEFAULT;
$$ = n;
@@ -1127,7 +1128,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "role";
- n->args = list_make1(makeStringConst($2));
+ n->args = list_make1(makeStringConst($2, @2));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
@@ -1135,7 +1136,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "session_authorization";
- n->args = list_make1(makeStringConst($3));
+ n->args = list_make1(makeStringConst($3, @3));
$$ = n;
}
| SESSION AUTHORIZATION DEFAULT
@@ -1150,7 +1151,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "xmloption";
- n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT"));
+ n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
$$ = n;
}
;
@@ -1168,11 +1169,11 @@ var_list: var_value { $$ = list_make1($1); }
;
var_value: opt_boolean
- { $$ = makeStringConst($1); }
+ { $$ = makeStringConst($1, @1); }
| ColId_or_Sconst
- { $$ = makeStringConst($1); }
+ { $$ = makeStringConst($1, @1); }
| NumericOnly
- { $$ = makeAConst($1); }
+ { $$ = makeAConst($1, @1); }
;
iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; }
@@ -1199,11 +1200,11 @@ opt_boolean:
zone_value:
Sconst
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| IDENT
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| ConstInterval Sconst opt_interval
{
@@ -1214,9 +1215,9 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
- t->typmods = list_make1(makeIntConst($3));
+ t->typmods = list_make1(makeIntConst($3, @3));
}
- $$ = makeStringConstCast($2, t);
+ $$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
@@ -1226,11 +1227,11 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
- t->typmods = list_make2(makeIntConst($6),
- makeIntConst($3));
- $$ = makeStringConstCast($5, t);
+ t->typmods = list_make2(makeIntConst($6, @6),
+ makeIntConst($3, @3));
+ $$ = makeStringConstCast($5, @5, t);
}
- | NumericOnly { $$ = makeAConst($1); }
+ | NumericOnly { $$ = makeAConst($1, @1); }
| DEFAULT { $$ = NULL; }
| LOCAL { $$ = NULL; }
;
@@ -5274,13 +5275,13 @@ opt_transaction: WORK {}
transaction_mode_item:
ISOLATION LEVEL iso_level
{ $$ = makeDefElem("transaction_isolation",
- makeStringConst($3)); }
+ makeStringConst($3, @3)); }
| READ ONLY
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(TRUE)); }
+ makeIntConst(TRUE, @1)); }
| READ WRITE
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(FALSE)); }
+ makeIntConst(FALSE, @1)); }
;
/* Syntax with commas is SQL-spec, without commas is Postgres historical */
@@ -6461,7 +6462,7 @@ select_limit_value:
| ALL
{
/* LIMIT ALL is represented as a NULL constant */
- $$ = makeNullAConst();
+ $$ = makeNullAConst(@1);
}
;
@@ -6963,13 +6964,13 @@ SimpleTypename:
{
$$ = $1;
if ($2 != INTERVAL_FULL_RANGE)
- $$->typmods = list_make1(makeIntConst($2));
+ $$->typmods = list_make1(makeIntConst($2, @2));
}
| ConstInterval '(' Iconst ')' opt_interval
{
$$ = $1;
- $$->typmods = list_make2(makeIntConst($5),
- makeIntConst($3));
+ $$->typmods = list_make2(makeIntConst($5, @5),
+ makeIntConst($3, @3));
}
;
@@ -7155,7 +7156,7 @@ BitWithoutLength:
else
{
$$ = SystemTypeName("bit");
- $$->typmods = list_make1(makeIntConst(1));
+ $$->typmods = list_make1(makeIntConst(1, -1));
}
$$->location = @1;
}
@@ -7207,7 +7208,7 @@ CharacterWithLength: character '(' Iconst ')' opt_charset
}
$$ = SystemTypeName($1);
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
;
@@ -7229,7 +7230,7 @@ CharacterWithoutLength: character opt_charset
/* char defaults to char(1), varchar to no limit */
if (strcmp($1, "bpchar") == 0)
- $$->typmods = list_make1(makeIntConst(1));
+ $$->typmods = list_make1(makeIntConst(1, -1));
$$->location = @1;
}
@@ -7269,7 +7270,7 @@ ConstDatetime:
$$ = SystemTypeName("timestamptz");
else
$$ = SystemTypeName("timestamp");
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIMESTAMP opt_timezone
@@ -7286,7 +7287,7 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIME opt_timezone
@@ -7365,7 +7366,7 @@ opt_interval:
*/
a_expr: c_expr { $$ = $1; }
| a_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3); }
+ { $$ = makeTypeCast($1, $3, @2); }
| a_expr AT TIME ZONE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -7480,7 +7481,7 @@ a_expr: c_expr { $$ = $1; }
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($4, makeNullAConst());
+ n->args = list_make2($4, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
@@ -7502,7 +7503,7 @@ a_expr: c_expr { $$ = $1; }
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($5, makeNullAConst());
+ n->args = list_make2($5, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
@@ -7674,6 +7675,7 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
+ n->location = @2;
$$ = (Node *)n;
}
else
@@ -7693,6 +7695,7 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
+ n->location = @3;
/* Stick a NOT on top */
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
}
@@ -7709,6 +7712,7 @@ a_expr: c_expr { $$ = $1; }
n->testexpr = $1;
n->operName = $2;
n->subselect = $4;
+ n->location = @2;
$$ = (Node *)n;
}
| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
@@ -7735,12 +7739,14 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
}
| a_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
- makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
+ makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
@2);
}
;
@@ -7757,7 +7763,7 @@ a_expr: c_expr { $$ = $1; }
b_expr: c_expr
{ $$ = $1; }
| b_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3); }
+ { $$ = makeTypeCast($1, $3, @2); }
| '+' b_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
@@ -7805,12 +7811,14 @@ b_expr: c_expr
}
| b_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
}
| b_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
- makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
+ makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
@2);
}
;
@@ -7829,6 +7837,7 @@ c_expr: columnref { $$ = $1; }
{
ParamRef *p = makeNode(ParamRef);
p->number = $1;
+ p->location = @1;
if ($2)
{
A_Indirection *n = makeNode(A_Indirection);
@@ -7862,6 +7871,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $1;
+ n->location = @1;
$$ = (Node *)n;
}
| EXISTS select_with_parens
@@ -7871,6 +7881,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
+ n->location = @1;
$$ = (Node *)n;
}
| ARRAY select_with_parens
@@ -7880,15 +7891,23 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
+ n->location = @1;
$$ = (Node *)n;
}
| ARRAY array_expr
- { $$ = $2; }
+ {
+ A_ArrayExpr *n = (A_ArrayExpr *) $2;
+ Assert(IsA(n, A_ArrayExpr));
+ /* point outermost A_ArrayExpr to the ARRAY keyword */
+ n->location = @1;
+ $$ = (Node *)n;
+ }
| row
{
RowExpr *r = makeNode(RowExpr);
r->args = $1;
r->row_typeid = InvalidOid; /* not analyzed yet */
+ r->location = @1;
$$ = (Node *)r;
}
;
@@ -8010,8 +8029,8 @@ func_expr: func_name '(' ')'
* to rely on it.)
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("date"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("date"), -1);
}
| CURRENT_TIME
{
@@ -8020,8 +8039,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timetz"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timetz"), -1);
}
| CURRENT_TIME '(' Iconst ')'
{
@@ -8031,10 +8050,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timetz");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| CURRENT_TIMESTAMP
{
@@ -8059,10 +8078,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamptz");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| LOCALTIME
{
@@ -8071,8 +8090,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast((Node *)n, SystemTypeName("time"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1);
}
| LOCALTIME '(' Iconst ')'
{
@@ -8082,10 +8101,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("time");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast((Node *)n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast((Node *)n, d, -1);
}
| LOCALTIMESTAMP
{
@@ -8094,8 +8113,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timestamp"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timestamp"), -1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
@@ -8105,10 +8124,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamp");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| CURRENT_ROLE
{
@@ -8155,7 +8174,7 @@ func_expr: func_name '(' ')'
$$ = (Node *)n;
}
| CAST '(' a_expr AS Typename ')'
- { $$ = makeTypeCast($3, $5); }
+ { $$ = makeTypeCast($3, $5, @1); }
| EXTRACT '(' extract_list ')'
{
FuncCall *n = makeNode(FuncCall);
@@ -8284,6 +8303,7 @@ func_expr: func_name '(' ')'
{
CoalesceExpr *c = makeNode(CoalesceExpr);
c->args = $3;
+ c->location = @1;
$$ = (Node *)c;
}
| GREATEST '(' expr_list ')'
@@ -8291,6 +8311,7 @@ func_expr: func_name '(' ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_GREATEST;
+ v->location = @1;
$$ = (Node *)v;
}
| LEAST '(' expr_list ')'
@@ -8298,52 +8319,54 @@ func_expr: func_name '(' ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_LEAST;
+ v->location = @1;
$$ = (Node *)v;
}
| XMLCONCAT '(' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
}
| XMLFOREST '(' xml_attribute_list ')'
{
- $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL);
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
- XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
- list_make2($4,
- makeBoolAConst($5)));
+ XmlExpr *x = (XmlExpr *)
+ makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ list_make2($4, makeBoolAConst($5, -1)),
+ @1);
x->xmloption = $3;
$$ = (Node *)x;
}
| XMLPI '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL);
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
}
| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6));
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
- list_make3($3, $5, $6));
+ list_make3($3, $5, $6), @1);
}
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
{
@@ -8351,6 +8374,7 @@ func_expr: func_name '(' ')'
n->xmloption = $3;
n->expr = $4;
n->typename = $6;
+ n->location = @1;
$$ = (Node *)n;
}
;
@@ -8361,17 +8385,17 @@ func_expr: func_name '(' ')'
xml_root_version: VERSION_P a_expr
{ $$ = $2; }
| VERSION_P NO VALUE_P
- { $$ = makeNullAConst(); }
+ { $$ = makeNullAConst(-1); }
;
opt_xml_root_standalone: ',' STANDALONE_P YES_P
- { $$ = makeIntConst(XML_STANDALONE_YES); }
+ { $$ = makeIntConst(XML_STANDALONE_YES, -1); }
| ',' STANDALONE_P NO
- { $$ = makeIntConst(XML_STANDALONE_NO); }
+ { $$ = makeIntConst(XML_STANDALONE_NO, -1); }
| ',' STANDALONE_P NO VALUE_P
- { $$ = makeIntConst(XML_STANDALONE_NO_VALUE); }
+ { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
| /*EMPTY*/
- { $$ = makeIntConst(XML_STANDALONE_OMITTED); }
+ { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
;
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
@@ -8495,15 +8519,15 @@ type_list: Typename { $$ = list_make1($1); }
array_expr: '[' expr_list ']'
{
- $$ = makeAArrayExpr($2);
+ $$ = makeAArrayExpr($2, @1);
}
| '[' array_expr_list ']'
{
- $$ = makeAArrayExpr($2);
+ $$ = makeAArrayExpr($2, @1);
}
| '[' ']'
{
- $$ = makeAArrayExpr(NIL);
+ $$ = makeAArrayExpr(NIL, @1);
}
;
@@ -8515,7 +8539,7 @@ array_expr_list: array_expr { $$ = list_make1($1); }
extract_list:
extract_arg FROM a_expr
{
- $$ = list_make2(makeStringConst($1), $3);
+ $$ = list_make2(makeStringConst($1, @1), $3);
}
| /*EMPTY*/ { $$ = NIL; }
;
@@ -8599,8 +8623,9 @@ substr_list:
* which it is likely to do if the second argument
* is unknown or doesn't have an implicit cast to int4.
*/
- $$ = list_make3($1, makeIntConst(1),
- makeTypeCast($2, SystemTypeName("int4")));
+ $$ = list_make3($1, makeIntConst(1, -1),
+ makeTypeCast($2,
+ SystemTypeName("int4"), -1));
}
| expr_list
{
@@ -8646,6 +8671,7 @@ case_expr: CASE case_arg when_clause_list case_default END_P
c->arg = (Expr *) $2;
c->args = $3;
c->defresult = (Expr *) $4;
+ c->location = @1;
$$ = (Node *)c;
}
;
@@ -8662,6 +8688,7 @@ when_clause:
CaseWhen *w = makeNode(CaseWhen);
w->expr = (Expr *) $2;
w->result = (Expr *) $4;
+ w->location = @1;
$$ = (Node *)w;
}
;
@@ -8738,7 +8765,12 @@ opt_asymmetric: ASYMMETRIC
ctext_expr:
a_expr { $$ = (Node *) $1; }
- | DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
+ | DEFAULT
+ {
+ SetToDefault *n = makeNode(SetToDefault);
+ n->location = @1;
+ $$ = (Node *) n;
+ }
;
ctext_expr_list:
@@ -8911,19 +8943,19 @@ func_name: type_function_name
*/
AexprConst: Iconst
{
- $$ = makeIntConst($1);
+ $$ = makeIntConst($1, @1);
}
| FCONST
{
- $$ = makeFloatConst($1);
+ $$ = makeFloatConst($1, @1);
}
| Sconst
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| BCONST
{
- $$ = makeBitStringConst($1);
+ $$ = makeBitStringConst($1, @1);
}
| XCONST
{
@@ -8932,14 +8964,14 @@ AexprConst: Iconst
* a <general literal> shall not be a
* <bit string literal> or a <hex string literal>.
*/
- $$ = makeBitStringConst($1);
+ $$ = makeBitStringConst($1, @1);
}
| func_name Sconst
{
/* generic type 'literal' syntax */
TypeName *t = makeTypeNameFromNameList($1);
t->location = @1;
- $$ = makeStringConstCast($2, t);
+ $$ = makeStringConstCast($2, @2, t);
}
| func_name '(' expr_list ')' Sconst
{
@@ -8947,38 +8979,38 @@ AexprConst: Iconst
TypeName *t = makeTypeNameFromNameList($1);
t->typmods = $3;
t->location = @1;
- $$ = makeStringConstCast($5, t);
+ $$ = makeStringConstCast($5, @5, t);
}
| ConstTypename Sconst
{
- $$ = makeStringConstCast($2, $1);
+ $$ = makeStringConstCast($2, @2, $1);
}
| ConstInterval Sconst opt_interval
{
TypeName *t = $1;
/* precision is not specified, but fields may be... */
if ($3 != INTERVAL_FULL_RANGE)
- t->typmods = list_make1(makeIntConst($3));
- $$ = makeStringConstCast($2, t);
+ t->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
TypeName *t = $1;
- t->typmods = list_make2(makeIntConst($6),
- makeIntConst($3));
- $$ = makeStringConstCast($5, t);
+ t->typmods = list_make2(makeIntConst($6, @6),
+ makeIntConst($3, @3));
+ $$ = makeStringConstCast($5, @5, t);
}
| TRUE_P
{
- $$ = makeBoolAConst(TRUE);
+ $$ = makeBoolAConst(TRUE, @1);
}
| FALSE_P
{
- $$ = makeBoolAConst(FALSE);
+ $$ = makeBoolAConst(FALSE, @1);
}
| NULL_P
{
- $$ = makeNullAConst();
+ $$ = makeNullAConst(@1);
}
;
@@ -9522,94 +9554,100 @@ makeColumnRef(char *relname, List *indirection, int location)
}
static Node *
-makeTypeCast(Node *arg, TypeName *typename)
+makeTypeCast(Node *arg, TypeName *typename, int location)
{
TypeCast *n = makeNode(TypeCast);
n->arg = arg;
n->typename = typename;
+ n->location = location;
return (Node *) n;
}
static Node *
-makeStringConst(char *str)
+makeStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeStringConstCast(char *str, TypeName *typename)
+makeStringConstCast(char *str, int location, TypeName *typename)
{
- Node *s = makeStringConst(str);
+ Node *s = makeStringConst(str, location);
- return makeTypeCast(s, typename);
+ return makeTypeCast(s, typename, -1);
}
static Node *
-makeIntConst(int val)
+makeIntConst(int val, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = val;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeFloatConst(char *str)
+makeFloatConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Float;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeBitStringConst(char *str)
+makeBitStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_BitString;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeNullAConst(void)
+makeNullAConst(int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeAConst(Value *v)
+makeAConst(Value *v, int location)
{
Node *n;
switch (v->type)
{
case T_Float:
- n = makeFloatConst(v->val.str);
+ n = makeFloatConst(v->val.str, location);
break;
case T_Integer:
- n = makeIntConst(v->val.ival);
+ n = makeIntConst(v->val.ival, location);
break;
case T_String:
default:
- n = makeStringConst(v->val.str);
+ n = makeStringConst(v->val.str, location);
break;
}
@@ -9620,14 +9658,15 @@ makeAConst(Value *v)
* Create an A_Const string node and put it inside a boolean cast.
*/
static Node *
-makeBoolAConst(bool state)
+makeBoolAConst(bool state, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (state ? "t" : "f");
+ n->location = location;
- return makeTypeCast((Node *)n, SystemTypeName("bool"));
+ return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
/* makeOverlaps()
@@ -9799,6 +9838,7 @@ SystemFuncName(char *name)
* Build a properly-qualified reference to a built-in type.
*
* typmod is defaulted, but may be changed afterwards by caller.
+ * Likewise for the location.
*/
TypeName *
SystemTypeName(char *name)
@@ -9827,6 +9867,9 @@ doNegate(Node *n, int location)
{
A_Const *con = (A_Const *)n;
+ /* report the constant's location as that of the '-' sign */
+ con->location = location;
+
if (con->val.type == T_Integer)
{
con->val.val.ival = -con->val.val.ival;
@@ -9863,16 +9906,18 @@ doNegateFloat(Value *v)
}
static Node *
-makeAArrayExpr(List *elements)
+makeAArrayExpr(List *elements, int location)
{
A_ArrayExpr *n = makeNode(A_ArrayExpr);
n->elements = elements;
+ n->location = location;
return (Node *) n;
}
static Node *
-makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
+makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
+ int location)
{
XmlExpr *x = makeNode(XmlExpr);
@@ -9885,6 +9930,9 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
x->named_args = named_args;
x->arg_names = NIL;
x->args = args;
+ /* xmloption, if relevant, must be filled in by caller */
+ /* type and typmod will be filled in during parse analysis */
+ x->location = location;
return (Node *) x;
}
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index b635c3260c9..215557396f9 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.81 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -396,6 +396,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
+ argp->location = -1;
args = list_make1(argp);
@@ -406,6 +407,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_input_types[i];
argp->paramtypmod = -1;
+ argp->location = -1;
args = lappend(args, argp);
}
@@ -429,6 +431,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
+ argp->location = -1;
args = list_make1(argp);
*finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index aa0b9fd09e4..7097ef50582 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.176 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.177 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -964,9 +964,10 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
outcoltypmod = l_colvar->vartypmod;
if (outcoltype != r_colvar->vartype)
{
- outcoltype = select_common_type(list_make2_oid(l_colvar->vartype,
- r_colvar->vartype),
- "JOIN/USING");
+ outcoltype = select_common_type(pstate,
+ list_make2(l_colvar, r_colvar),
+ "JOIN/USING",
+ NULL);
outcoltypmod = -1; /* ie, unknown */
}
else if (outcoltypmod != r_colvar->vartypmod)
@@ -984,7 +985,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (l_colvar->vartype != outcoltype)
l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Expr *) l_colvar,
outcoltype, outcoltypmod,
@@ -995,7 +996,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (r_colvar->vartype != outcoltype)
r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Expr *) r_colvar,
outcoltype, outcoltypmod,
@@ -1038,6 +1039,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
c->coalescetype = outcoltype;
c->args = list_make2(l_node, r_node);
+ c->location = -1;
res_node = (Node *) c;
break;
}
@@ -1239,6 +1241,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
if (IsA(node, A_Const))
{
Value *val = &((A_Const *) node)->val;
+ int location = ((A_Const *) node)->location;
int targetlist_pos = 0;
int target_pos;
@@ -1247,7 +1250,9 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("non-integer constant in %s",
- clauseText[clause])));
+ clauseText[clause]),
+ parser_errposition(pstate, location)));
+
target_pos = intVal(val);
foreach(tl, *tlist)
{
@@ -1263,7 +1268,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("%s position %d is not in select list",
- clauseText[clause], target_pos)));
+ clauseText[clause], target_pos),
+ parser_errposition(pstate, location)));
}
/*
@@ -1590,7 +1596,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
restype = TEXTOID;
}
@@ -1704,7 +1711,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
restype = TEXTOID;
}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 1244498ffb2..cd9b7b0cfbe 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.164 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,18 +32,20 @@
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit,
- bool hideInputCoercion);
+ CoercionForm cformat, int location,
+ bool isExplicit, bool hideInputCoercion);
static void hide_coercion_node(Node *node);
static Node *build_coercion_expression(Node *node,
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit);
+ CoercionForm cformat, int location,
+ bool isExplicit);
static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
- CoercionForm cformat);
+ CoercionForm cformat,
+ int location);
/*
@@ -65,12 +67,14 @@ static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
* targettype - desired result type
* targettypmod - desired result typmod
* ccontext, cformat - context indicators to control coercions
+ * location - parse location of the coercion request, or -1 if unknown/implicit
*/
Node *
coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
- CoercionForm cformat)
+ CoercionForm cformat,
+ int location)
{
Node *result;
@@ -79,7 +83,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
result = coerce_type(pstate, expr, exprtype,
targettype, targettypmod,
- ccontext, cformat);
+ ccontext, cformat, location);
/*
* If the target is a fixed-length type, it may need a length coercion as
@@ -88,7 +92,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
*/
result = coerce_type_typmod(result,
targettype, targettypmod,
- cformat,
+ cformat, location,
(cformat != COERCE_IMPLICIT_CAST),
(result != expr && !IsA(result, Const)));
@@ -118,7 +122,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Node *
coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat)
+ CoercionContext ccontext, CoercionForm cformat, int location)
{
Node *result;
CoercionPathType pathtype;
@@ -195,6 +199,13 @@ coerce_type(ParseState *pstate, Node *node,
newcon->constlen = typeLen(targetType);
newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull;
+ /* Use the leftmost of the constant's and coercion's locations */
+ if (location < 0)
+ newcon->location = con->location;
+ else if (con->location >= 0 && con->location < location)
+ newcon->location = con->location;
+ else
+ newcon->location = location;
/*
* We pass typmod -1 to the input routine, primarily because existing
@@ -219,7 +230,7 @@ coerce_type(ParseState *pstate, Node *node,
result = coerce_to_domain(result,
baseTypeId, baseTypeMod,
targetTypeId,
- cformat, false, false);
+ cformat, location, false, false);
ReleaseSysCache(targetType);
@@ -280,6 +291,11 @@ coerce_type(ParseState *pstate, Node *node,
*/
param->paramtypmod = -1;
+ /* Use the leftmost of the param's and coercion's locations */
+ if (location >= 0 &&
+ (param->location < 0 || location < param->location))
+ param->location = location;
+
return (Node *) param;
}
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
@@ -303,7 +319,7 @@ coerce_type(ParseState *pstate, Node *node,
result = build_coercion_expression(node, pathtype, funcId,
baseTypeId, baseTypeMod,
- cformat,
+ cformat, location,
(cformat != COERCE_IMPLICIT_CAST));
/*
@@ -314,7 +330,7 @@ coerce_type(ParseState *pstate, Node *node,
if (targetTypeId != baseTypeId)
result = coerce_to_domain(result, baseTypeId, baseTypeMod,
targetTypeId,
- cformat, true,
+ cformat, location, true,
exprIsLengthCoercion(result,
NULL));
}
@@ -330,7 +346,7 @@ coerce_type(ParseState *pstate, Node *node,
* then we won't need a RelabelType node.
*/
result = coerce_to_domain(node, InvalidOid, -1, targetTypeId,
- cformat, false, false);
+ cformat, location, false, false);
if (result == node)
{
/*
@@ -339,9 +355,12 @@ coerce_type(ParseState *pstate, Node *node,
* later? Would work if both types have same interpretation of
* typmod, which is likely but not certain.
*/
- result = (Node *) makeRelabelType((Expr *) result,
- targetTypeId, -1,
- cformat);
+ RelabelType *r = makeRelabelType((Expr *) result,
+ targetTypeId, -1,
+ cformat);
+
+ r->location = location;
+ result = (Node *) r;
}
}
return result;
@@ -351,7 +370,7 @@ coerce_type(ParseState *pstate, Node *node,
{
/* Coerce a RECORD to a specific complex type */
return coerce_record_to_complex(pstate, node, targetTypeId,
- ccontext, cformat);
+ ccontext, cformat, location);
}
if (targetTypeId == RECORDOID &&
ISCOMPLEX(inputTypeId))
@@ -372,6 +391,7 @@ coerce_type(ParseState *pstate, Node *node,
r->arg = (Expr *) node;
r->resulttype = targetTypeId;
r->convertformat = cformat;
+ r->location = location;
return (Node *) r;
}
/* If we get here, caller blew it */
@@ -483,6 +503,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
* has not bothered to look this up)
* 'typeId': target type to coerce to
* 'cformat': coercion format
+ * 'location': coercion request location
* 'hideInputCoercion': if true, hide the input coercion under this one.
* 'lengthCoercionDone': if true, caller already accounted for length,
* ie the input is already of baseTypMod as well as baseTypeId.
@@ -491,7 +512,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
*/
Node *
coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
- CoercionForm cformat, bool hideInputCoercion,
+ CoercionForm cformat, int location,
+ bool hideInputCoercion,
bool lengthCoercionDone)
{
CoerceToDomain *result;
@@ -525,7 +547,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
{
if (baseTypeMod >= 0)
arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod,
- COERCE_IMPLICIT_CAST,
+ COERCE_IMPLICIT_CAST, location,
(cformat != COERCE_IMPLICIT_CAST),
false);
}
@@ -540,6 +562,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
result->resulttype = typeId;
result->resulttypmod = -1; /* currently, always -1 for domains */
result->coercionformat = cformat;
+ result->location = location;
return (Node *) result;
}
@@ -568,8 +591,8 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
*/
static Node *
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit,
- bool hideInputCoercion)
+ CoercionForm cformat, int location,
+ bool isExplicit, bool hideInputCoercion)
{
CoercionPathType pathtype;
Oid funcId;
@@ -591,7 +614,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
node = build_coercion_expression(node, pathtype, funcId,
targetTypeId, targetTypMod,
- cformat, isExplicit);
+ cformat, location,
+ isExplicit);
}
return node;
@@ -640,7 +664,8 @@ build_coercion_expression(Node *node,
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit)
+ CoercionForm cformat, int location,
+ bool isExplicit)
{
int nargs = 0;
@@ -677,6 +702,7 @@ build_coercion_expression(Node *node,
if (pathtype == COERCION_PATH_FUNC)
{
/* We build an ordinary FuncExpr with special arguments */
+ FuncExpr *fexpr;
List *args;
Const *cons;
@@ -710,7 +736,9 @@ build_coercion_expression(Node *node,
args = lappend(args, cons);
}
- return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
+ fexpr = makeFuncExpr(funcId, targetTypeId, args, cformat);
+ fexpr->location = location;
+ return (Node *) fexpr;
}
else if (pathtype == COERCION_PATH_ARRAYCOERCE)
{
@@ -729,6 +757,7 @@ build_coercion_expression(Node *node,
acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1;
acoerce->isExplicit = isExplicit;
acoerce->coerceformat = cformat;
+ acoerce->location = location;
return (Node *) acoerce;
}
@@ -742,6 +771,7 @@ build_coercion_expression(Node *node,
iocoerce->arg = (Expr *) node;
iocoerce->resulttype = targetTypeId;
iocoerce->coerceformat = cformat;
+ iocoerce->location = location;
return (Node *) iocoerce;
}
@@ -765,7 +795,8 @@ static Node *
coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
- CoercionForm cformat)
+ CoercionForm cformat,
+ int location)
{
RowExpr *rowexpr;
TupleDesc tupdesc;
@@ -799,7 +830,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
- format_type_be(targetTypeId))));
+ format_type_be(targetTypeId)),
+ parser_coercion_errposition(pstate, location, node)));
tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1);
newargs = NIL;
@@ -808,6 +840,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
for (i = 0; i < tupdesc->natts; i++)
{
Node *expr;
+ Node *cexpr;
Oid exprtype;
/* Fill in NULLs for dropped columns in rowtype */
@@ -827,17 +860,19 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
- errdetail("Input has too few columns.")));
+ errdetail("Input has too few columns."),
+ parser_coercion_errposition(pstate, location, node)));
expr = (Node *) lfirst(arg);
exprtype = exprType(expr);
- expr = coerce_to_target_type(pstate,
- expr, exprtype,
- tupdesc->attrs[i]->atttypid,
- tupdesc->attrs[i]->atttypmod,
- ccontext,
- COERCE_IMPLICIT_CAST);
- if (expr == NULL)
+ cexpr = coerce_to_target_type(pstate,
+ expr, exprtype,
+ tupdesc->attrs[i]->atttypid,
+ tupdesc->attrs[i]->atttypmod,
+ ccontext,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (cexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
@@ -846,8 +881,9 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errdetail("Cannot cast type %s to %s in column %d.",
format_type_be(exprtype),
format_type_be(tupdesc->attrs[i]->atttypid),
- ucolno)));
- newargs = lappend(newargs, expr);
+ ucolno),
+ parser_coercion_errposition(pstate, location, expr)));
+ newargs = lappend(newargs, cexpr);
ucolno++;
arg = lnext(arg);
}
@@ -857,7 +893,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
- errdetail("Input has too many columns.")));
+ errdetail("Input has too many columns."),
+ parser_coercion_errposition(pstate, location, node)));
ReleaseTupleDesc(tupdesc);
@@ -865,6 +902,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
rowexpr->args = newargs;
rowexpr->row_typeid = targetTypeId;
rowexpr->row_format = cformat;
+ rowexpr->location = location;
return (Node *) rowexpr;
}
@@ -886,16 +924,21 @@ coerce_to_boolean(ParseState *pstate, Node *node,
if (inputTypeId != BOOLOID)
{
- node = coerce_to_target_type(pstate, node, inputTypeId,
- BOOLOID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
+ Node *newnode;
+
+ newnode = coerce_to_target_type(pstate, node, inputTypeId,
+ BOOLOID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg WHERE */
- errmsg("argument of %s must be type boolean, not type %s",
- constructName, format_type_be(inputTypeId))));
+ errmsg("argument of %s must be type boolean, not type %s",
+ constructName, format_type_be(inputTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
+ node = newnode;
}
if (expression_returns_set(node))
@@ -903,7 +946,8 @@ coerce_to_boolean(ParseState *pstate, Node *node,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg WHERE */
errmsg("argument of %s must not return a set",
- constructName)));
+ constructName),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
@@ -927,18 +971,23 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
if (inputTypeId != targetTypeId)
{
- node = coerce_to_target_type(pstate, node, inputTypeId,
- targetTypeId, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
+ Node *newnode;
+
+ newnode = coerce_to_target_type(pstate, node, inputTypeId,
+ targetTypeId, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must be type %s, not type %s",
constructName,
format_type_be(targetTypeId),
- format_type_be(inputTypeId))));
+ format_type_be(inputTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
+ node = newnode;
}
if (expression_returns_set(node))
@@ -946,32 +995,62 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must not return a set",
- constructName)));
+ constructName),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
-/* select_common_type()
- * Determine the common supertype of a list of input expression types.
+/*
+ * parser_coercion_errposition - report coercion error location, if possible
+ *
+ * We prefer to point at the coercion request (CAST, ::, etc) if possible;
+ * but there may be no such location in the case of an implicit coercion.
+ * In that case point at the input expression.
+ *
+ * XXX possibly this is more generally useful than coercion errors;
+ * if so, should rename and place with parser_errposition.
+ */
+int
+parser_coercion_errposition(ParseState *pstate,
+ int coerce_location,
+ Node *input_expr)
+{
+ if (coerce_location >= 0)
+ return parser_errposition(pstate, coerce_location);
+ else
+ return parser_errposition(pstate, exprLocation(input_expr));
+}
+
+
+/*
+ * select_common_type()
+ * Determine the common supertype of a list of input expressions.
* This is used for determining the output type of CASE and UNION
* constructs.
*
- * 'typeids' is a nonempty list of type OIDs. Note that earlier items
+ * 'exprs' is a *nonempty* list of expressions. Note that earlier items
* in the list will be preferred if there is doubt.
* 'context' is a phrase to use in the error message if we fail to select
* a usable type.
+ * 'which_expr': if not NULL, receives a pointer to the particular input
+ * expression from which the result type was taken.
*/
Oid
-select_common_type(List *typeids, const char *context)
+select_common_type(ParseState *pstate, List *exprs, const char *context,
+ Node **which_expr)
{
+ Node *pexpr;
Oid ptype;
TYPCATEGORY pcategory;
bool pispreferred;
- ListCell *type_item;
+ ListCell *lc;
- Assert(typeids != NIL);
- ptype = linitial_oid(typeids);
+ Assert(exprs != NIL);
+ pexpr = (Node *) linitial(exprs);
+ lc = lnext(list_head(exprs));
+ ptype = exprType(pexpr);
/*
* If all input types are valid and exactly the same, just pick that type.
@@ -980,24 +1059,34 @@ select_common_type(List *typeids, const char *context)
*/
if (ptype != UNKNOWNOID)
{
- for_each_cell(type_item, lnext(list_head(typeids)))
+ for_each_cell(lc, lc)
{
- Oid ntype = lfirst_oid(type_item);
+ Node *nexpr = (Node *) lfirst(lc);
+ Oid ntype = exprType(nexpr);
if (ntype != ptype)
break;
}
- if (type_item == NULL) /* got to the end of the list? */
+ if (lc == NULL) /* got to the end of the list? */
+ {
+ if (which_expr)
+ *which_expr = pexpr;
return ptype;
+ }
}
- /* Nope, so set up for the full algorithm */
+ /*
+ * Nope, so set up for the full algorithm. Note that at this point,
+ * lc points to the first list item with type different from pexpr's;
+ * we need not re-examine any items the previous loop advanced over.
+ */
ptype = getBaseType(ptype);
get_type_category_preferred(ptype, &pcategory, &pispreferred);
- for_each_cell(type_item, lnext(list_head(typeids)))
+ for_each_cell(lc, lc)
{
- Oid ntype = getBaseType(lfirst_oid(type_item));
+ Node *nexpr = (Node *) lfirst(lc);
+ Oid ntype = getBaseType(exprType(nexpr));
/* move on to next one if no new information... */
if (ntype != UNKNOWNOID && ntype != ptype)
@@ -1009,6 +1098,7 @@ select_common_type(List *typeids, const char *context)
if (ptype == UNKNOWNOID)
{
/* so far, only unknowns so take anything... */
+ pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
@@ -1020,13 +1110,13 @@ select_common_type(List *typeids, const char *context)
*/
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
-
/*------
translator: first %s is name of a SQL construct, eg CASE */
errmsg("%s types %s and %s cannot be matched",
context,
format_type_be(ptype),
- format_type_be(ntype))));
+ format_type_be(ntype)),
+ parser_errposition(pstate, exprLocation(nexpr))));
}
else if (!pispreferred &&
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
@@ -1036,6 +1126,7 @@ select_common_type(List *typeids, const char *context)
* take new type if can coerce to it implicitly but not the
* other way; but if we have a preferred type, stay on it.
*/
+ pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
@@ -1057,10 +1148,13 @@ select_common_type(List *typeids, const char *context)
if (ptype == UNKNOWNOID)
ptype = TEXTOID;
+ if (which_expr)
+ *which_expr = pexpr;
return ptype;
}
-/* coerce_to_common_type()
+/*
+ * coerce_to_common_type()
* Coerce an expression to the given type.
*
* This is used following select_common_type() to coerce the individual
@@ -1080,7 +1174,7 @@ coerce_to_common_type(ParseState *pstate, Node *node,
return node; /* no work */
if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
@@ -1088,7 +1182,8 @@ coerce_to_common_type(ParseState *pstate, Node *node,
errmsg("%s could not convert type %s to %s",
context,
format_type_be(inputTypeId),
- format_type_be(targetTypeId))));
+ format_type_be(targetTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
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)
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index b1de6264aa5..31317800c1e 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.205 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -173,7 +173,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
*/
return coerce_type(pstate, linitial(fargs),
actual_arg_types[0], rettype, -1,
- COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
+ COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
}
else if (fdresult == FUNCDETAIL_NORMAL)
{
@@ -272,6 +272,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("could not find array type for data type %s",
format_type_be(newa->element_typeid))));
newa->multidims = false;
+ newa->location = exprLocation((Node *) vargs);
fargs = lappend(fargs, newa);
}
@@ -286,6 +287,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
funcexpr->funcretset = retset;
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
funcexpr->args = fargs;
+ funcexpr->location = location;
retval = (Node *) funcexpr;
}
@@ -299,6 +301,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
aggref->args = fargs;
aggref->aggstar = agg_star;
aggref->aggdistinct = agg_distinct;
+ aggref->location = location;
/*
* Reject attempt to call a parameterless aggregate without (*)
@@ -1009,7 +1012,8 @@ make_fn_arguments(ParseState *pstate,
actual_arg_types[i],
declared_arg_types[i], -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
}
i++;
}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 8cc531b350a..1760e492854 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.101 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -117,8 +117,9 @@ parser_errposition(ParseState *pstate, int location)
* Build a Var node for an attribute identified by RTE and attrno
*/
Var *
-make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
+make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
{
+ Var *result;
int vnum,
sublevels_up;
Oid vartypeid;
@@ -126,7 +127,9 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod);
- return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ result->location = location;
+ return result;
}
/*
@@ -243,11 +246,13 @@ transformArraySubscripts(ParseState *pstate,
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer")));
+ errmsg("array subscript must have type integer"),
+ parser_errposition(pstate, exprLocation(ai->lidx))));
}
else
{
@@ -267,11 +272,13 @@ transformArraySubscripts(ParseState *pstate,
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer")));
+ errmsg("array subscript must have type integer"),
+ parser_errposition(pstate, exprLocation(ai->uidx))));
upperIndexpr = lappend(upperIndexpr, subexpr);
}
@@ -283,20 +290,24 @@ transformArraySubscripts(ParseState *pstate,
{
Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? arrayType : elementType;
+ Node *newFrom;
- assignFrom = coerce_to_target_type(pstate,
- assignFrom, typesource,
- typeneeded, elementTypMod,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (assignFrom == NULL)
+ newFrom = coerce_to_target_type(pstate,
+ assignFrom, typesource,
+ typeneeded, elementTypMod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment requires type %s"
" but expression is of type %s",
format_type_be(typeneeded),
format_type_be(typesource)),
- errhint("You will need to rewrite or cast the expression.")));
+ errhint("You will need to rewrite or cast the expression."),
+ parser_errposition(pstate, exprLocation(assignFrom))));
+ assignFrom = newFrom;
}
/*
@@ -333,7 +344,7 @@ transformArraySubscripts(ParseState *pstate,
* too many examples that fail if we try.
*/
Const *
-make_const(Value *value)
+make_const(Value *value, int location)
{
Datum val;
int64 val64;
@@ -423,6 +434,7 @@ make_const(Value *value)
(Datum) 0,
true,
false);
+ con->location = location;
return con;
default:
@@ -436,6 +448,7 @@ make_const(Value *value)
val,
false,
typebyval);
+ con->location = location;
return con;
}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index f27615603b2..0ff5b59d00f 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.104 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.105 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -857,6 +857,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
result->opresulttype = rettype;
result->opretset = get_func_retset(opform->oprcode);
result->args = args;
+ result->location = location;
ReleaseSysCache(tup);
@@ -984,6 +985,7 @@ make_scalar_array_op(ParseState *pstate, List *opname,
result->opfuncid = opform->oprcode;
result->useOr = useOr;
result->args = args;
+ result->location = location;
ReleaseSysCache(tup);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 7bd53e2a94b..f7eb825f5d0 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.133 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -362,7 +362,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
errmsg("column reference \"%s\" is ambiguous",
colname),
parser_errposition(pstate, location)));
- result = (Node *) make_var(pstate, rte, attnum);
+ result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}
@@ -390,7 +390,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
Int16GetDatum(attnum),
0, 0))
{
- result = (Node *) make_var(pstate, rte, attnum);
+ result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 70acb8382a8..c7758e9adde 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.161 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.162 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -318,7 +318,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
* colname target column name (ie, name of attribute to be assigned to)
* attrno target attribute number
* indirection subscripts/field names for target column, if any
- * location error cursor position, or -1
+ * location error cursor position for the target column, or -1
*
* Returns the modified expression.
*/
@@ -403,7 +403,8 @@ transformAssignedExpr(ParseState *pstate,
*/
colVar = (Node *) make_var(pstate,
pstate->p_target_rangetblentry,
- attrno);
+ attrno,
+ location);
}
expr = (Expr *)
@@ -428,7 +429,8 @@ transformAssignedExpr(ParseState *pstate,
(Node *) expr, type_id,
attrtype, attrtypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -677,7 +679,8 @@ transformAssignmentIndirection(ParseState *pstate,
rhs, exprType(rhs),
targetTypeId, targetTypMod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (result == NULL)
{
if (targetIsArray)
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 4bab0552697..ae3ddeb2023 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -19,7 +19,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.15 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.16 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -380,9 +380,11 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
snamenode = makeNode(A_Const);
snamenode->val.type = T_String;
snamenode->val.val.str = qstring;
+ snamenode->location = -1;
castnode = makeNode(TypeCast);
castnode->typename = SystemTypeName("regclass");
castnode->arg = (Node *) snamenode;
+ castnode->location = -1;
funccallnode = makeNode(FuncCall);
funccallnode->funcname = SystemFuncName("nextval");
funccallnode->args = list_make1(castnode);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 5269fa63cd9..a6e01a8b1c2 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.178 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.179 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -654,6 +654,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation,
InvalidOid, -1,
att_tup->atttypid,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
@@ -886,7 +887,8 @@ build_column_default(Relation rel, int attrno)
expr, exprtype,
atttype, atttypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -993,6 +995,7 @@ rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos)
InvalidOid, -1,
att_tup->atttypid,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 840118bbf75..f75c1888aba 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.111 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.112 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -933,6 +933,7 @@ resolve_one_var(Var *var, ResolveNew_context *context)
InvalidOid, -1,
var->vartype,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
@@ -989,6 +990,7 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
return (Node *) rowexpr;
}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f5e28069a17..8e287a80db1 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.480 2008/08/25 11:18:43 mha Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.481 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200808251
+#define CATALOG_VERSION_NO 200808281
#endif
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index eca8feee977..d8ffa442247 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.61 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.62 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,7 +49,7 @@ extern Const *makeNullConst(Oid consttype, int32 consttypmod);
extern Node *makeBoolConst(bool value, bool isnull);
-extern Expr *makeBoolExpr(BoolExprType boolop, List *args);
+extern Expr *makeBoolExpr(BoolExprType boolop, List *args, int location);
extern Alias *makeAlias(const char *aliasname, List *colnames);
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index f699fc1b68e..5ea2efe81ef 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.27 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.28 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,8 @@ extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern bool expression_returns_set(Node *clause);
+extern int exprLocation(Node *expr);
+
extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context);
extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 65c3698a841..6292ca237c8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3,11 +3,17 @@
* parsenodes.h
* definitions for parse tree nodes
*
+ * Many of the node types used in parsetrees include a "location" field.
+ * This is a byte (not character) offset in the original source text, to be
+ * used for positioning an error cursor when there is an error related to
+ * the node. Access to the original source text is needed to make use of
+ * the location.
+ *
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.371 2008/08/07 01:11:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.372 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -141,11 +147,6 @@ typedef struct Query
* Most of these node types appear in raw parsetrees output by the grammar,
* and get transformed to something else by the analyzer. A few of them
* are used as-is in transformed querytrees.
- *
- * Many of the node types used in raw parsetrees include a "location" field.
- * This is a byte (not character) offset in the original source text, to be
- * used for positioning an error cursor when there is an analysis-time
- * error related to the node.
****************************************************************************/
/*
@@ -199,6 +200,7 @@ typedef struct ParamRef
{
NodeTag type;
int number; /* the number of the parameter */
+ int location; /* token location, or -1 if unknown */
} ParamRef;
/*
@@ -235,6 +237,7 @@ typedef struct A_Const
{
NodeTag type;
Value val; /* value (includes type info, see value.h) */
+ int location; /* token location, or -1 if unknown */
} A_Const;
/*
@@ -245,6 +248,7 @@ typedef struct TypeCast
NodeTag type;
Node *arg; /* the expression being casted */
TypeName *typename; /* the target type */
+ int location; /* token location, or -1 if unknown */
} TypeCast;
/*
@@ -305,6 +309,7 @@ typedef struct A_ArrayExpr
{
NodeTag type;
List *elements; /* array element expressions */
+ int location; /* token location, or -1 if unknown */
} A_ArrayExpr;
/*
@@ -459,14 +464,15 @@ typedef struct LockingClause
} LockingClause;
/*
- * XMLSERIALIZE
+ * XMLSERIALIZE (in raw parse tree only)
*/
typedef struct XmlSerialize
{
NodeTag type;
- XmlOptionType xmloption;
+ XmlOptionType xmloption; /* DOCUMENT or CONTENT */
Node *expr;
TypeName *typename;
+ int location; /* token location, or -1 if unknown */
} XmlSerialize;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f6da1adbfa0..e4de091a751 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.139 2008/08/22 00:16:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.140 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -138,14 +138,12 @@ typedef struct Var
* all */
Oid vartype; /* pg_type OID for the type of this var */
int32 vartypmod; /* pg_attribute typmod value */
- Index varlevelsup;
-
- /*
- * for subquery variables referencing outer relations; 0 in a normal var,
- * >0 means N levels up
- */
+ Index varlevelsup; /* for subquery variables referencing outer
+ * relations; 0 in a normal var, >0 means N
+ * levels up */
Index varnoold; /* original value of varno, for debugging */
AttrNumber varoattno; /* original value of varattno */
+ int location; /* token location, or -1 if unknown */
} Var;
/*
@@ -164,6 +162,7 @@ typedef struct Const
* If true, then all the information is stored
* in the Datum. If false, then the Datum
* contains a pointer to the information. */
+ int location; /* token location, or -1 if unknown */
} Const;
/* ----------------
@@ -204,6 +203,7 @@ typedef struct Param
int paramid; /* numeric ID for parameter */
Oid paramtype; /* pg_type OID of parameter's datatype */
int32 paramtypmod; /* typmod value, if known */
+ int location; /* token location, or -1 if unknown */
} Param;
/*
@@ -218,6 +218,7 @@ typedef struct Aggref
Index agglevelsup; /* > 0 if agg belongs to outer query */
bool aggstar; /* TRUE if argument list was really '*' */
bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */
+ int location; /* token location, or -1 if unknown */
} Aggref;
/* ----------------
@@ -293,6 +294,7 @@ typedef struct FuncExpr
bool funcretset; /* true if function returns set */
CoercionForm funcformat; /* how to display this function call */
List *args; /* arguments to the function */
+ int location; /* token location, or -1 if unknown */
} FuncExpr;
/*
@@ -312,6 +314,7 @@ typedef struct OpExpr
Oid opresulttype; /* PG_TYPE OID of result value */
bool opretset; /* true if operator returns set */
List *args; /* arguments to the operator (1 or 2) */
+ int location; /* token location, or -1 if unknown */
} OpExpr;
/*
@@ -343,6 +346,7 @@ typedef struct ScalarArrayOpExpr
Oid opfuncid; /* PG_PROC OID of underlying function */
bool useOr; /* true for ANY, false for ALL */
List *args; /* the scalar and array operands */
+ int location; /* token location, or -1 if unknown */
} ScalarArrayOpExpr;
/*
@@ -350,9 +354,11 @@ typedef struct ScalarArrayOpExpr
*
* Notice the arguments are given as a List. For NOT, of course the list
* must always have exactly one element. For AND and OR, the executor can
- * handle any number of arguments. The parser treats AND and OR as binary
- * and so it only produces two-element lists, but the optimizer will flatten
- * trees of AND and OR nodes to produce longer lists when possible.
+ * handle any number of arguments. The parser generally treats AND and OR
+ * as binary and so it typically only produces two-element lists, but the
+ * optimizer will flatten trees of AND and OR nodes to produce longer lists
+ * when possible. There are also a few special cases where more arguments
+ * can appear before optimization.
*/
typedef enum BoolExprType
{
@@ -364,6 +370,7 @@ typedef struct BoolExpr
Expr xpr;
BoolExprType boolop;
List *args; /* arguments to this expression */
+ int location; /* token location, or -1 if unknown */
} BoolExpr;
/*
@@ -423,6 +430,7 @@ typedef struct SubLink
Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */
List *operName; /* originally specified operator name */
Node *subselect; /* subselect as Query* or parsetree */
+ int location; /* token location, or -1 if unknown */
} SubLink;
/*
@@ -570,6 +578,7 @@ typedef struct RelabelType
Oid resulttype; /* output type of coercion expression */
int32 resulttypmod; /* output typmod (usually -1) */
CoercionForm relabelformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} RelabelType;
/* ----------------
@@ -588,6 +597,7 @@ typedef struct CoerceViaIO
Oid resulttype; /* output type of coercion */
/* output typmod is not stored, but is presumed -1 */
CoercionForm coerceformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} CoerceViaIO;
/* ----------------
@@ -611,6 +621,7 @@ typedef struct ArrayCoerceExpr
int32 resulttypmod; /* output typmod (also element typmod) */
bool isExplicit; /* conversion semantics flag to pass to func */
CoercionForm coerceformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} ArrayCoerceExpr;
/* ----------------
@@ -632,6 +643,7 @@ typedef struct ConvertRowtypeExpr
Oid resulttype; /* output type (always a composite type) */
/* result typmod is not stored, but must be -1; see RowExpr comments */
CoercionForm convertformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} ConvertRowtypeExpr;
/*----------
@@ -663,6 +675,7 @@ typedef struct CaseExpr
Expr *arg; /* implicit equality comparison argument */
List *args; /* the arguments (list of WHEN clauses) */
Expr *defresult; /* the default result (ELSE clause) */
+ int location; /* token location, or -1 if unknown */
} CaseExpr;
/*
@@ -673,6 +686,7 @@ typedef struct CaseWhen
Expr xpr;
Expr *expr; /* condition expression */
Expr *result; /* substitution result */
+ int location; /* token location, or -1 if unknown */
} CaseWhen;
/*
@@ -705,6 +719,7 @@ typedef struct ArrayExpr
Oid element_typeid; /* common type of array elements */
List *elements; /* the array elements or sub-arrays */
bool multidims; /* true if elements are sub-arrays */
+ int location; /* token location, or -1 if unknown */
} ArrayExpr;
/*
@@ -733,6 +748,7 @@ typedef struct RowExpr
* parsetrees. We must assume typmod -1 for a RowExpr node.
*/
CoercionForm row_format; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} RowExpr;
/*
@@ -778,6 +794,7 @@ typedef struct CoalesceExpr
Expr xpr;
Oid coalescetype; /* type of expression result */
List *args; /* the arguments */
+ int location; /* token location, or -1 if unknown */
} CoalesceExpr;
/*
@@ -795,6 +812,7 @@ typedef struct MinMaxExpr
Oid minmaxtype; /* common type of arguments and result */
MinMaxOp op; /* function to execute */
List *args; /* the arguments */
+ int location; /* token location, or -1 if unknown */
} MinMaxExpr;
/*
@@ -833,6 +851,7 @@ typedef struct XmlExpr
XmlOptionType xmloption; /* DOCUMENT or CONTENT */
Oid type; /* target type for XMLSERIALIZE */
int32 typmod;
+ int location; /* token location, or -1 if unknown */
} XmlExpr;
/*
@@ -905,6 +924,7 @@ typedef struct CoerceToDomain
Oid resulttype; /* domain type ID (result type) */
int32 resulttypmod; /* output typmod (currently always -1) */
CoercionForm coercionformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} CoerceToDomain;
/*
@@ -921,6 +941,7 @@ typedef struct CoerceToDomainValue
Expr xpr;
Oid typeId; /* type for substituted value */
int32 typeMod; /* typemod for substituted value */
+ int location; /* token location, or -1 if unknown */
} CoerceToDomainValue;
/*
@@ -935,6 +956,7 @@ typedef struct SetToDefault
Expr xpr;
Oid typeId; /* type for substituted value */
int32 typeMod; /* typemod for substituted value */
+ int location; /* token location, or -1 if unknown */
} SetToDefault;
/*
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index 68d5173378a..85485812d86 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.76 2008/07/30 17:05:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.77 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,15 +39,17 @@ extern Node *coerce_to_target_type(ParseState *pstate,
Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
- CoercionForm cformat);
+ CoercionForm cformat,
+ int location);
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
CoercionContext ccontext);
extern Node *coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat);
+ CoercionContext ccontext, CoercionForm cformat, int location);
extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
Oid typeId,
- CoercionForm cformat, bool hideInputCoercion,
+ CoercionForm cformat, int location,
+ bool hideInputCoercion,
bool lengthCoercionDone);
extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
@@ -56,7 +58,12 @@ extern Node *coerce_to_specific_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *constructName);
-extern Oid select_common_type(List *typeids, const char *context);
+extern int parser_coercion_errposition(ParseState *pstate,
+ int coerce_location,
+ Node *input_expr);
+
+extern Oid select_common_type(ParseState *pstate, List *exprs,
+ const char *context, Node **which_expr);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *context);
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index ed8f7fe3b3a..fa6b14d4d3a 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.54 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.55 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,7 +86,8 @@ extern ParseState *make_parsestate(ParseState *parentParseState);
extern void free_parsestate(ParseState *pstate);
extern int parser_errposition(ParseState *pstate, int location);
-extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
+extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
+ int location);
extern Oid transformArrayType(Oid arrayType);
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
@@ -95,6 +96,6 @@ extern ArrayRef *transformArraySubscripts(ParseState *pstate,
int32 elementTypMod,
List *indirection,
Node *assignFrom);
-extern Const *make_const(Value *value);
+extern Const *make_const(Value *value, int location);
#endif /* PARSE_NODE_H */
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index bcb451e8080..5103d6868de 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -787,6 +787,8 @@ select '{ }}'::text[];
ERROR: malformed array literal: "{ }}"
select array[];
ERROR: cannot determine type of empty array
+LINE 1: select array[];
+ ^
HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[].
-- none of the above should be accepted
-- all of the following should be accepted
diff --git a/src/test/regress/expected/select_implicit.out b/src/test/regress/expected/select_implicit.out
index 1ee7f9b7358..14ee2b62053 100644
--- a/src/test/regress/expected/select_implicit.out
+++ b/src/test/regress/expected/select_implicit.out
@@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1;
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
diff --git a/src/test/regress/expected/select_implicit_1.out b/src/test/regress/expected/select_implicit_1.out
index 85092ef046c..feb33ec576c 100644
--- a/src/test/regress/expected/select_implicit_1.out
+++ b/src/test/regress/expected/select_implicit_1.out
@@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1;
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
diff --git a/src/test/regress/expected/select_implicit_2.out b/src/test/regress/expected/select_implicit_2.out
index 718eb09f058..fac106353f4 100644
--- a/src/test/regress/expected/select_implicit_2.out
+++ b/src/test/regress/expected/select_implicit_2.out
@@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1;
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 45d82c7dda8..f29c61b23c5 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -54,6 +54,8 @@ SELECT xmlconcat('hello', 'you');
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
+LINE 1: SELECT xmlconcat(1, 2);
+ ^
SELECT xmlconcat('bad', '<syntax');
ERROR: invalid XML content
DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
@@ -82,6 +84,8 @@ SELECT xmlelement(name element,
SELECT xmlelement(name element,
xmlattributes ('unnamed and wrong'));
ERROR: unnamed XML attribute value must be a column reference
+LINE 2: xmlattributes ('unnamed and wrong'));
+ ^
SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
xmlelement
-------------------------------------------
@@ -101,6 +105,8 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
ERROR: XML attribute name "a" appears more than once
+LINE 1: ...ment(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
+ ^
SELECT xmlelement(name num, 37);
xmlelement
---------------
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 76455919fc0..ff3bfb77bf7 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -51,6 +51,8 @@ DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
+LINE 1: SELECT xmlconcat(1, 2);
+ ^
SELECT xmlconcat('bad', '<syntax');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.