Extend the parser location infrastructure to include a location field in
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 28 Aug 2008 23:09:48 +0000 (23:09 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 28 Aug 2008 23:09:48 +0000 (23:09 +0000)
most node types used in expression trees (both before and after parse
analysis).  This allows us to place an error cursor in many situations
where we formerly could not, because the information wasn't available
beyond the very first level of parse analysis.  There's a fair amount
of work still to be done to persuade individual ereport() calls to actually
include an error location, but this gets the initdb-forcing part of the
work out of the way; and the situation is already markedly better than
before for complaints about unimplementable implicit casts, such as
CASE and UNION constructs with incompatible alternative data types.
Per my proposal of a few days ago.

44 files changed:
src/backend/catalog/heap.c
src/backend/commands/prepare.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/prep/prepqual.c
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/var.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_utilcmd.c
src/backend/rewrite/rewriteHandler.c
src/backend/rewrite/rewriteManip.c
src/include/catalog/catversion.h
src/include/nodes/makefuncs.h
src/include/nodes/nodeFuncs.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/include/parser/parse_coerce.h
src/include/parser/parse_node.h
src/test/regress/expected/arrays.out
src/test/regress/expected/select_implicit.out
src/test/regress/expected/select_implicit_1.out
src/test/regress/expected/select_implicit_2.out
src/test/regress/expected/xml.out
src/test/regress/expected/xml_1.out

index 6b2351dc93a658ed9ce3aef2794a541faae00cba..8a82e099019065571e5c1c6734a282fda6487d7b 100644 (file)
@@ -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),
index e0231cba54e12cfb8ab788a6e5506c05a9428e8b..144b05787149e4452321a01fed158f1cf7063f09 100644 (file)
@@ -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,
index e9cd1f0d1f861cc62d4b3e3a1458df4424f47763..c96c20058746a360c18999f05322bb8b60ec72af 100644 (file)
@@ -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),
index 903aeb56b286ff4b9de73fb4cb6145d342591a18..f5d9618a9ee1d7b77927ab176e7ceb652682dc9d 100644 (file)
@@ -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;
 
index 81e9197cc8d5a7d9ab1915ccf62d379882ff61ee..f0f902c69a644c1003d24c378dce39da677f942e 100644 (file)
                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;
 }
index eaba9f160604f9a53185b83a70f68465d8476e90..9b9fd46567c21b5736c27ef80f521407667b9de2 100644 (file)
  * 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
                        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;
 }
index b938b6c4d860e8bd47c00ee9e99092296227eedd..37933afb72174af4627e09785591dc459050eac1 100644 (file)
@@ -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;
 }
index 998bc377a79ead717eaabd74f900bee55c2e570f..ed24ae95d24254321b67bfe3e77fafeef2b1f349 100644 (file)
@@ -23,6 +23,7 @@
 
 
 static bool expression_returns_set_walker(Node *node, void *context);
+static int     leftmostLoc(int loc1, int loc2);
 
 
 /*
@@ -574,6 +575,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
  *
index 001645ed55826c883fbcf103e14498022a8f90d8..d8cb3da6e65269c0f3be2c0f33e2770364d9c20b 100644 (file)
        (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
index 07c88282b2f8d52cfe4dd71dfed4655b649df966..94b6bba824f112fd574eb58bff004be8bb46c5dd 100644 (file)
  *       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"
        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();
 }
index 17f29df7a2b1e3b1bd64c0090cd7d3329f8fdeae..24c5502250296cde2ef17f4d81db3be276e67610 100644 (file)
@@ -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);
index d98b0deadcd5ca9fa55af8641fd9934bf69ce21d..d28c66e23a9eca76383ff1b8b312bfc5eb15feb6 100644 (file)
@@ -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;
index 9e1bf6dbfcd45b55c64698890a868974dbba12e3..3e069005bf38abfeb285ab8b9277574d4c42f810 100644 (file)
@@ -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
index f402f92255b610e5cb91e4534ae6c166c57fa3b8..a1f40f5c06b623682bc69281c7bf527adf688815 100644 (file)
@@ -292,6 +292,7 @@ expand_targetlist(List *tlist, int command_type,
                                                                                                        InvalidOid, -1,
                                                                                                        atttype,
                                                                                                        COERCE_IMPLICIT_CAST,
+                                                                                                       -1,
                                                                                                        false,
                                                                                                        false);
                                        }
index 7d86aa17fce44869e2750fc7124c2bb618e666ff..36b08fad2b1f08d47f51ac269418a1d3bf4bd0e2 100644 (file)
@@ -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;
                                }
                        }
index 093446970618b357d9df802c93c7ad5e7a1e0fb7..db802d75fbafc0ca0fa24bea4238be03b47ef8f9 100644 (file)
@@ -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);
 }
index 22ee492e9e73a977a769901ac46fbd2633e4ab34..489f1b573cc571fc91c4d97f0f1edbf61b434f53 100644 (file)
@@ -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;
                }
index e0a5e4111cf0aeb8f2bc26c167a46bc2020b3553..e9b63e3f41a878c5fe93681c12a6625f9a5166b9 100644 (file)
@@ -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.
@@ -1264,6 +1276,24 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
                                                 errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level")));
                }
 
+               /*
+                * 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.
                 */
@@ -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,59 +1420,12 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
 
                                op->groupClauses = lappend(op->groupClauses, grpcl);
                        }
-
-                       lcm = lnext(lcm);
-                       rcm = lnext(rcm);
                }
 
                return (Node *) op;
        }
 }
 
-/*
- * 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)
index fc3bfea7d3cc612fc84bf008a1b0479cbc1001ae..17a4d24e404f35509da71d65172163e425430600 100644 (file)
@@ -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;
 }
 
index 0732baba5650de0a150e2a0da7e6b1890ae35abd..54ca963dd8a512d4b063957731b2a13ed725b5df 100644 (file)
@@ -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,
index 8577abd1f642ca4898da7db08d46184adb3087ee..e1cf581de27a0dabd53f4aaa46631bfdbdf98210 100644 (file)
@@ -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;
        }
 
index 3865cff1bfd0cc0ec7270cdab7c10ffe01ddca5f..4b6249fa33cb2ecd7cf74fe6ecfa8d486c776bc1 100644 (file)
 
 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;
 }
 
index e94644548e6c91228b39e0c3d60344ee63427c80..a4f5fbf173b90954f653f211d06b4e2185c2d1e4 100644 (file)
@@ -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)
index 3fbb0ceae313b05c211a5b5c3a8c92d538c8b4f3..625361f6e82901c5522058053783ea0325e11586 100644 (file)
@@ -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++;
        }
index 39fcfe84e3cdffd2abf2346e2c12581286540324..02b0d5bd14d29414e4c6705f93c7cf773aba6864 100644 (file)
@@ -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;
 }
index 16f2a0e1f6bcb268d43d1f9a442fcd8220fec71d..3ee052899c296becf68eceb74cf99a44363c9ceb 100644 (file)
@@ -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);
 
index d4028233c3b894a0118b19bffc8b1efddafa3ae1..0e08072e26ae9af110f7ce034441d055dc4f6b93 100644 (file)
@@ -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;
                        }
index 4d22c30a446cf8fd81ea85ee003d8b85a2f5662f..29c719002c920dba780ba894495581f0c3c2cd3e 100644 (file)
@@ -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)
index b52d71c79f69f1486b1772f1ee7c16a8110c9404..a1fcfc6efd7ebf87260f7d92938a0e3719ccfecd 100644 (file)
@@ -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);
index 7444ebd9ed4778880d7486bdfdffa472306fff31..cb8626dccbea2124595c3332ee93993ae7b383d7 100644 (file)
@@ -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);
                                }
index bc25958a8722d90c72658ec37b040d6ff5586c4d..2121e961d01c4ecc75a1f1d966c7c117ee3b3fbe 100644 (file)
@@ -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;
                        }
index dad61b7937645bb963026e07b590323978243e40..2a7c8474a32a8bba63b22c7abaf5dbffb20f3585 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200808251
+#define CATALOG_VERSION_NO     200808281
 
 #endif
index 9a059103d1abb90c947a704b67a637b70d2752db..e03c7607c3fc431abf066428f57a638d5c0d4eca 100644 (file)
@@ -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);
 
index 4207510c6843dfd3cd4275499efce2ec1d505451..7fe13d1032285a6bd2ff49bcf0ca7033a89b667c 100644 (file)
@@ -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) (),
index 51d71ecb1f784c8f7b2e7f1d5d6dfed7cd6ff513..2366e0384a0901dde1a4545bcd79e76a6725f077 100644 (file)
@@ -3,6 +3,12 @@
  * 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
@@ -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;
 
 
index a9a6bda0c33a06b9bec3867e7dfa9c0d43bceb0c..49ab5ca2f9c4a005deec85fcebd09be54a798a26 100644 (file)
@@ -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;
 
 /*
index d6a38a2b8106ca68b2b7719759b0827964823dd6..c8ae4adf41c8d9c613eb9e1acbcbd120b0a02cd4 100644 (file)
@@ -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);
index 9aab580bd710c16e86ec7295c0349e98bd553dc9..edeac719f5f1fc86e718b13a3fac334652f5b6fc 100644 (file)
@@ -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 */
index bcb451e8080a9374b33c8cbccd81e6ea9fc82f42..5103d6868de5045c9ffaea29a1bd360d6cd2ac95 100644 (file)
@@ -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
index 1ee7f9b7358d2e6b540a4028c400a7ce65ed848e..14ee2b62053c19f2711a243815a394414577e019 100644 (file)
@@ -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 
index 85092ef046cf23b37aa475c347a5cbfd94b250ac..feb33ec576cf4c20c4248b9aa50df8737f074977 100644 (file)
@@ -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 
index 718eb09f058101127db6e7db55157445ed7a9c10..fac106353f47820fb38c5e31dae73e3533a407b7 100644 (file)
@@ -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 
index 45d82c7dda8ae8c1e9e93051725c4fe3171dc983..f29c61b23c51858ff5d313951284fbf3b3e3e7e9 100644 (file)
@@ -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   
 ---------------
index 76455919fc0567a804914678e747b5179d1ba8c5..ff3bfb77bf7d4caa989523822c3450d58bd716f0 100644 (file)
@@ -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.