diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 499929ef10..5b26b91b69 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.338 2008/08/25 22:42:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.339 2008/08/28 23:09:45 tgl Exp $ * * * INTERFACE ROUTINES @@ -2121,7 +2121,8 @@ cookDefault(ParseState *pstate, expr = coerce_to_target_type(pstate, expr, type_id, atttypid, atttypmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 2fca3a5e81..dee994c550 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2008, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.90 2008/08/25 22:42:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.91 2008/08/28 23:09:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -353,7 +353,8 @@ EvaluateParams(PreparedStatement *pstmt, List *params, expr = coerce_to_target_type(pstate, expr, given_type_id, expected_type_id, -1, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (expr == NULL) ereport(ERROR, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a8ae2e4be1..6f2303f62c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.263 2008/08/25 22:42:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.264 2008/08/28 23:09:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3649,7 +3649,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, typeOid, typmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (defval == NULL) /* should not happen */ elog(ERROR, "failed to coerce base type to domain"); } @@ -5509,7 +5510,8 @@ ATPrepAlterColumnType(List **wqueue, transform, exprType(transform), targettype, targettypmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (transform == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -5607,7 +5609,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, defaultexpr, exprType(defaultexpr), targettype, targettypmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (defaultexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index ee30d32704..c0dc74bee7 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.122 2008/07/31 16:27:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.123 2008/08/28 23:09:45 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -2135,6 +2135,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, domVal = makeNode(CoerceToDomainValue); domVal->typeId = baseTypeOid; domVal->typeMod = typMod; + domVal->location = -1; /* will be set when/if used */ pstate->p_value_substitute = (Node *) domVal; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 4a30a3d822..4e984719d3 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.401 2008/08/22 00:16:03 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.402 2008/08/28 23:09:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,6 +58,10 @@ memcpy(newnode->fldname, from->fldname, _size); \ } while (0) +/* Copy a parse location field (for Copy, this is same as scalar case) */ +#define COPY_LOCATION_FIELD(fldname) \ + (newnode->fldname = from->fldname) + /* **************************************************************** * plannodes.h copy functions @@ -761,6 +765,7 @@ _copyVar(Var *from) COPY_SCALAR_FIELD(varlevelsup); COPY_SCALAR_FIELD(varnoold); COPY_SCALAR_FIELD(varoattno); + COPY_LOCATION_FIELD(location); return newnode; } @@ -797,6 +802,7 @@ _copyConst(Const *from) COPY_SCALAR_FIELD(constisnull); COPY_SCALAR_FIELD(constbyval); + COPY_LOCATION_FIELD(location); return newnode; } @@ -813,6 +819,7 @@ _copyParam(Param *from) COPY_SCALAR_FIELD(paramid); COPY_SCALAR_FIELD(paramtype); COPY_SCALAR_FIELD(paramtypmod); + COPY_LOCATION_FIELD(location); return newnode; } @@ -831,6 +838,7 @@ _copyAggref(Aggref *from) COPY_SCALAR_FIELD(agglevelsup); COPY_SCALAR_FIELD(aggstar); COPY_SCALAR_FIELD(aggdistinct); + COPY_LOCATION_FIELD(location); return newnode; } @@ -867,6 +875,7 @@ _copyFuncExpr(FuncExpr *from) COPY_SCALAR_FIELD(funcretset); COPY_SCALAR_FIELD(funcformat); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -884,6 +893,7 @@ _copyOpExpr(OpExpr *from) COPY_SCALAR_FIELD(opresulttype); COPY_SCALAR_FIELD(opretset); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -901,6 +911,7 @@ _copyDistinctExpr(DistinctExpr *from) COPY_SCALAR_FIELD(opresulttype); COPY_SCALAR_FIELD(opretset); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -917,6 +928,7 @@ _copyScalarArrayOpExpr(ScalarArrayOpExpr *from) COPY_SCALAR_FIELD(opfuncid); COPY_SCALAR_FIELD(useOr); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -931,6 +943,7 @@ _copyBoolExpr(BoolExpr *from) COPY_SCALAR_FIELD(boolop); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -947,6 +960,7 @@ _copySubLink(SubLink *from) COPY_NODE_FIELD(testexpr); COPY_NODE_FIELD(operName); COPY_NODE_FIELD(subselect); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1032,6 +1046,7 @@ _copyRelabelType(RelabelType *from) COPY_SCALAR_FIELD(resulttype); COPY_SCALAR_FIELD(resulttypmod); COPY_SCALAR_FIELD(relabelformat); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1047,6 +1062,7 @@ _copyCoerceViaIO(CoerceViaIO *from) COPY_NODE_FIELD(arg); COPY_SCALAR_FIELD(resulttype); COPY_SCALAR_FIELD(coerceformat); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1065,6 +1081,7 @@ _copyArrayCoerceExpr(ArrayCoerceExpr *from) COPY_SCALAR_FIELD(resulttypmod); COPY_SCALAR_FIELD(isExplicit); COPY_SCALAR_FIELD(coerceformat); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1080,6 +1097,7 @@ _copyConvertRowtypeExpr(ConvertRowtypeExpr *from) COPY_NODE_FIELD(arg); COPY_SCALAR_FIELD(resulttype); COPY_SCALAR_FIELD(convertformat); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1096,6 +1114,7 @@ _copyCaseExpr(CaseExpr *from) COPY_NODE_FIELD(arg); COPY_NODE_FIELD(args); COPY_NODE_FIELD(defresult); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1110,6 +1129,7 @@ _copyCaseWhen(CaseWhen *from) COPY_NODE_FIELD(expr); COPY_NODE_FIELD(result); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1140,6 +1160,7 @@ _copyArrayExpr(ArrayExpr *from) COPY_SCALAR_FIELD(element_typeid); COPY_NODE_FIELD(elements); COPY_SCALAR_FIELD(multidims); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1155,6 +1176,7 @@ _copyRowExpr(RowExpr *from) COPY_NODE_FIELD(args); COPY_SCALAR_FIELD(row_typeid); COPY_SCALAR_FIELD(row_format); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1186,6 +1208,7 @@ _copyCoalesceExpr(CoalesceExpr *from) COPY_SCALAR_FIELD(coalescetype); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1201,6 +1224,7 @@ _copyMinMaxExpr(MinMaxExpr *from) COPY_SCALAR_FIELD(minmaxtype); COPY_SCALAR_FIELD(op); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1221,6 +1245,7 @@ _copyXmlExpr(XmlExpr *from) COPY_SCALAR_FIELD(xmloption); COPY_SCALAR_FIELD(type); COPY_SCALAR_FIELD(typmod); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1238,6 +1263,7 @@ _copyNullIfExpr(NullIfExpr *from) COPY_SCALAR_FIELD(opresulttype); COPY_SCALAR_FIELD(opretset); COPY_NODE_FIELD(args); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1282,6 +1308,7 @@ _copyCoerceToDomain(CoerceToDomain *from) COPY_SCALAR_FIELD(resulttype); COPY_SCALAR_FIELD(resulttypmod); COPY_SCALAR_FIELD(coercionformat); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1296,6 +1323,7 @@ _copyCoerceToDomainValue(CoerceToDomainValue *from) COPY_SCALAR_FIELD(typeId); COPY_SCALAR_FIELD(typeMod); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1310,6 +1338,7 @@ _copySetToDefault(SetToDefault *from) COPY_SCALAR_FIELD(typeId); COPY_SCALAR_FIELD(typeMod); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1595,7 +1624,7 @@ _copyAExpr(A_Expr *from) COPY_NODE_FIELD(name); COPY_NODE_FIELD(lexpr); COPY_NODE_FIELD(rexpr); - COPY_SCALAR_FIELD(location); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1606,7 +1635,7 @@ _copyColumnRef(ColumnRef *from) ColumnRef *newnode = makeNode(ColumnRef); COPY_NODE_FIELD(fields); - COPY_SCALAR_FIELD(location); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1617,6 +1646,7 @@ _copyParamRef(ParamRef *from) ParamRef *newnode = makeNode(ParamRef); COPY_SCALAR_FIELD(number); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1647,6 +1677,8 @@ _copyAConst(A_Const *from) break; } + COPY_LOCATION_FIELD(location); + return newnode; } @@ -1660,7 +1692,7 @@ _copyFuncCall(FuncCall *from) COPY_SCALAR_FIELD(agg_star); COPY_SCALAR_FIELD(agg_distinct); COPY_SCALAR_FIELD(func_variadic); - COPY_SCALAR_FIELD(location); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1693,6 +1725,7 @@ _copyA_ArrayExpr(A_ArrayExpr *from) A_ArrayExpr *newnode = makeNode(A_ArrayExpr); COPY_NODE_FIELD(elements); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1705,7 +1738,7 @@ _copyResTarget(ResTarget *from) COPY_STRING_FIELD(name); COPY_NODE_FIELD(indirection); COPY_NODE_FIELD(val); - COPY_SCALAR_FIELD(location); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1722,7 +1755,7 @@ _copyTypeName(TypeName *from) COPY_NODE_FIELD(typmods); COPY_SCALAR_FIELD(typemod); COPY_NODE_FIELD(arrayBounds); - COPY_SCALAR_FIELD(location); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1770,6 +1803,7 @@ _copyTypeCast(TypeCast *from) COPY_NODE_FIELD(arg); COPY_NODE_FIELD(typename); + COPY_LOCATION_FIELD(location); return newnode; } @@ -1852,6 +1886,7 @@ _copyXmlSerialize(XmlSerialize *from) COPY_SCALAR_FIELD(xmloption); COPY_NODE_FIELD(expr); COPY_NODE_FIELD(typename); + COPY_LOCATION_FIELD(location); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 3a25111c60..3d130c9524 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -13,12 +13,16 @@ * Currently, in fact, equal() doesn't know how to compare Plan trees * either. This might need to be fixed someday. * + * NOTE: it is intentional that parse location fields (in nodes that have + * one) are not compared. This is because we want, for example, a variable + * "x" to be considered equal() to another reference to "x" in the query. + * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.328 2008/08/22 00:16:03 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.329 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,6 +79,10 @@ return false; \ } while (0) +/* Compare a parse location field (this is a no-op, per note above) */ +#define COMPARE_LOCATION_FIELD(fldname) \ + ((void) 0) + /* * Stuff from primnodes.h @@ -131,6 +139,7 @@ _equalVar(Var *a, Var *b) COMPARE_SCALAR_FIELD(varlevelsup); COMPARE_SCALAR_FIELD(varnoold); COMPARE_SCALAR_FIELD(varoattno); + COMPARE_LOCATION_FIELD(location); return true; } @@ -143,6 +152,7 @@ _equalConst(Const *a, Const *b) COMPARE_SCALAR_FIELD(constlen); COMPARE_SCALAR_FIELD(constisnull); COMPARE_SCALAR_FIELD(constbyval); + COMPARE_LOCATION_FIELD(location); /* * We treat all NULL constants of the same type as equal. Someday this @@ -161,6 +171,7 @@ _equalParam(Param *a, Param *b) COMPARE_SCALAR_FIELD(paramid); COMPARE_SCALAR_FIELD(paramtype); COMPARE_SCALAR_FIELD(paramtypmod); + COMPARE_LOCATION_FIELD(location); return true; } @@ -174,6 +185,7 @@ _equalAggref(Aggref *a, Aggref *b) COMPARE_SCALAR_FIELD(agglevelsup); COMPARE_SCALAR_FIELD(aggstar); COMPARE_SCALAR_FIELD(aggdistinct); + COMPARE_LOCATION_FIELD(location); return true; } @@ -209,6 +221,7 @@ _equalFuncExpr(FuncExpr *a, FuncExpr *b) return false; COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -232,6 +245,7 @@ _equalOpExpr(OpExpr *a, OpExpr *b) COMPARE_SCALAR_FIELD(opresulttype); COMPARE_SCALAR_FIELD(opretset); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -255,6 +269,7 @@ _equalDistinctExpr(DistinctExpr *a, DistinctExpr *b) COMPARE_SCALAR_FIELD(opresulttype); COMPARE_SCALAR_FIELD(opretset); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -277,6 +292,7 @@ _equalScalarArrayOpExpr(ScalarArrayOpExpr *a, ScalarArrayOpExpr *b) COMPARE_SCALAR_FIELD(useOr); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -286,6 +302,7 @@ _equalBoolExpr(BoolExpr *a, BoolExpr *b) { COMPARE_SCALAR_FIELD(boolop); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -297,6 +314,7 @@ _equalSubLink(SubLink *a, SubLink *b) COMPARE_NODE_FIELD(testexpr); COMPARE_NODE_FIELD(operName); COMPARE_NODE_FIELD(subselect); + COMPARE_LOCATION_FIELD(location); return true; } @@ -366,6 +384,8 @@ _equalRelabelType(RelabelType *a, RelabelType *b) b->relabelformat != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -384,6 +404,8 @@ _equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b) b->coerceformat != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -405,6 +427,8 @@ _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b) b->coerceformat != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -423,6 +447,8 @@ _equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b) b->convertformat != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -433,6 +459,7 @@ _equalCaseExpr(CaseExpr *a, CaseExpr *b) COMPARE_NODE_FIELD(arg); COMPARE_NODE_FIELD(args); COMPARE_NODE_FIELD(defresult); + COMPARE_LOCATION_FIELD(location); return true; } @@ -442,6 +469,7 @@ _equalCaseWhen(CaseWhen *a, CaseWhen *b) { COMPARE_NODE_FIELD(expr); COMPARE_NODE_FIELD(result); + COMPARE_LOCATION_FIELD(location); return true; } @@ -462,6 +490,7 @@ _equalArrayExpr(ArrayExpr *a, ArrayExpr *b) COMPARE_SCALAR_FIELD(element_typeid); COMPARE_NODE_FIELD(elements); COMPARE_SCALAR_FIELD(multidims); + COMPARE_LOCATION_FIELD(location); return true; } @@ -481,6 +510,8 @@ _equalRowExpr(RowExpr *a, RowExpr *b) b->row_format != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -501,6 +532,7 @@ _equalCoalesceExpr(CoalesceExpr *a, CoalesceExpr *b) { COMPARE_SCALAR_FIELD(coalescetype); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -511,6 +543,7 @@ _equalMinMaxExpr(MinMaxExpr *a, MinMaxExpr *b) COMPARE_SCALAR_FIELD(minmaxtype); COMPARE_SCALAR_FIELD(op); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -526,6 +559,7 @@ _equalXmlExpr(XmlExpr *a, XmlExpr *b) COMPARE_SCALAR_FIELD(xmloption); COMPARE_SCALAR_FIELD(type); COMPARE_SCALAR_FIELD(typmod); + COMPARE_LOCATION_FIELD(location); return true; } @@ -549,6 +583,7 @@ _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b) COMPARE_SCALAR_FIELD(opresulttype); COMPARE_SCALAR_FIELD(opretset); COMPARE_NODE_FIELD(args); + COMPARE_LOCATION_FIELD(location); return true; } @@ -587,6 +622,8 @@ _equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b) b->coercionformat != COERCE_DONTCARE) return false; + COMPARE_LOCATION_FIELD(location); + return true; } @@ -595,6 +632,7 @@ _equalCoerceToDomainValue(CoerceToDomainValue *a, CoerceToDomainValue *b) { COMPARE_SCALAR_FIELD(typeId); COMPARE_SCALAR_FIELD(typeMod); + COMPARE_LOCATION_FIELD(location); return true; } @@ -604,6 +642,7 @@ _equalSetToDefault(SetToDefault *a, SetToDefault *b) { COMPARE_SCALAR_FIELD(typeId); COMPARE_SCALAR_FIELD(typeMod); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1680,7 +1719,7 @@ _equalAExpr(A_Expr *a, A_Expr *b) COMPARE_NODE_FIELD(name); COMPARE_NODE_FIELD(lexpr); COMPARE_NODE_FIELD(rexpr); - COMPARE_SCALAR_FIELD(location); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1689,7 +1728,7 @@ static bool _equalColumnRef(ColumnRef *a, ColumnRef *b) { COMPARE_NODE_FIELD(fields); - COMPARE_SCALAR_FIELD(location); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1698,6 +1737,7 @@ static bool _equalParamRef(ParamRef *a, ParamRef *b) { COMPARE_SCALAR_FIELD(number); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1707,6 +1747,7 @@ _equalAConst(A_Const *a, A_Const *b) { if (!equal(&a->val, &b->val)) /* hack for in-line Value field */ return false; + COMPARE_LOCATION_FIELD(location); return true; } @@ -1719,7 +1760,7 @@ _equalFuncCall(FuncCall *a, FuncCall *b) COMPARE_SCALAR_FIELD(agg_star); COMPARE_SCALAR_FIELD(agg_distinct); COMPARE_SCALAR_FIELD(func_variadic); - COMPARE_SCALAR_FIELD(location); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1746,6 +1787,7 @@ static bool _equalA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b) { COMPARE_NODE_FIELD(elements); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1756,7 +1798,7 @@ _equalResTarget(ResTarget *a, ResTarget *b) COMPARE_STRING_FIELD(name); COMPARE_NODE_FIELD(indirection); COMPARE_NODE_FIELD(val); - COMPARE_SCALAR_FIELD(location); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1771,7 +1813,7 @@ _equalTypeName(TypeName *a, TypeName *b) COMPARE_NODE_FIELD(typmods); COMPARE_SCALAR_FIELD(typemod); COMPARE_NODE_FIELD(arrayBounds); - COMPARE_SCALAR_FIELD(location); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1781,6 +1823,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b) { COMPARE_NODE_FIELD(arg); COMPARE_NODE_FIELD(typename); + COMPARE_LOCATION_FIELD(location); return true; } @@ -1941,6 +1984,7 @@ _equalXmlSerialize(XmlSerialize *a, XmlSerialize *b) COMPARE_SCALAR_FIELD(xmloption); COMPARE_NODE_FIELD(expr); COMPARE_NODE_FIELD(typename); + COMPARE_LOCATION_FIELD(location); return true; } diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 228bf5ea91..5ab853c37b 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.58 2008/01/01 19:45:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.59 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -84,6 +84,9 @@ makeVar(Index varno, var->varnoold = varno; var->varoattno = varattno; + /* Likewise, we just set location to "unknown" here */ + var->location = -1; + return var; } @@ -168,6 +171,7 @@ makeConst(Oid consttype, cnst->constvalue = constvalue; cnst->constisnull = constisnull; cnst->constbyval = constbyval; + cnst->location = -1; /* "unknown" */ return cnst; } @@ -211,12 +215,13 @@ makeBoolConst(bool value, bool isnull) * creates a BoolExpr node */ Expr * -makeBoolExpr(BoolExprType boolop, List *args) +makeBoolExpr(BoolExprType boolop, List *args, int location) { BoolExpr *b = makeNode(BoolExpr); b->boolop = boolop; b->args = args; + b->location = location; return (Expr *) b; } @@ -251,6 +256,7 @@ makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, CoercionForm rformat) r->resulttype = rtype; r->resulttypmod = rtypmod; r->relabelformat = rformat; + r->location = -1; return r; } @@ -336,6 +342,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, CoercionForm fformat) funcexpr->funcretset = false; /* only allowed case here */ funcexpr->funcformat = fformat; funcexpr->args = args; + funcexpr->location = -1; return funcexpr; } diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 7944936ba6..fa1bb347b9 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.30 2008/08/25 22:42:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.31 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ static bool expression_returns_set_walker(Node *node, void *context); +static int leftmostLoc(int loc1, int loc2); /* @@ -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 * diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 76f8da1bab..91fa30ae23 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.335 2008/08/22 00:16:03 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.336 2008/08/28 23:09:46 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -79,6 +79,10 @@ (appendStringInfo(str, " :" CppAsString(fldname) " "), \ _outToken(str, node->fldname)) +/* Write a parse location field (actually same as INT case) */ +#define WRITE_LOCATION_FIELD(fldname) \ + appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname) + /* Write a Node field */ #define WRITE_NODE_FIELD(fldname) \ (appendStringInfo(str, " :" CppAsString(fldname) " "), \ @@ -689,6 +693,7 @@ _outVar(StringInfo str, Var *node) WRITE_UINT_FIELD(varlevelsup); WRITE_UINT_FIELD(varnoold); WRITE_INT_FIELD(varoattno); + WRITE_LOCATION_FIELD(location); } static void @@ -701,6 +706,7 @@ _outConst(StringInfo str, Const *node) WRITE_INT_FIELD(constlen); WRITE_BOOL_FIELD(constbyval); WRITE_BOOL_FIELD(constisnull); + WRITE_LOCATION_FIELD(location); appendStringInfo(str, " :constvalue "); if (node->constisnull) @@ -718,6 +724,7 @@ _outParam(StringInfo str, Param *node) WRITE_INT_FIELD(paramid); WRITE_OID_FIELD(paramtype); WRITE_INT_FIELD(paramtypmod); + WRITE_LOCATION_FIELD(location); } static void @@ -731,6 +738,7 @@ _outAggref(StringInfo str, Aggref *node) WRITE_UINT_FIELD(agglevelsup); WRITE_BOOL_FIELD(aggstar); WRITE_BOOL_FIELD(aggdistinct); + WRITE_LOCATION_FIELD(location); } static void @@ -757,6 +765,7 @@ _outFuncExpr(StringInfo str, FuncExpr *node) WRITE_BOOL_FIELD(funcretset); WRITE_ENUM_FIELD(funcformat, CoercionForm); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -769,6 +778,7 @@ _outOpExpr(StringInfo str, OpExpr *node) WRITE_OID_FIELD(opresulttype); WRITE_BOOL_FIELD(opretset); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -781,6 +791,7 @@ _outDistinctExpr(StringInfo str, DistinctExpr *node) WRITE_OID_FIELD(opresulttype); WRITE_BOOL_FIELD(opretset); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -792,6 +803,7 @@ _outScalarArrayOpExpr(StringInfo str, ScalarArrayOpExpr *node) WRITE_OID_FIELD(opfuncid); WRITE_BOOL_FIELD(useOr); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -818,6 +830,7 @@ _outBoolExpr(StringInfo str, BoolExpr *node) _outToken(str, opstr); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -829,6 +842,7 @@ _outSubLink(StringInfo str, SubLink *node) WRITE_NODE_FIELD(testexpr); WRITE_NODE_FIELD(operName); WRITE_NODE_FIELD(subselect); + WRITE_LOCATION_FIELD(location); } static void @@ -889,6 +903,7 @@ _outRelabelType(StringInfo str, RelabelType *node) WRITE_OID_FIELD(resulttype); WRITE_INT_FIELD(resulttypmod); WRITE_ENUM_FIELD(relabelformat, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -899,6 +914,7 @@ _outCoerceViaIO(StringInfo str, CoerceViaIO *node) WRITE_NODE_FIELD(arg); WRITE_OID_FIELD(resulttype); WRITE_ENUM_FIELD(coerceformat, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -912,6 +928,7 @@ _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node) WRITE_INT_FIELD(resulttypmod); WRITE_BOOL_FIELD(isExplicit); WRITE_ENUM_FIELD(coerceformat, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -922,6 +939,7 @@ _outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node) WRITE_NODE_FIELD(arg); WRITE_OID_FIELD(resulttype); WRITE_ENUM_FIELD(convertformat, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -933,6 +951,7 @@ _outCaseExpr(StringInfo str, CaseExpr *node) WRITE_NODE_FIELD(arg); WRITE_NODE_FIELD(args); WRITE_NODE_FIELD(defresult); + WRITE_LOCATION_FIELD(location); } static void @@ -942,6 +961,7 @@ _outCaseWhen(StringInfo str, CaseWhen *node) WRITE_NODE_FIELD(expr); WRITE_NODE_FIELD(result); + WRITE_LOCATION_FIELD(location); } static void @@ -962,6 +982,7 @@ _outArrayExpr(StringInfo str, ArrayExpr *node) WRITE_OID_FIELD(element_typeid); WRITE_NODE_FIELD(elements); WRITE_BOOL_FIELD(multidims); + WRITE_LOCATION_FIELD(location); } static void @@ -972,6 +993,7 @@ _outRowExpr(StringInfo str, RowExpr *node) WRITE_NODE_FIELD(args); WRITE_OID_FIELD(row_typeid); WRITE_ENUM_FIELD(row_format, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -993,6 +1015,7 @@ _outCoalesceExpr(StringInfo str, CoalesceExpr *node) WRITE_OID_FIELD(coalescetype); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -1003,6 +1026,7 @@ _outMinMaxExpr(StringInfo str, MinMaxExpr *node) WRITE_OID_FIELD(minmaxtype); WRITE_ENUM_FIELD(op, MinMaxOp); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -1018,6 +1042,7 @@ _outXmlExpr(StringInfo str, XmlExpr *node) WRITE_ENUM_FIELD(xmloption, XmlOptionType); WRITE_OID_FIELD(type); WRITE_INT_FIELD(typmod); + WRITE_LOCATION_FIELD(location); } static void @@ -1030,6 +1055,7 @@ _outNullIfExpr(StringInfo str, NullIfExpr *node) WRITE_OID_FIELD(opresulttype); WRITE_BOOL_FIELD(opretset); WRITE_NODE_FIELD(args); + WRITE_LOCATION_FIELD(location); } static void @@ -1059,6 +1085,7 @@ _outCoerceToDomain(StringInfo str, CoerceToDomain *node) WRITE_OID_FIELD(resulttype); WRITE_INT_FIELD(resulttypmod); WRITE_ENUM_FIELD(coercionformat, CoercionForm); + WRITE_LOCATION_FIELD(location); } static void @@ -1068,6 +1095,7 @@ _outCoerceToDomainValue(StringInfo str, CoerceToDomainValue *node) WRITE_OID_FIELD(typeId); WRITE_INT_FIELD(typeMod); + WRITE_LOCATION_FIELD(location); } static void @@ -1077,6 +1105,7 @@ _outSetToDefault(StringInfo str, SetToDefault *node) WRITE_OID_FIELD(typeId); WRITE_INT_FIELD(typeMod); + WRITE_LOCATION_FIELD(location); } static void @@ -1626,7 +1655,7 @@ _outFuncCall(StringInfo str, FuncCall *node) WRITE_BOOL_FIELD(agg_star); WRITE_BOOL_FIELD(agg_distinct); WRITE_BOOL_FIELD(func_variadic); - WRITE_INT_FIELD(location); + WRITE_LOCATION_FIELD(location); } static void @@ -1656,6 +1685,7 @@ _outXmlSerialize(StringInfo str, XmlSerialize *node) WRITE_ENUM_FIELD(xmloption, XmlOptionType); WRITE_NODE_FIELD(expr); WRITE_NODE_FIELD(typename); + WRITE_LOCATION_FIELD(location); } static void @@ -1685,7 +1715,7 @@ _outTypeName(StringInfo str, TypeName *node) WRITE_NODE_FIELD(typmods); WRITE_INT_FIELD(typemod); WRITE_NODE_FIELD(arrayBounds); - WRITE_INT_FIELD(location); + WRITE_LOCATION_FIELD(location); } static void @@ -1695,6 +1725,7 @@ _outTypeCast(StringInfo str, TypeCast *node) WRITE_NODE_FIELD(arg); WRITE_NODE_FIELD(typename); + WRITE_LOCATION_FIELD(location); } static void @@ -1892,7 +1923,7 @@ _outAExpr(StringInfo str, A_Expr *node) WRITE_NODE_FIELD(lexpr); WRITE_NODE_FIELD(rexpr); - WRITE_INT_FIELD(location); + WRITE_LOCATION_FIELD(location); } static void @@ -1936,7 +1967,7 @@ _outColumnRef(StringInfo str, ColumnRef *node) WRITE_NODE_TYPE("COLUMNREF"); WRITE_NODE_FIELD(fields); - WRITE_INT_FIELD(location); + WRITE_LOCATION_FIELD(location); } static void @@ -1945,6 +1976,7 @@ _outParamRef(StringInfo str, ParamRef *node) WRITE_NODE_TYPE("PARAMREF"); WRITE_INT_FIELD(number); + WRITE_LOCATION_FIELD(location); } static void @@ -1954,6 +1986,7 @@ _outAConst(StringInfo str, A_Const *node) appendStringInfo(str, " :val "); _outValue(str, &(node->val)); + WRITE_LOCATION_FIELD(location); } static void @@ -1980,6 +2013,7 @@ _outA_ArrayExpr(StringInfo str, A_ArrayExpr *node) WRITE_NODE_TYPE("A_ARRAYEXPR"); WRITE_NODE_FIELD(elements); + WRITE_LOCATION_FIELD(location); } static void @@ -1990,7 +2024,7 @@ _outResTarget(StringInfo str, ResTarget *node) WRITE_STRING_FIELD(name); WRITE_NODE_FIELD(indirection); WRITE_NODE_FIELD(val); - WRITE_INT_FIELD(location); + WRITE_LOCATION_FIELD(location); } static void diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index c46593d22c..ee363502f6 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.212 2008/08/07 01:11:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.213 2008/08/28 23:09:46 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -16,6 +16,12 @@ * claimed to read them, but it was broken as well as unused.) We * never read executor state trees, either. * + * Parse location fields are written out by outfuncs.c, but only for + * possible debugging use. When reading a location field, we discard + * the stored value and set the location field to -1 (ie, "unknown"). + * This is because nodes coming from a stored rule should not be thought + * to have a known location in the current query's text. + * *------------------------------------------------------------------------- */ #include "postgres.h" @@ -97,6 +103,12 @@ token = pg_strtok(&length); /* get field value */ \ local_node->fldname = nullable_string(token, length) +/* Read a parse location field (and throw away the value, per notes above) */ +#define READ_LOCATION_FIELD(fldname) \ + token = pg_strtok(&length); /* skip :fldname */ \ + token = pg_strtok(&length); /* get field value */ \ + local_node->fldname = -1 /* set field to "unknown" */ + /* Read a Node field */ #define READ_NODE_FIELD(fldname) \ token = pg_strtok(&length); /* skip :fldname */ \ @@ -299,6 +311,7 @@ _readVar(void) READ_UINT_FIELD(varlevelsup); READ_UINT_FIELD(varnoold); READ_INT_FIELD(varoattno); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -316,6 +329,7 @@ _readConst(void) READ_INT_FIELD(constlen); READ_BOOL_FIELD(constbyval); READ_BOOL_FIELD(constisnull); + READ_LOCATION_FIELD(location); token = pg_strtok(&length); /* skip :constvalue */ if (local_node->constisnull) @@ -338,6 +352,7 @@ _readParam(void) READ_INT_FIELD(paramid); READ_OID_FIELD(paramtype); READ_INT_FIELD(paramtypmod); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -356,6 +371,7 @@ _readAggref(void) READ_UINT_FIELD(agglevelsup); READ_BOOL_FIELD(aggstar); READ_BOOL_FIELD(aggdistinct); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -392,6 +408,7 @@ _readFuncExpr(void) READ_BOOL_FIELD(funcretset); READ_ENUM_FIELD(funcformat, CoercionForm); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -420,6 +437,7 @@ _readOpExpr(void) READ_OID_FIELD(opresulttype); READ_BOOL_FIELD(opretset); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -448,6 +466,7 @@ _readDistinctExpr(void) READ_OID_FIELD(opresulttype); READ_BOOL_FIELD(opretset); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -475,6 +494,7 @@ _readScalarArrayOpExpr(void) READ_BOOL_FIELD(useOr); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -500,6 +520,7 @@ _readBoolExpr(void) elog(ERROR, "unrecognized boolop \"%.*s\"", length, token); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -516,6 +537,7 @@ _readSubLink(void) READ_NODE_FIELD(testexpr); READ_NODE_FIELD(operName); READ_NODE_FIELD(subselect); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -568,6 +590,7 @@ _readRelabelType(void) READ_OID_FIELD(resulttype); READ_INT_FIELD(resulttypmod); READ_ENUM_FIELD(relabelformat, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -583,6 +606,7 @@ _readCoerceViaIO(void) READ_NODE_FIELD(arg); READ_OID_FIELD(resulttype); READ_ENUM_FIELD(coerceformat, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -601,6 +625,7 @@ _readArrayCoerceExpr(void) READ_INT_FIELD(resulttypmod); READ_BOOL_FIELD(isExplicit); READ_ENUM_FIELD(coerceformat, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -616,6 +641,7 @@ _readConvertRowtypeExpr(void) READ_NODE_FIELD(arg); READ_OID_FIELD(resulttype); READ_ENUM_FIELD(convertformat, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -632,6 +658,7 @@ _readCaseExpr(void) READ_NODE_FIELD(arg); READ_NODE_FIELD(args); READ_NODE_FIELD(defresult); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -646,6 +673,7 @@ _readCaseWhen(void) READ_NODE_FIELD(expr); READ_NODE_FIELD(result); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -676,6 +704,7 @@ _readArrayExpr(void) READ_OID_FIELD(element_typeid); READ_NODE_FIELD(elements); READ_BOOL_FIELD(multidims); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -691,6 +720,7 @@ _readRowExpr(void) READ_NODE_FIELD(args); READ_OID_FIELD(row_typeid); READ_ENUM_FIELD(row_format, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -722,6 +752,7 @@ _readCoalesceExpr(void) READ_OID_FIELD(coalescetype); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -737,6 +768,7 @@ _readMinMaxExpr(void) READ_OID_FIELD(minmaxtype); READ_ENUM_FIELD(op, MinMaxOp); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -757,6 +789,7 @@ _readXmlExpr(void) READ_ENUM_FIELD(xmloption, XmlOptionType); READ_OID_FIELD(type); READ_INT_FIELD(typmod); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -785,6 +818,7 @@ _readNullIfExpr(void) READ_OID_FIELD(opresulttype); READ_BOOL_FIELD(opretset); READ_NODE_FIELD(args); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -829,6 +863,7 @@ _readCoerceToDomain(void) READ_OID_FIELD(resulttype); READ_INT_FIELD(resulttypmod); READ_ENUM_FIELD(coercionformat, CoercionForm); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -843,6 +878,7 @@ _readCoerceToDomainValue(void) READ_OID_FIELD(typeId); READ_INT_FIELD(typeMod); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -857,6 +893,7 @@ _readSetToDefault(void) READ_OID_FIELD(typeId); READ_INT_FIELD(typeMod); + READ_LOCATION_FIELD(location); READ_DONE(); } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a0ca92bd73..1a79c96dba 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.246 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.247 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1949,6 +1949,7 @@ get_switched_clauses(List *clauses, Relids outerrelids) temp->opresulttype = clause->opresulttype; temp->opretset = clause->opretset; temp->args = list_copy(clause->args); + temp->location = clause->location; /* Commute it --- note this modifies the temp node in-place. */ CommuteOpExpr(temp); t_list = lappend(t_list, temp); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 42ac74e1a2..fe8be5b1bb 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.139 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.140 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,6 +140,7 @@ replace_outer_var(PlannerInfo *root, Var *var) retval->paramid = i; retval->paramtype = var->vartype; retval->paramtypmod = var->vartypmod; + retval->location = -1; return retval; } @@ -179,6 +180,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg) retval->paramid = i; retval->paramtype = agg->aggtype; retval->paramtypmod = -1; + retval->location = -1; return retval; } @@ -199,6 +201,7 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod) retval->paramid = list_length(root->glob->paramlist); retval->paramtype = paramtype; retval->paramtypmod = paramtypmod; + retval->location = -1; pitem = makeNode(PlannerParamItem); pitem->item = (Node *) retval; diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index f7a5405659..c87bb00381 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -25,7 +25,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.58 2008/01/01 19:45:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.59 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -219,6 +219,7 @@ push_nots(Expr *qual) newopexpr->opresulttype = opexpr->opresulttype; newopexpr->opretset = opexpr->opretset; newopexpr->args = opexpr->args; + newopexpr->location = opexpr->location; return (Expr *) newopexpr; } else @@ -243,6 +244,7 @@ push_nots(Expr *qual) newopexpr->opfuncid = InvalidOid; newopexpr->useOr = !saopexpr->useOr; newopexpr->args = saopexpr->args; + newopexpr->location = saopexpr->location; return (Expr *) newopexpr; } else diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index de0218748d..08b70c8ee5 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -16,7 +16,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.90 2008/06/19 00:46:04 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.91 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -292,6 +292,7 @@ expand_targetlist(List *tlist, int command_type, InvalidOid, -1, atttype, COERCE_IMPLICIT_CAST, + -1, false, false); } diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index c07ca4434a..7dc274797e 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.154 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.155 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1410,6 +1410,7 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context) r->arg = (Expr *) var; r->resulttype = context->parent_reltype; r->convertformat = COERCE_IMPLICIT_CAST; + r->location = -1; /* Make sure the Var node has the right type ID, too */ var->vartype = context->child_reltype; return (Node *) r; @@ -1428,6 +1429,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context) rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; + rowexpr->location = -1; + return (Node *) rowexpr; } } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 55bafa2c96..254b86e0d9 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.265 2008/08/26 02:16:31 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.266 2008/08/28 23:09:46 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -135,6 +135,7 @@ make_opclause(Oid opno, Oid opresulttype, bool opretset, expr->args = list_make2(leftop, rightop); else expr->args = list_make1(leftop); + expr->location = -1; return (Expr *) expr; } @@ -201,6 +202,7 @@ make_notclause(Expr *notclause) expr->boolop = NOT_EXPR; expr->args = list_make1(notclause); + expr->location = -1; return (Expr *) expr; } @@ -244,6 +246,7 @@ make_orclause(List *orclauses) expr->boolop = OR_EXPR; expr->args = orclauses; + expr->location = -1; return (Expr *) expr; } @@ -277,6 +280,7 @@ make_andclause(List *andclauses) expr->boolop = AND_EXPR; expr->args = andclauses; + expr->location = -1; return (Expr *) expr; } @@ -2014,6 +2018,7 @@ eval_const_expressions_mutator(Node *node, newexpr->funcretset = expr->funcretset; newexpr->funcformat = expr->funcformat; newexpr->args = args; + newexpr->location = expr->location; return (Node *) newexpr; } if (IsA(node, OpExpr)) @@ -2071,6 +2076,7 @@ eval_const_expressions_mutator(Node *node, newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; + newexpr->location = expr->location; return (Node *) newexpr; } if (IsA(node, DistinctExpr)) @@ -2162,6 +2168,7 @@ eval_const_expressions_mutator(Node *node, newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; + newexpr->location = expr->location; return (Node *) newexpr; } if (IsA(node, BoolExpr)) @@ -2291,6 +2298,7 @@ eval_const_expressions_mutator(Node *node, newrelabel->resulttype = relabel->resulttype; newrelabel->resulttypmod = relabel->resulttypmod; newrelabel->relabelformat = relabel->relabelformat; + newrelabel->location = relabel->location; return (Node *) newrelabel; } } @@ -2357,6 +2365,7 @@ eval_const_expressions_mutator(Node *node, newexpr->arg = arg; newexpr->resulttype = expr->resulttype; newexpr->coerceformat = expr->coerceformat; + newexpr->location = expr->location; return (Node *) newexpr; } if (IsA(node, ArrayCoerceExpr)) @@ -2379,6 +2388,7 @@ eval_const_expressions_mutator(Node *node, newexpr->resulttypmod = expr->resulttypmod; newexpr->isExplicit = expr->isExplicit; newexpr->coerceformat = expr->coerceformat; + newexpr->location = expr->location; /* * If constant argument and it's a binary-coercible or immutable @@ -2477,6 +2487,7 @@ eval_const_expressions_mutator(Node *node, newcasewhen->expr = (Expr *) casecond; newcasewhen->result = (Expr *) caseresult; + newcasewhen->location = oldcasewhen->location; newargs = lappend(newargs, newcasewhen); continue; } @@ -2506,6 +2517,7 @@ eval_const_expressions_mutator(Node *node, newcase->arg = (Expr *) newarg; newcase->args = newargs; newcase->defresult = (Expr *) defresult; + newcase->location = caseexpr->location; return (Node *) newcase; } if (IsA(node, CaseTestExpr)) @@ -2545,6 +2557,7 @@ eval_const_expressions_mutator(Node *node, newarray->element_typeid = arrayexpr->element_typeid; newarray->elements = newelems; newarray->multidims = arrayexpr->multidims; + newarray->location = arrayexpr->location; if (all_const) return (Node *) evaluate_expr((Expr *) newarray, @@ -2590,6 +2603,7 @@ eval_const_expressions_mutator(Node *node, newcoalesce = makeNode(CoalesceExpr); newcoalesce->coalescetype = coalesceexpr->coalescetype; newcoalesce->args = newargs; + newcoalesce->location = coalesceexpr->location; return (Node *) newcoalesce; } if (IsA(node, FieldSelect)) @@ -3206,6 +3220,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args, newexpr->funcretset = false; newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */ newexpr->args = args; + newexpr->location = -1; return evaluate_expr((Expr *) newexpr, result_type, result_typmod); } diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 85f34e4942..e9fd15e6f3 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.77 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.78 2008/08/28 23:09:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -624,6 +624,7 @@ flatten_join_alias_vars_mutator(Node *node, rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; + rowexpr->location = -1; return (Node *) rowexpr; } diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 2086c3321f..b513d61c07 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -17,7 +17,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.377 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.378 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,9 +53,8 @@ static List *transformInsertRow(ParseState *pstate, List *exprlist, static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt); static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt); -static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt); -static void getSetColTypes(ParseState *pstate, Node *node, - List **colTypes, List **colTypmods); +static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, + List **colInfo); static void applyColumnNames(List *dst, List *src); static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); static List *transformReturningList(ParseState *pstate, List *returningList); @@ -789,7 +788,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) { Query *qry = makeNode(Query); List *exprsLists = NIL; - List **coltype_lists = NULL; + List **colexprs = NULL; Oid *coltypes = NULL; int sublist_length = -1; List *newExprsLists; @@ -831,8 +830,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) { /* Remember post-transformation length of first sublist */ sublist_length = list_length(sublist); - /* and allocate arrays for column-type info */ - coltype_lists = (List **) palloc0(sublist_length * sizeof(List *)); + /* and allocate arrays for per-column info */ + colexprs = (List **) palloc0(sublist_length * sizeof(List *)); coltypes = (Oid *) palloc0(sublist_length * sizeof(Oid)); } else if (sublist_length != list_length(sublist)) @@ -844,6 +843,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) exprsLists = lappend(exprsLists, sublist); + /* Check for DEFAULT and build per-column expression lists */ i = 0; foreach(lc2, sublist) { @@ -852,8 +852,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) if (IsA(col, SetToDefault)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("DEFAULT can only appear in a VALUES list within INSERT"))); - coltype_lists[i] = lappend_oid(coltype_lists[i], exprType(col)); + errmsg("DEFAULT can only appear in a VALUES list within INSERT"), + parser_errposition(pstate, exprLocation(col)))); + colexprs[i] = lappend(colexprs[i], col); i++; } } @@ -864,7 +865,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) */ for (i = 0; i < sublist_length; i++) { - coltypes[i] = select_common_type(coltype_lists[i], "VALUES"); + coltypes[i] = select_common_type(pstate, colexprs[i], "VALUES", NULL); } newExprsLists = NIL; @@ -985,6 +986,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) int leftmostRTI; Query *leftmostQuery; SetOperationStmt *sostmt; + List *socolinfo; List *intoColNames = NIL; List *sortClause; Node *limitOffset; @@ -1047,7 +1049,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) /* * Recursively transform the components of the tree. */ - sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt); + sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt, + &socolinfo); Assert(sostmt && IsA(sostmt, SetOperationStmt)); qry->setOperations = (Node *) sostmt; @@ -1191,9 +1194,17 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) /* * transformSetOperationTree * Recursively transform leaves and internal nodes of a set-op tree + * + * In addition to returning the transformed node, we return a list of + * expression nodes showing the type, typmod, and location (for error messages) + * of each output column of the set-op node. This is used only during the + * internal recursion of this function. We use SetToDefault nodes for + * this purpose, since they carry exactly the fields needed, but any other + * expression node type would do as well. */ static Node * -transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) +transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, + List **colInfo) { bool isLeaf; @@ -1240,6 +1251,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) char selectName[32]; RangeTblEntry *rte; RangeTblRef *rtr; + ListCell *tl; /* * Transform SelectStmt into a Query. @@ -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) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 39e52099f4..e908750f76 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.619 2008/08/28 23:09:47 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -90,15 +90,15 @@ static bool QueryIsRule = FALSE; /*#define __YYSCLASS*/ static Node *makeColumnRef(char *relname, List *indirection, int location); -static Node *makeTypeCast(Node *arg, TypeName *typename); -static Node *makeStringConst(char *str); -static Node *makeStringConstCast(char *str, TypeName *typename); -static Node *makeIntConst(int val); -static Node *makeFloatConst(char *str); -static Node *makeBitStringConst(char *str); -static Node *makeNullAConst(void); -static Node *makeAConst(Value *v); -static Node *makeBoolAConst(bool state); +static Node *makeTypeCast(Node *arg, TypeName *typename, int location); +static Node *makeStringConst(char *str, int location); +static Node *makeStringConstCast(char *str, int location, TypeName *typename); +static Node *makeIntConst(int val, int location); +static Node *makeFloatConst(char *str, int location); +static Node *makeBitStringConst(char *str, int location); +static Node *makeNullAConst(int location); +static Node *makeAConst(Value *v, int location); +static Node *makeBoolAConst(bool state, int location); static FuncCall *makeOverlaps(List *largs, List *rargs, int location); static void check_qualified_name(List *names); static List *check_func_name(List *names); @@ -110,8 +110,9 @@ static void insertSelectOptions(SelectStmt *stmt, static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); static Node *doNegate(Node *n, int location); static void doNegateFloat(Value *v); -static Node *makeAArrayExpr(List *elements); -static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args); +static Node *makeAArrayExpr(List *elements, int location); +static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, + List *args, int location); static List *mergeTableFuncParameters(List *func_args, List *columns); static TypeName *TableFuncTypeName(List *columns); @@ -1117,7 +1118,7 @@ set_rest: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "client_encoding"; if ($2 != NULL) - n->args = list_make1(makeStringConst($2)); + n->args = list_make1(makeStringConst($2, @2)); else n->kind = VAR_SET_DEFAULT; $$ = n; @@ -1127,7 +1128,7 @@ set_rest: /* Generic SET syntaxes: */ VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_SET_VALUE; n->name = "role"; - n->args = list_make1(makeStringConst($2)); + n->args = list_make1(makeStringConst($2, @2)); $$ = n; } | SESSION AUTHORIZATION ColId_or_Sconst @@ -1135,7 +1136,7 @@ set_rest: /* Generic SET syntaxes: */ VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_SET_VALUE; n->name = "session_authorization"; - n->args = list_make1(makeStringConst($3)); + n->args = list_make1(makeStringConst($3, @3)); $$ = n; } | SESSION AUTHORIZATION DEFAULT @@ -1150,7 +1151,7 @@ set_rest: /* Generic SET syntaxes: */ VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_SET_VALUE; n->name = "xmloption"; - n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT")); + n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3)); $$ = n; } ; @@ -1168,11 +1169,11 @@ var_list: var_value { $$ = list_make1($1); } ; var_value: opt_boolean - { $$ = makeStringConst($1); } + { $$ = makeStringConst($1, @1); } | ColId_or_Sconst - { $$ = makeStringConst($1); } + { $$ = makeStringConst($1, @1); } | NumericOnly - { $$ = makeAConst($1); } + { $$ = makeAConst($1, @1); } ; iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; } @@ -1199,11 +1200,11 @@ opt_boolean: zone_value: Sconst { - $$ = makeStringConst($1); + $$ = makeStringConst($1, @1); } | IDENT { - $$ = makeStringConst($1); + $$ = makeStringConst($1, @1); } | ConstInterval Sconst opt_interval { @@ -1214,9 +1215,9 @@ zone_value: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("time zone interval must be HOUR or HOUR TO MINUTE"))); - t->typmods = list_make1(makeIntConst($3)); + t->typmods = list_make1(makeIntConst($3, @3)); } - $$ = makeStringConstCast($2, t); + $$ = makeStringConstCast($2, @2, t); } | ConstInterval '(' Iconst ')' Sconst opt_interval { @@ -1226,11 +1227,11 @@ zone_value: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("time zone interval must be HOUR or HOUR TO MINUTE"))); - t->typmods = list_make2(makeIntConst($6), - makeIntConst($3)); - $$ = makeStringConstCast($5, t); + t->typmods = list_make2(makeIntConst($6, @6), + makeIntConst($3, @3)); + $$ = makeStringConstCast($5, @5, t); } - | NumericOnly { $$ = makeAConst($1); } + | NumericOnly { $$ = makeAConst($1, @1); } | DEFAULT { $$ = NULL; } | LOCAL { $$ = NULL; } ; @@ -5274,13 +5275,13 @@ opt_transaction: WORK {} transaction_mode_item: ISOLATION LEVEL iso_level { $$ = makeDefElem("transaction_isolation", - makeStringConst($3)); } + makeStringConst($3, @3)); } | READ ONLY { $$ = makeDefElem("transaction_read_only", - makeIntConst(TRUE)); } + makeIntConst(TRUE, @1)); } | READ WRITE { $$ = makeDefElem("transaction_read_only", - makeIntConst(FALSE)); } + makeIntConst(FALSE, @1)); } ; /* Syntax with commas is SQL-spec, without commas is Postgres historical */ @@ -6461,7 +6462,7 @@ select_limit_value: | ALL { /* LIMIT ALL is represented as a NULL constant */ - $$ = makeNullAConst(); + $$ = makeNullAConst(@1); } ; @@ -6963,13 +6964,13 @@ SimpleTypename: { $$ = $1; if ($2 != INTERVAL_FULL_RANGE) - $$->typmods = list_make1(makeIntConst($2)); + $$->typmods = list_make1(makeIntConst($2, @2)); } | ConstInterval '(' Iconst ')' opt_interval { $$ = $1; - $$->typmods = list_make2(makeIntConst($5), - makeIntConst($3)); + $$->typmods = list_make2(makeIntConst($5, @5), + makeIntConst($3, @3)); } ; @@ -7155,7 +7156,7 @@ BitWithoutLength: else { $$ = SystemTypeName("bit"); - $$->typmods = list_make1(makeIntConst(1)); + $$->typmods = list_make1(makeIntConst(1, -1)); } $$->location = @1; } @@ -7207,7 +7208,7 @@ CharacterWithLength: character '(' Iconst ')' opt_charset } $$ = SystemTypeName($1); - $$->typmods = list_make1(makeIntConst($3)); + $$->typmods = list_make1(makeIntConst($3, @3)); $$->location = @1; } ; @@ -7229,7 +7230,7 @@ CharacterWithoutLength: character opt_charset /* char defaults to char(1), varchar to no limit */ if (strcmp($1, "bpchar") == 0) - $$->typmods = list_make1(makeIntConst(1)); + $$->typmods = list_make1(makeIntConst(1, -1)); $$->location = @1; } @@ -7269,7 +7270,7 @@ ConstDatetime: $$ = SystemTypeName("timestamptz"); else $$ = SystemTypeName("timestamp"); - $$->typmods = list_make1(makeIntConst($3)); + $$->typmods = list_make1(makeIntConst($3, @3)); $$->location = @1; } | TIMESTAMP opt_timezone @@ -7286,7 +7287,7 @@ ConstDatetime: $$ = SystemTypeName("timetz"); else $$ = SystemTypeName("time"); - $$->typmods = list_make1(makeIntConst($3)); + $$->typmods = list_make1(makeIntConst($3, @3)); $$->location = @1; } | TIME opt_timezone @@ -7365,7 +7366,7 @@ opt_interval: */ a_expr: c_expr { $$ = $1; } | a_expr TYPECAST Typename - { $$ = makeTypeCast($1, $3); } + { $$ = makeTypeCast($1, $3, @2); } | a_expr AT TIME ZONE a_expr { FuncCall *n = makeNode(FuncCall); @@ -7480,7 +7481,7 @@ a_expr: c_expr { $$ = $1; } { FuncCall *n = makeNode(FuncCall); n->funcname = SystemFuncName("similar_escape"); - n->args = list_make2($4, makeNullAConst()); + n->args = list_make2($4, makeNullAConst(-1)); n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = FALSE; @@ -7502,7 +7503,7 @@ a_expr: c_expr { $$ = $1; } { FuncCall *n = makeNode(FuncCall); n->funcname = SystemFuncName("similar_escape"); - n->args = list_make2($5, makeNullAConst()); + n->args = list_make2($5, makeNullAConst(-1)); n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = FALSE; @@ -7674,6 +7675,7 @@ a_expr: c_expr { $$ = $1; } n->subLinkType = ANY_SUBLINK; n->testexpr = $1; n->operName = list_make1(makeString("=")); + n->location = @2; $$ = (Node *)n; } else @@ -7693,6 +7695,7 @@ a_expr: c_expr { $$ = $1; } n->subLinkType = ANY_SUBLINK; n->testexpr = $1; n->operName = list_make1(makeString("=")); + n->location = @3; /* Stick a NOT on top */ $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2); } @@ -7709,6 +7712,7 @@ a_expr: c_expr { $$ = $1; } n->testexpr = $1; n->operName = $2; n->subselect = $4; + n->location = @2; $$ = (Node *)n; } | a_expr subquery_Op sub_type '(' a_expr ')' %prec Op @@ -7735,12 +7739,14 @@ a_expr: c_expr { $$ = $1; } } | a_expr IS DOCUMENT_P %prec IS { - $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)); + $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, + list_make1($1), @2); } | a_expr IS NOT DOCUMENT_P %prec IS { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, - makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)), + makeXmlExpr(IS_DOCUMENT, NULL, NIL, + list_make1($1), @2), @2); } ; @@ -7757,7 +7763,7 @@ a_expr: c_expr { $$ = $1; } b_expr: c_expr { $$ = $1; } | b_expr TYPECAST Typename - { $$ = makeTypeCast($1, $3); } + { $$ = makeTypeCast($1, $3, @2); } | '+' b_expr %prec UMINUS { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } | '-' b_expr %prec UMINUS @@ -7805,12 +7811,14 @@ b_expr: c_expr } | b_expr IS DOCUMENT_P %prec IS { - $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)); + $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, + list_make1($1), @2); } | b_expr IS NOT DOCUMENT_P %prec IS { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, - makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)), + makeXmlExpr(IS_DOCUMENT, NULL, NIL, + list_make1($1), @2), @2); } ; @@ -7829,6 +7837,7 @@ c_expr: columnref { $$ = $1; } { ParamRef *p = makeNode(ParamRef); p->number = $1; + p->location = @1; if ($2) { A_Indirection *n = makeNode(A_Indirection); @@ -7862,6 +7871,7 @@ c_expr: columnref { $$ = $1; } n->testexpr = NULL; n->operName = NIL; n->subselect = $1; + n->location = @1; $$ = (Node *)n; } | EXISTS select_with_parens @@ -7871,6 +7881,7 @@ c_expr: columnref { $$ = $1; } n->testexpr = NULL; n->operName = NIL; n->subselect = $2; + n->location = @1; $$ = (Node *)n; } | ARRAY select_with_parens @@ -7880,15 +7891,23 @@ c_expr: columnref { $$ = $1; } n->testexpr = NULL; n->operName = NIL; n->subselect = $2; + n->location = @1; $$ = (Node *)n; } | ARRAY array_expr - { $$ = $2; } + { + A_ArrayExpr *n = (A_ArrayExpr *) $2; + Assert(IsA(n, A_ArrayExpr)); + /* point outermost A_ArrayExpr to the ARRAY keyword */ + n->location = @1; + $$ = (Node *)n; + } | row { RowExpr *r = makeNode(RowExpr); r->args = $1; r->row_typeid = InvalidOid; /* not analyzed yet */ + r->location = @1; $$ = (Node *)r; } ; @@ -8010,8 +8029,8 @@ func_expr: func_name '(' ')' * to rely on it.) */ Node *n; - n = makeStringConstCast("now", SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("date")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); + $$ = makeTypeCast(n, SystemTypeName("date"), -1); } | CURRENT_TIME { @@ -8020,8 +8039,8 @@ func_expr: func_name '(' ')' * See comments for CURRENT_DATE. */ Node *n; - n = makeStringConstCast("now", SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("timetz")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); + $$ = makeTypeCast(n, SystemTypeName("timetz"), -1); } | CURRENT_TIME '(' Iconst ')' { @@ -8031,10 +8050,10 @@ func_expr: func_name '(' ')' */ Node *n; TypeName *d; - n = makeStringConstCast("now", SystemTypeName("text")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); d = SystemTypeName("timetz"); - d->typmods = list_make1(makeIntConst($3)); - $$ = makeTypeCast(n, d); + d->typmods = list_make1(makeIntConst($3, @3)); + $$ = makeTypeCast(n, d, -1); } | CURRENT_TIMESTAMP { @@ -8059,10 +8078,10 @@ func_expr: func_name '(' ')' */ Node *n; TypeName *d; - n = makeStringConstCast("now", SystemTypeName("text")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); d = SystemTypeName("timestamptz"); - d->typmods = list_make1(makeIntConst($3)); - $$ = makeTypeCast(n, d); + d->typmods = list_make1(makeIntConst($3, @3)); + $$ = makeTypeCast(n, d, -1); } | LOCALTIME { @@ -8071,8 +8090,8 @@ func_expr: func_name '(' ')' * See comments for CURRENT_DATE. */ Node *n; - n = makeStringConstCast("now", SystemTypeName("text")); - $$ = makeTypeCast((Node *)n, SystemTypeName("time")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); + $$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1); } | LOCALTIME '(' Iconst ')' { @@ -8082,10 +8101,10 @@ func_expr: func_name '(' ')' */ Node *n; TypeName *d; - n = makeStringConstCast("now", SystemTypeName("text")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); d = SystemTypeName("time"); - d->typmods = list_make1(makeIntConst($3)); - $$ = makeTypeCast((Node *)n, d); + d->typmods = list_make1(makeIntConst($3, @3)); + $$ = makeTypeCast((Node *)n, d, -1); } | LOCALTIMESTAMP { @@ -8094,8 +8113,8 @@ func_expr: func_name '(' ')' * See comments for CURRENT_DATE. */ Node *n; - n = makeStringConstCast("now", SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("timestamp")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); + $$ = makeTypeCast(n, SystemTypeName("timestamp"), -1); } | LOCALTIMESTAMP '(' Iconst ')' { @@ -8105,10 +8124,10 @@ func_expr: func_name '(' ')' */ Node *n; TypeName *d; - n = makeStringConstCast("now", SystemTypeName("text")); + n = makeStringConstCast("now", @1, SystemTypeName("text")); d = SystemTypeName("timestamp"); - d->typmods = list_make1(makeIntConst($3)); - $$ = makeTypeCast(n, d); + d->typmods = list_make1(makeIntConst($3, @3)); + $$ = makeTypeCast(n, d, -1); } | CURRENT_ROLE { @@ -8155,7 +8174,7 @@ func_expr: func_name '(' ')' $$ = (Node *)n; } | CAST '(' a_expr AS Typename ')' - { $$ = makeTypeCast($3, $5); } + { $$ = makeTypeCast($3, $5, @1); } | EXTRACT '(' extract_list ')' { FuncCall *n = makeNode(FuncCall); @@ -8284,6 +8303,7 @@ func_expr: func_name '(' ')' { CoalesceExpr *c = makeNode(CoalesceExpr); c->args = $3; + c->location = @1; $$ = (Node *)c; } | GREATEST '(' expr_list ')' @@ -8291,6 +8311,7 @@ func_expr: func_name '(' ')' MinMaxExpr *v = makeNode(MinMaxExpr); v->args = $3; v->op = IS_GREATEST; + v->location = @1; $$ = (Node *)v; } | LEAST '(' expr_list ')' @@ -8298,52 +8319,54 @@ func_expr: func_name '(' ')' MinMaxExpr *v = makeNode(MinMaxExpr); v->args = $3; v->op = IS_LEAST; + v->location = @1; $$ = (Node *)v; } | XMLCONCAT '(' expr_list ')' { - $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3); + $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1); } | XMLELEMENT '(' NAME_P ColLabel ')' { - $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL); + $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1); } | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')' { - $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL); + $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1); } | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')' { - $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6); + $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1); } | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')' { - $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8); + $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1); } | XMLFOREST '(' xml_attribute_list ')' { - $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL); + $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1); } | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')' { - XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL, - list_make2($4, - makeBoolAConst($5))); + XmlExpr *x = (XmlExpr *) + makeXmlExpr(IS_XMLPARSE, NULL, NIL, + list_make2($4, makeBoolAConst($5, -1)), + @1); x->xmloption = $3; $$ = (Node *)x; } | XMLPI '(' NAME_P ColLabel ')' { - $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL); + $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1); } | XMLPI '(' NAME_P ColLabel ',' a_expr ')' { - $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6)); + $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1); } | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')' { $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL, - list_make3($3, $5, $6)); + list_make3($3, $5, $6), @1); } | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')' { @@ -8351,6 +8374,7 @@ func_expr: func_name '(' ')' n->xmloption = $3; n->expr = $4; n->typename = $6; + n->location = @1; $$ = (Node *)n; } ; @@ -8361,17 +8385,17 @@ func_expr: func_name '(' ')' xml_root_version: VERSION_P a_expr { $$ = $2; } | VERSION_P NO VALUE_P - { $$ = makeNullAConst(); } + { $$ = makeNullAConst(-1); } ; opt_xml_root_standalone: ',' STANDALONE_P YES_P - { $$ = makeIntConst(XML_STANDALONE_YES); } + { $$ = makeIntConst(XML_STANDALONE_YES, -1); } | ',' STANDALONE_P NO - { $$ = makeIntConst(XML_STANDALONE_NO); } + { $$ = makeIntConst(XML_STANDALONE_NO, -1); } | ',' STANDALONE_P NO VALUE_P - { $$ = makeIntConst(XML_STANDALONE_NO_VALUE); } + { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); } | /*EMPTY*/ - { $$ = makeIntConst(XML_STANDALONE_OMITTED); } + { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); } ; xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; } @@ -8495,15 +8519,15 @@ type_list: Typename { $$ = list_make1($1); } array_expr: '[' expr_list ']' { - $$ = makeAArrayExpr($2); + $$ = makeAArrayExpr($2, @1); } | '[' array_expr_list ']' { - $$ = makeAArrayExpr($2); + $$ = makeAArrayExpr($2, @1); } | '[' ']' { - $$ = makeAArrayExpr(NIL); + $$ = makeAArrayExpr(NIL, @1); } ; @@ -8515,7 +8539,7 @@ array_expr_list: array_expr { $$ = list_make1($1); } extract_list: extract_arg FROM a_expr { - $$ = list_make2(makeStringConst($1), $3); + $$ = list_make2(makeStringConst($1, @1), $3); } | /*EMPTY*/ { $$ = NIL; } ; @@ -8599,8 +8623,9 @@ substr_list: * which it is likely to do if the second argument * is unknown or doesn't have an implicit cast to int4. */ - $$ = list_make3($1, makeIntConst(1), - makeTypeCast($2, SystemTypeName("int4"))); + $$ = list_make3($1, makeIntConst(1, -1), + makeTypeCast($2, + SystemTypeName("int4"), -1)); } | expr_list { @@ -8646,6 +8671,7 @@ case_expr: CASE case_arg when_clause_list case_default END_P c->arg = (Expr *) $2; c->args = $3; c->defresult = (Expr *) $4; + c->location = @1; $$ = (Node *)c; } ; @@ -8662,6 +8688,7 @@ when_clause: CaseWhen *w = makeNode(CaseWhen); w->expr = (Expr *) $2; w->result = (Expr *) $4; + w->location = @1; $$ = (Node *)w; } ; @@ -8738,7 +8765,12 @@ opt_asymmetric: ASYMMETRIC ctext_expr: a_expr { $$ = (Node *) $1; } - | DEFAULT { $$ = (Node *) makeNode(SetToDefault); } + | DEFAULT + { + SetToDefault *n = makeNode(SetToDefault); + n->location = @1; + $$ = (Node *) n; + } ; ctext_expr_list: @@ -8911,19 +8943,19 @@ func_name: type_function_name */ AexprConst: Iconst { - $$ = makeIntConst($1); + $$ = makeIntConst($1, @1); } | FCONST { - $$ = makeFloatConst($1); + $$ = makeFloatConst($1, @1); } | Sconst { - $$ = makeStringConst($1); + $$ = makeStringConst($1, @1); } | BCONST { - $$ = makeBitStringConst($1); + $$ = makeBitStringConst($1, @1); } | XCONST { @@ -8932,14 +8964,14 @@ AexprConst: Iconst * a shall not be a * or a . */ - $$ = makeBitStringConst($1); + $$ = makeBitStringConst($1, @1); } | func_name Sconst { /* generic type 'literal' syntax */ TypeName *t = makeTypeNameFromNameList($1); t->location = @1; - $$ = makeStringConstCast($2, t); + $$ = makeStringConstCast($2, @2, t); } | func_name '(' expr_list ')' Sconst { @@ -8947,38 +8979,38 @@ AexprConst: Iconst TypeName *t = makeTypeNameFromNameList($1); t->typmods = $3; t->location = @1; - $$ = makeStringConstCast($5, t); + $$ = makeStringConstCast($5, @5, t); } | ConstTypename Sconst { - $$ = makeStringConstCast($2, $1); + $$ = makeStringConstCast($2, @2, $1); } | ConstInterval Sconst opt_interval { TypeName *t = $1; /* precision is not specified, but fields may be... */ if ($3 != INTERVAL_FULL_RANGE) - t->typmods = list_make1(makeIntConst($3)); - $$ = makeStringConstCast($2, t); + t->typmods = list_make1(makeIntConst($3, @3)); + $$ = makeStringConstCast($2, @2, t); } | ConstInterval '(' Iconst ')' Sconst opt_interval { TypeName *t = $1; - t->typmods = list_make2(makeIntConst($6), - makeIntConst($3)); - $$ = makeStringConstCast($5, t); + t->typmods = list_make2(makeIntConst($6, @6), + makeIntConst($3, @3)); + $$ = makeStringConstCast($5, @5, t); } | TRUE_P { - $$ = makeBoolAConst(TRUE); + $$ = makeBoolAConst(TRUE, @1); } | FALSE_P { - $$ = makeBoolAConst(FALSE); + $$ = makeBoolAConst(FALSE, @1); } | NULL_P { - $$ = makeNullAConst(); + $$ = makeNullAConst(@1); } ; @@ -9522,94 +9554,100 @@ makeColumnRef(char *relname, List *indirection, int location) } static Node * -makeTypeCast(Node *arg, TypeName *typename) +makeTypeCast(Node *arg, TypeName *typename, int location) { TypeCast *n = makeNode(TypeCast); n->arg = arg; n->typename = typename; + n->location = location; return (Node *) n; } static Node * -makeStringConst(char *str) +makeStringConst(char *str, int location) { A_Const *n = makeNode(A_Const); n->val.type = T_String; n->val.val.str = str; + n->location = location; return (Node *)n; } static Node * -makeStringConstCast(char *str, TypeName *typename) +makeStringConstCast(char *str, int location, TypeName *typename) { - Node *s = makeStringConst(str); + Node *s = makeStringConst(str, location); - return makeTypeCast(s, typename); + return makeTypeCast(s, typename, -1); } static Node * -makeIntConst(int val) +makeIntConst(int val, int location) { A_Const *n = makeNode(A_Const); n->val.type = T_Integer; n->val.val.ival = val; + n->location = location; return (Node *)n; } static Node * -makeFloatConst(char *str) +makeFloatConst(char *str, int location) { A_Const *n = makeNode(A_Const); n->val.type = T_Float; n->val.val.str = str; + n->location = location; return (Node *)n; } static Node * -makeBitStringConst(char *str) +makeBitStringConst(char *str, int location) { A_Const *n = makeNode(A_Const); n->val.type = T_BitString; n->val.val.str = str; + n->location = location; return (Node *)n; } static Node * -makeNullAConst(void) +makeNullAConst(int location) { A_Const *n = makeNode(A_Const); n->val.type = T_Null; + n->location = location; return (Node *)n; } static Node * -makeAConst(Value *v) +makeAConst(Value *v, int location) { Node *n; switch (v->type) { case T_Float: - n = makeFloatConst(v->val.str); + n = makeFloatConst(v->val.str, location); break; case T_Integer: - n = makeIntConst(v->val.ival); + n = makeIntConst(v->val.ival, location); break; case T_String: default: - n = makeStringConst(v->val.str); + n = makeStringConst(v->val.str, location); break; } @@ -9620,14 +9658,15 @@ makeAConst(Value *v) * Create an A_Const string node and put it inside a boolean cast. */ static Node * -makeBoolAConst(bool state) +makeBoolAConst(bool state, int location) { A_Const *n = makeNode(A_Const); n->val.type = T_String; n->val.val.str = (state ? "t" : "f"); + n->location = location; - return makeTypeCast((Node *)n, SystemTypeName("bool")); + return makeTypeCast((Node *)n, SystemTypeName("bool"), -1); } /* makeOverlaps() @@ -9799,6 +9838,7 @@ SystemFuncName(char *name) * Build a properly-qualified reference to a built-in type. * * typmod is defaulted, but may be changed afterwards by caller. + * Likewise for the location. */ TypeName * SystemTypeName(char *name) @@ -9827,6 +9867,9 @@ doNegate(Node *n, int location) { A_Const *con = (A_Const *)n; + /* report the constant's location as that of the '-' sign */ + con->location = location; + if (con->val.type == T_Integer) { con->val.val.ival = -con->val.val.ival; @@ -9863,16 +9906,18 @@ doNegateFloat(Value *v) } static Node * -makeAArrayExpr(List *elements) +makeAArrayExpr(List *elements, int location) { A_ArrayExpr *n = makeNode(A_ArrayExpr); n->elements = elements; + n->location = location; return (Node *) n; } static Node * -makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) +makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, + int location) { XmlExpr *x = makeNode(XmlExpr); @@ -9885,6 +9930,9 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) x->named_args = named_args; x->arg_names = NIL; x->args = args; + /* xmloption, if relevant, must be filled in by caller */ + /* type and typmod will be filled in during parse analysis */ + x->location = location; return (Node *) x; } diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index b635c3260c..215557396f 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.81 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -396,6 +396,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramid = -1; argp->paramtype = agg_state_type; argp->paramtypmod = -1; + argp->location = -1; args = list_make1(argp); @@ -406,6 +407,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramid = -1; argp->paramtype = agg_input_types[i]; argp->paramtypmod = -1; + argp->location = -1; args = lappend(args, argp); } @@ -429,6 +431,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramid = -1; argp->paramtype = agg_state_type; argp->paramtypmod = -1; + argp->location = -1; args = list_make1(argp); *finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid, diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index aa0b9fd09e..7097ef5058 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.176 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.177 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -964,9 +964,10 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, outcoltypmod = l_colvar->vartypmod; if (outcoltype != r_colvar->vartype) { - outcoltype = select_common_type(list_make2_oid(l_colvar->vartype, - r_colvar->vartype), - "JOIN/USING"); + outcoltype = select_common_type(pstate, + list_make2(l_colvar, r_colvar), + "JOIN/USING", + NULL); outcoltypmod = -1; /* ie, unknown */ } else if (outcoltypmod != r_colvar->vartypmod) @@ -984,7 +985,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, if (l_colvar->vartype != outcoltype) l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype, outcoltype, outcoltypmod, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); else if (l_colvar->vartypmod != outcoltypmod) l_node = (Node *) makeRelabelType((Expr *) l_colvar, outcoltype, outcoltypmod, @@ -995,7 +996,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, if (r_colvar->vartype != outcoltype) r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype, outcoltype, outcoltypmod, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); else if (r_colvar->vartypmod != outcoltypmod) r_node = (Node *) makeRelabelType((Expr *) r_colvar, outcoltype, outcoltypmod, @@ -1038,6 +1039,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, c->coalescetype = outcoltype; c->args = list_make2(l_node, r_node); + c->location = -1; res_node = (Node *) c; break; } @@ -1239,6 +1241,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause) if (IsA(node, A_Const)) { Value *val = &((A_Const *) node)->val; + int location = ((A_Const *) node)->location; int targetlist_pos = 0; int target_pos; @@ -1247,7 +1250,9 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause) (errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is name of a SQL construct, eg ORDER BY */ errmsg("non-integer constant in %s", - clauseText[clause]))); + clauseText[clause]), + parser_errposition(pstate, location))); + target_pos = intVal(val); foreach(tl, *tlist) { @@ -1263,7 +1268,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause) (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /* translator: %s is name of a SQL construct, eg ORDER BY */ errmsg("%s position %d is not in select list", - clauseText[clause], target_pos))); + clauseText[clause], target_pos), + parser_errposition(pstate, location))); } /* @@ -1590,7 +1596,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle, tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr, restype, TEXTOID, -1, COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); restype = TEXTOID; } @@ -1704,7 +1711,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle, tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr, restype, TEXTOID, -1, COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); restype = TEXTOID; } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 1244498ffb..cd9b7b0cfb 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.164 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,18 +32,20 @@ static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit, - bool hideInputCoercion); + CoercionForm cformat, int location, + bool isExplicit, bool hideInputCoercion); static void hide_coercion_node(Node *node); static Node *build_coercion_expression(Node *node, CoercionPathType pathtype, Oid funcId, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit); + CoercionForm cformat, int location, + bool isExplicit); static Node *coerce_record_to_complex(ParseState *pstate, Node *node, Oid targetTypeId, CoercionContext ccontext, - CoercionForm cformat); + CoercionForm cformat, + int location); /* @@ -65,12 +67,14 @@ static Node *coerce_record_to_complex(ParseState *pstate, Node *node, * targettype - desired result type * targettypmod - desired result typmod * ccontext, cformat - context indicators to control coercions + * location - parse location of the coercion request, or -1 if unknown/implicit */ Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, - CoercionForm cformat) + CoercionForm cformat, + int location) { Node *result; @@ -79,7 +83,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, result = coerce_type(pstate, expr, exprtype, targettype, targettypmod, - ccontext, cformat); + ccontext, cformat, location); /* * If the target is a fixed-length type, it may need a length coercion as @@ -88,7 +92,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, */ result = coerce_type_typmod(result, targettype, targettypmod, - cformat, + cformat, location, (cformat != COERCE_IMPLICIT_CAST), (result != expr && !IsA(result, Const))); @@ -118,7 +122,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Node * coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, - CoercionContext ccontext, CoercionForm cformat) + CoercionContext ccontext, CoercionForm cformat, int location) { Node *result; CoercionPathType pathtype; @@ -195,6 +199,13 @@ coerce_type(ParseState *pstate, Node *node, newcon->constlen = typeLen(targetType); newcon->constbyval = typeByVal(targetType); newcon->constisnull = con->constisnull; + /* Use the leftmost of the constant's and coercion's locations */ + if (location < 0) + newcon->location = con->location; + else if (con->location >= 0 && con->location < location) + newcon->location = con->location; + else + newcon->location = location; /* * We pass typmod -1 to the input routine, primarily because existing @@ -219,7 +230,7 @@ coerce_type(ParseState *pstate, Node *node, result = coerce_to_domain(result, baseTypeId, baseTypeMod, targetTypeId, - cformat, false, false); + cformat, location, false, false); ReleaseSysCache(targetType); @@ -280,6 +291,11 @@ coerce_type(ParseState *pstate, Node *node, */ param->paramtypmod = -1; + /* Use the leftmost of the param's and coercion's locations */ + if (location >= 0 && + (param->location < 0 || location < param->location)) + param->location = location; + return (Node *) param; } pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, @@ -303,7 +319,7 @@ coerce_type(ParseState *pstate, Node *node, result = build_coercion_expression(node, pathtype, funcId, baseTypeId, baseTypeMod, - cformat, + cformat, location, (cformat != COERCE_IMPLICIT_CAST)); /* @@ -314,7 +330,7 @@ coerce_type(ParseState *pstate, Node *node, if (targetTypeId != baseTypeId) result = coerce_to_domain(result, baseTypeId, baseTypeMod, targetTypeId, - cformat, true, + cformat, location, true, exprIsLengthCoercion(result, NULL)); } @@ -330,7 +346,7 @@ coerce_type(ParseState *pstate, Node *node, * then we won't need a RelabelType node. */ result = coerce_to_domain(node, InvalidOid, -1, targetTypeId, - cformat, false, false); + cformat, location, false, false); if (result == node) { /* @@ -339,9 +355,12 @@ coerce_type(ParseState *pstate, Node *node, * later? Would work if both types have same interpretation of * typmod, which is likely but not certain. */ - result = (Node *) makeRelabelType((Expr *) result, - targetTypeId, -1, - cformat); + RelabelType *r = makeRelabelType((Expr *) result, + targetTypeId, -1, + cformat); + + r->location = location; + result = (Node *) r; } } return result; @@ -351,7 +370,7 @@ coerce_type(ParseState *pstate, Node *node, { /* Coerce a RECORD to a specific complex type */ return coerce_record_to_complex(pstate, node, targetTypeId, - ccontext, cformat); + ccontext, cformat, location); } if (targetTypeId == RECORDOID && ISCOMPLEX(inputTypeId)) @@ -372,6 +391,7 @@ coerce_type(ParseState *pstate, Node *node, r->arg = (Expr *) node; r->resulttype = targetTypeId; r->convertformat = cformat; + r->location = location; return (Node *) r; } /* If we get here, caller blew it */ @@ -483,6 +503,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, * has not bothered to look this up) * 'typeId': target type to coerce to * 'cformat': coercion format + * 'location': coercion request location * 'hideInputCoercion': if true, hide the input coercion under this one. * 'lengthCoercionDone': if true, caller already accounted for length, * ie the input is already of baseTypMod as well as baseTypeId. @@ -491,7 +512,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, */ Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, - CoercionForm cformat, bool hideInputCoercion, + CoercionForm cformat, int location, + bool hideInputCoercion, bool lengthCoercionDone) { CoerceToDomain *result; @@ -525,7 +547,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, { if (baseTypeMod >= 0) arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod, - COERCE_IMPLICIT_CAST, + COERCE_IMPLICIT_CAST, location, (cformat != COERCE_IMPLICIT_CAST), false); } @@ -540,6 +562,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, result->resulttype = typeId; result->resulttypmod = -1; /* currently, always -1 for domains */ result->coercionformat = cformat; + result->location = location; return (Node *) result; } @@ -568,8 +591,8 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, */ static Node * coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit, - bool hideInputCoercion) + CoercionForm cformat, int location, + bool isExplicit, bool hideInputCoercion) { CoercionPathType pathtype; Oid funcId; @@ -591,7 +614,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, node = build_coercion_expression(node, pathtype, funcId, targetTypeId, targetTypMod, - cformat, isExplicit); + cformat, location, + isExplicit); } return node; @@ -640,7 +664,8 @@ build_coercion_expression(Node *node, CoercionPathType pathtype, Oid funcId, Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit) + CoercionForm cformat, int location, + bool isExplicit) { int nargs = 0; @@ -677,6 +702,7 @@ build_coercion_expression(Node *node, if (pathtype == COERCION_PATH_FUNC) { /* We build an ordinary FuncExpr with special arguments */ + FuncExpr *fexpr; List *args; Const *cons; @@ -710,7 +736,9 @@ build_coercion_expression(Node *node, args = lappend(args, cons); } - return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat); + fexpr = makeFuncExpr(funcId, targetTypeId, args, cformat); + fexpr->location = location; + return (Node *) fexpr; } else if (pathtype == COERCION_PATH_ARRAYCOERCE) { @@ -729,6 +757,7 @@ build_coercion_expression(Node *node, acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; acoerce->isExplicit = isExplicit; acoerce->coerceformat = cformat; + acoerce->location = location; return (Node *) acoerce; } @@ -742,6 +771,7 @@ build_coercion_expression(Node *node, iocoerce->arg = (Expr *) node; iocoerce->resulttype = targetTypeId; iocoerce->coerceformat = cformat; + iocoerce->location = location; return (Node *) iocoerce; } @@ -765,7 +795,8 @@ static Node * coerce_record_to_complex(ParseState *pstate, Node *node, Oid targetTypeId, CoercionContext ccontext, - CoercionForm cformat) + CoercionForm cformat, + int location) { RowExpr *rowexpr; TupleDesc tupdesc; @@ -799,7 +830,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", format_type_be(RECORDOID), - format_type_be(targetTypeId)))); + format_type_be(targetTypeId)), + parser_coercion_errposition(pstate, location, node))); tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1); newargs = NIL; @@ -808,6 +840,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node, for (i = 0; i < tupdesc->natts; i++) { Node *expr; + Node *cexpr; Oid exprtype; /* Fill in NULLs for dropped columns in rowtype */ @@ -827,17 +860,19 @@ coerce_record_to_complex(ParseState *pstate, Node *node, errmsg("cannot cast type %s to %s", format_type_be(RECORDOID), format_type_be(targetTypeId)), - errdetail("Input has too few columns."))); + errdetail("Input has too few columns."), + parser_coercion_errposition(pstate, location, node))); expr = (Node *) lfirst(arg); exprtype = exprType(expr); - expr = coerce_to_target_type(pstate, - expr, exprtype, - tupdesc->attrs[i]->atttypid, - tupdesc->attrs[i]->atttypmod, - ccontext, - COERCE_IMPLICIT_CAST); - if (expr == NULL) + cexpr = coerce_to_target_type(pstate, + expr, exprtype, + tupdesc->attrs[i]->atttypid, + tupdesc->attrs[i]->atttypmod, + ccontext, + COERCE_IMPLICIT_CAST, + -1); + if (cexpr == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", @@ -846,8 +881,9 @@ coerce_record_to_complex(ParseState *pstate, Node *node, errdetail("Cannot cast type %s to %s in column %d.", format_type_be(exprtype), format_type_be(tupdesc->attrs[i]->atttypid), - ucolno))); - newargs = lappend(newargs, expr); + ucolno), + parser_coercion_errposition(pstate, location, expr))); + newargs = lappend(newargs, cexpr); ucolno++; arg = lnext(arg); } @@ -857,7 +893,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node, errmsg("cannot cast type %s to %s", format_type_be(RECORDOID), format_type_be(targetTypeId)), - errdetail("Input has too many columns."))); + errdetail("Input has too many columns."), + parser_coercion_errposition(pstate, location, node))); ReleaseTupleDesc(tupdesc); @@ -865,6 +902,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node, rowexpr->args = newargs; rowexpr->row_typeid = targetTypeId; rowexpr->row_format = cformat; + rowexpr->location = location; return (Node *) rowexpr; } @@ -886,16 +924,21 @@ coerce_to_boolean(ParseState *pstate, Node *node, if (inputTypeId != BOOLOID) { - node = coerce_to_target_type(pstate, node, inputTypeId, - BOOLOID, -1, - COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); - if (node == NULL) + Node *newnode; + + newnode = coerce_to_target_type(pstate, node, inputTypeId, + BOOLOID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (newnode == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), /* translator: first %s is name of a SQL construct, eg WHERE */ - errmsg("argument of %s must be type boolean, not type %s", - constructName, format_type_be(inputTypeId)))); + errmsg("argument of %s must be type boolean, not type %s", + constructName, format_type_be(inputTypeId)), + parser_errposition(pstate, exprLocation(node)))); + node = newnode; } if (expression_returns_set(node)) @@ -903,7 +946,8 @@ coerce_to_boolean(ParseState *pstate, Node *node, (errcode(ERRCODE_DATATYPE_MISMATCH), /* translator: %s is name of a SQL construct, eg WHERE */ errmsg("argument of %s must not return a set", - constructName))); + constructName), + parser_errposition(pstate, exprLocation(node)))); return node; } @@ -927,18 +971,23 @@ coerce_to_specific_type(ParseState *pstate, Node *node, if (inputTypeId != targetTypeId) { - node = coerce_to_target_type(pstate, node, inputTypeId, - targetTypeId, -1, - COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); - if (node == NULL) + Node *newnode; + + newnode = coerce_to_target_type(pstate, node, inputTypeId, + targetTypeId, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (newnode == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), /* translator: first %s is name of a SQL construct, eg LIMIT */ errmsg("argument of %s must be type %s, not type %s", constructName, format_type_be(targetTypeId), - format_type_be(inputTypeId)))); + format_type_be(inputTypeId)), + parser_errposition(pstate, exprLocation(node)))); + node = newnode; } if (expression_returns_set(node)) @@ -946,32 +995,62 @@ coerce_to_specific_type(ParseState *pstate, Node *node, (errcode(ERRCODE_DATATYPE_MISMATCH), /* translator: %s is name of a SQL construct, eg LIMIT */ errmsg("argument of %s must not return a set", - constructName))); + constructName), + parser_errposition(pstate, exprLocation(node)))); return node; } -/* select_common_type() - * Determine the common supertype of a list of input expression types. +/* + * parser_coercion_errposition - report coercion error location, if possible + * + * We prefer to point at the coercion request (CAST, ::, etc) if possible; + * but there may be no such location in the case of an implicit coercion. + * In that case point at the input expression. + * + * XXX possibly this is more generally useful than coercion errors; + * if so, should rename and place with parser_errposition. + */ +int +parser_coercion_errposition(ParseState *pstate, + int coerce_location, + Node *input_expr) +{ + if (coerce_location >= 0) + return parser_errposition(pstate, coerce_location); + else + return parser_errposition(pstate, exprLocation(input_expr)); +} + + +/* + * select_common_type() + * Determine the common supertype of a list of input expressions. * This is used for determining the output type of CASE and UNION * constructs. * - * 'typeids' is a nonempty list of type OIDs. Note that earlier items + * 'exprs' is a *nonempty* list of expressions. Note that earlier items * in the list will be preferred if there is doubt. * 'context' is a phrase to use in the error message if we fail to select * a usable type. + * 'which_expr': if not NULL, receives a pointer to the particular input + * expression from which the result type was taken. */ Oid -select_common_type(List *typeids, const char *context) +select_common_type(ParseState *pstate, List *exprs, const char *context, + Node **which_expr) { + Node *pexpr; Oid ptype; TYPCATEGORY pcategory; bool pispreferred; - ListCell *type_item; + ListCell *lc; - Assert(typeids != NIL); - ptype = linitial_oid(typeids); + Assert(exprs != NIL); + pexpr = (Node *) linitial(exprs); + lc = lnext(list_head(exprs)); + ptype = exprType(pexpr); /* * If all input types are valid and exactly the same, just pick that type. @@ -980,24 +1059,34 @@ select_common_type(List *typeids, const char *context) */ if (ptype != UNKNOWNOID) { - for_each_cell(type_item, lnext(list_head(typeids))) + for_each_cell(lc, lc) { - Oid ntype = lfirst_oid(type_item); + Node *nexpr = (Node *) lfirst(lc); + Oid ntype = exprType(nexpr); if (ntype != ptype) break; } - if (type_item == NULL) /* got to the end of the list? */ + if (lc == NULL) /* got to the end of the list? */ + { + if (which_expr) + *which_expr = pexpr; return ptype; + } } - /* Nope, so set up for the full algorithm */ + /* + * Nope, so set up for the full algorithm. Note that at this point, + * lc points to the first list item with type different from pexpr's; + * we need not re-examine any items the previous loop advanced over. + */ ptype = getBaseType(ptype); get_type_category_preferred(ptype, &pcategory, &pispreferred); - for_each_cell(type_item, lnext(list_head(typeids))) + for_each_cell(lc, lc) { - Oid ntype = getBaseType(lfirst_oid(type_item)); + Node *nexpr = (Node *) lfirst(lc); + Oid ntype = getBaseType(exprType(nexpr)); /* move on to next one if no new information... */ if (ntype != UNKNOWNOID && ntype != ptype) @@ -1009,6 +1098,7 @@ select_common_type(List *typeids, const char *context) if (ptype == UNKNOWNOID) { /* so far, only unknowns so take anything... */ + pexpr = nexpr; ptype = ntype; pcategory = ncategory; pispreferred = nispreferred; @@ -1020,13 +1110,13 @@ select_common_type(List *typeids, const char *context) */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - /*------ translator: first %s is name of a SQL construct, eg CASE */ errmsg("%s types %s and %s cannot be matched", context, format_type_be(ptype), - format_type_be(ntype)))); + format_type_be(ntype)), + parser_errposition(pstate, exprLocation(nexpr)))); } else if (!pispreferred && can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) && @@ -1036,6 +1126,7 @@ select_common_type(List *typeids, const char *context) * take new type if can coerce to it implicitly but not the * other way; but if we have a preferred type, stay on it. */ + pexpr = nexpr; ptype = ntype; pcategory = ncategory; pispreferred = nispreferred; @@ -1057,10 +1148,13 @@ select_common_type(List *typeids, const char *context) if (ptype == UNKNOWNOID) ptype = TEXTOID; + if (which_expr) + *which_expr = pexpr; return ptype; } -/* coerce_to_common_type() +/* + * coerce_to_common_type() * Coerce an expression to the given type. * * This is used following select_common_type() to coerce the individual @@ -1080,7 +1174,7 @@ coerce_to_common_type(ParseState *pstate, Node *node, return node; /* no work */ if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT)) node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); else ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), @@ -1088,7 +1182,8 @@ coerce_to_common_type(ParseState *pstate, Node *node, errmsg("%s could not convert type %s to %s", context, format_type_be(inputTypeId), - format_type_be(targetTypeId)))); + format_type_be(targetTypeId)), + parser_errposition(pstate, exprLocation(node)))); return node; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 4257b91a8e..3c14cf1b52 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.232 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,8 +63,7 @@ static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, int location); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); -static Node *typecast_expression(ParseState *pstate, Node *expr, - TypeName *typename); +static Node *transformTypeCast(ParseState *pstate, TypeCast *tc); static Node *make_row_comparison_op(ParseState *pstate, List *opname, List *largs, List *rargs, int location); static Node *make_row_distinct_op(ParseState *pstate, List *opname, @@ -123,7 +122,7 @@ transformExpr(ParseState *pstate, Node *expr) A_Const *con = (A_Const *) expr; Value *val = &con->val; - result = (Node *) make_const(val); + result = (Node *) make_const(val, con->location); break; } @@ -145,7 +144,6 @@ transformExpr(ParseState *pstate, Node *expr) case T_TypeCast: { TypeCast *tc = (TypeCast *) expr; - Node *arg; /* * If the subject of the typecast is an ARRAY[] construct @@ -179,8 +177,7 @@ transformExpr(ParseState *pstate, Node *expr) */ } - arg = transformExpr(pstate, tc->arg); - result = typecast_expression(pstate, arg, tc->typename); + result = transformTypeCast(pstate, tc); break; } @@ -425,6 +422,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) strcmp(name, "value") == 0) { node = (Node *) copyObject(pstate->p_value_substitute); + + /* + * Try to propagate location knowledge. This should + * be extended if p_value_substitute can ever take on + * other node types. + */ + if (IsA(node, CoerceToDomainValue)) + ((CoerceToDomainValue *) node)->location = cref->location; break; } @@ -631,6 +636,7 @@ transformParamRef(ParseState *pstate, ParamRef *pref) param->paramid = paramno; param->paramtype = *pptype; param->paramtypmod = -1; + param->location = pref->location; return (Node *) param; } @@ -691,6 +697,7 @@ transformAExprOp(ParseState *pstate, A_Expr *a) s->subLinkType = ROWCOMPARE_SUBLINK; s->testexpr = lexpr; s->operName = a->name; + s->location = a->location; result = transformExpr(pstate, (Node *) s); } else if (lexpr && IsA(lexpr, RowExpr) && @@ -734,7 +741,8 @@ transformAExprAnd(ParseState *pstate, A_Expr *a) rexpr = coerce_to_boolean(pstate, rexpr, "AND"); return (Node *) makeBoolExpr(AND_EXPR, - list_make2(lexpr, rexpr)); + list_make2(lexpr, rexpr), + a->location); } static Node * @@ -747,7 +755,8 @@ transformAExprOr(ParseState *pstate, A_Expr *a) rexpr = coerce_to_boolean(pstate, rexpr, "OR"); return (Node *) makeBoolExpr(OR_EXPR, - list_make2(lexpr, rexpr)); + list_make2(lexpr, rexpr), + a->location); } static Node * @@ -758,7 +767,8 @@ transformAExprNot(ParseState *pstate, A_Expr *a) rexpr = coerce_to_boolean(pstate, rexpr, "NOT"); return (Node *) makeBoolExpr(NOT_EXPR, - list_make1(rexpr)); + list_make1(rexpr), + a->location); } static Node * @@ -849,6 +859,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a) * in a boolean constant node. */ Node *lexpr = transformExpr(pstate, a->lexpr); + Const *result; ListCell *telem; Oid ltype, rtype; @@ -870,7 +881,12 @@ transformAExprOf(ParseState *pstate, A_Expr *a) if (strcmp(strVal(linitial(a->name)), "<>") == 0) matched = (!matched); - return makeBoolConst(matched, false); + result = (Const *) makeBoolConst(matched, false); + + /* Make the result have the original input's parse location */ + result->location = exprLocation((Node *) a); + + return (Node *) result; } static Node * @@ -878,7 +894,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a) { Node *lexpr; List *rexprs; - List *typeids; bool useOr; bool haveRowExpr; Node *result; @@ -903,7 +918,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a) */ lexpr = transformExpr(pstate, a->lexpr); haveRowExpr = (lexpr && IsA(lexpr, RowExpr)); - typeids = list_make1_oid(exprType(lexpr)); rexprs = NIL; foreach(l, (List *) a->rexpr) { @@ -911,7 +925,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a) haveRowExpr |= (rexpr && IsA(rexpr, RowExpr)); rexprs = lappend(rexprs, rexpr); - typeids = lappend_oid(typeids, exprType(rexpr)); } /* @@ -922,6 +935,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a) */ if (!haveRowExpr && list_length(rexprs) != 1) { + List *allexprs; Oid scalar_type; Oid array_type; @@ -929,8 +943,11 @@ transformAExprIn(ParseState *pstate, A_Expr *a) * Select a common type for the array elements. Note that since the * LHS' type is first in the list, it will be preferred when there is * doubt (eg, when all the RHS items are unknown literals). + * + * Note: use list_concat here not lcons, to avoid damaging rexprs. */ - scalar_type = select_common_type(typeids, "IN"); + allexprs = list_concat(list_make1(lexpr), rexprs); + scalar_type = select_common_type(pstate, allexprs, "IN", NULL); /* Do we have an array type to use? */ array_type = get_array_type(scalar_type); @@ -958,6 +975,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a) newa->element_typeid = scalar_type; newa->elements = aexprs; newa->multidims = false; + newa->location = -1; return (Node *) make_scalar_array_op(pstate, a->name, @@ -1003,7 +1021,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a) result = cmp; else result = (Node *) makeBoolExpr(useOr ? OR_EXPR : AND_EXPR, - list_make2(result, cmp)); + list_make2(result, cmp), + a->location); } return result; @@ -1041,7 +1060,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) Node *arg; CaseTestExpr *placeholder; List *newargs; - List *typeids; + List *resultexprs; ListCell *l; Node *defresult; Oid ptype; @@ -1079,7 +1098,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) /* transform the list of arguments */ newargs = NIL; - typeids = NIL; + resultexprs = NIL; foreach(l, c->args) { CaseWhen *w = (CaseWhen *) lfirst(l); @@ -1095,7 +1114,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) placeholder, warg, - -1); + w->location); } neww->expr = (Expr *) transformExpr(pstate, warg); @@ -1105,9 +1124,10 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) warg = (Node *) w->result; neww->result = (Expr *) transformExpr(pstate, warg); + neww->location = w->location; newargs = lappend(newargs, neww); - typeids = lappend_oid(typeids, exprType((Node *) neww->result)); + resultexprs = lappend(resultexprs, neww->result); } newc->args = newargs; @@ -1119,6 +1139,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) A_Const *n = makeNode(A_Const); n->val.type = T_Null; + n->location = -1; defresult = (Node *) n; } newc->defresult = (Expr *) transformExpr(pstate, defresult); @@ -1128,9 +1149,9 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) * determining preferred type. This is how the code worked before, but it * seems a little bogus to me --- tgl */ - typeids = lcons_oid(exprType((Node *) newc->defresult), typeids); + resultexprs = lcons(newc->defresult, resultexprs); - ptype = select_common_type(typeids, "CASE"); + ptype = select_common_type(pstate, resultexprs, "CASE", NULL); Assert(OidIsValid(ptype)); newc->casetype = ptype; @@ -1153,6 +1174,8 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) "CASE/WHEN"); } + newc->location = c->location; + return (Node *) newc; } @@ -1196,13 +1219,15 @@ transformSubLink(ParseState *pstate, SubLink *sublink) ((TargetEntry *) lfirst(tlist_item))->resjunk) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("subquery must return a column"))); + errmsg("subquery must return a column"), + parser_errposition(pstate, sublink->location))); while ((tlist_item = lnext(tlist_item)) != NULL) { if (!((TargetEntry *) lfirst(tlist_item))->resjunk) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("subquery must return only one column"))); + errmsg("subquery must return only one column"), + parser_errposition(pstate, sublink->location))); } /* @@ -1247,6 +1272,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) param->paramid = tent->resno; param->paramtype = exprType((Node *) tent->expr); param->paramtypmod = exprTypmod((Node *) tent->expr); + param->location = -1; right_list = lappend(right_list, param); } @@ -1259,11 +1285,13 @@ transformSubLink(ParseState *pstate, SubLink *sublink) if (list_length(left_list) < list_length(right_list)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("subquery has too many columns"))); + errmsg("subquery has too many columns"), + parser_errposition(pstate, sublink->location))); if (list_length(left_list) > list_length(right_list)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("subquery has too few columns"))); + errmsg("subquery has too few columns"), + parser_errposition(pstate, sublink->location))); /* * Identify the combining operator(s) and generate a suitable @@ -1273,7 +1301,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) sublink->operName, left_list, right_list, - -1); + sublink->location); } return result; @@ -1293,7 +1321,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, ArrayExpr *newa = makeNode(ArrayExpr); List *newelems = NIL; List *newcoercedelems = NIL; - List *typeids = NIL; ListCell *element; Oid coerce_type; bool coerce_hard; @@ -1309,7 +1336,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, { Node *e = (Node *) lfirst(element); Node *newe; - Oid newe_type; /* * If an element is itself an A_ArrayExpr, recurse directly so that @@ -1322,25 +1348,22 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, array_type, element_type, typmod); - newe_type = exprType(newe); /* we certainly have an array here */ - Assert(array_type == InvalidOid || array_type == newe_type); + Assert(array_type == InvalidOid || array_type == exprType(newe)); newa->multidims = true; } else { newe = transformExpr(pstate, e); - newe_type = exprType(newe); /* * Check for sub-array expressions, if we haven't already * found one. */ - if (!newa->multidims && type_is_array(newe_type)) + if (!newa->multidims && type_is_array(exprType(newe))) newa->multidims = true; } newelems = lappend(newelems, newe); - typeids = lappend_oid(typeids, newe_type); } /* @@ -1359,15 +1382,16 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, else { /* Can't handle an empty array without a target type */ - if (typeids == NIL) + if (newelems == NIL) ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_DATATYPE), errmsg("cannot determine type of empty array"), errhint("Explicitly cast to the desired type, " - "for example ARRAY[]::integer[]."))); + "for example ARRAY[]::integer[]."), + parser_errposition(pstate, a->location))); /* Select a common type for the elements */ - coerce_type = select_common_type(typeids, "ARRAY"); + coerce_type = select_common_type(pstate, newelems, "ARRAY", NULL); if (newa->multidims) { @@ -1414,13 +1438,15 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, coerce_type, typmod, COERCION_EXPLICIT, - COERCE_EXPLICIT_CAST); + COERCE_EXPLICIT_CAST, + -1); if (newe == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", format_type_be(exprType(e)), - format_type_be(coerce_type)))); + format_type_be(coerce_type)), + parser_errposition(pstate, exprLocation(e)))); } else newe = coerce_to_common_type(pstate, e, @@ -1432,6 +1458,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, newa->array_typeid = array_type; newa->element_typeid = element_type; newa->elements = newcoercedelems; + newa->location = a->location; return (Node *) newa; } @@ -1447,6 +1474,7 @@ transformRowExpr(ParseState *pstate, RowExpr *r) /* Barring later casting, we consider the type RECORD */ newr->row_typeid = RECORDOID; newr->row_format = COERCE_IMPLICIT_CAST; + newr->location = r->location; return (Node *) newr; } @@ -1457,7 +1485,6 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c) CoalesceExpr *newc = makeNode(CoalesceExpr); List *newargs = NIL; List *newcoercedargs = NIL; - List *typeids = NIL; ListCell *args; foreach(args, c->args) @@ -1467,10 +1494,9 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c) newe = transformExpr(pstate, e); newargs = lappend(newargs, newe); - typeids = lappend_oid(typeids, exprType(newe)); } - newc->coalescetype = select_common_type(typeids, "COALESCE"); + newc->coalescetype = select_common_type(pstate, newargs, "COALESCE", NULL); /* Convert arguments if necessary */ foreach(args, newargs) @@ -1485,6 +1511,7 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c) } newc->args = newcoercedargs; + newc->location = c->location; return (Node *) newc; } @@ -1494,7 +1521,7 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m) MinMaxExpr *newm = makeNode(MinMaxExpr); List *newargs = NIL; List *newcoercedargs = NIL; - List *typeids = NIL; + const char *funcname = (m->op == IS_GREATEST) ? "GREATEST" : "LEAST"; ListCell *args; newm->op = m->op; @@ -1505,10 +1532,9 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m) newe = transformExpr(pstate, e); newargs = lappend(newargs, newe); - typeids = lappend_oid(typeids, exprType(newe)); } - newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST"); + newm->minmaxtype = select_common_type(pstate, newargs, funcname, NULL); /* Convert arguments if necessary */ foreach(args, newargs) @@ -1518,11 +1544,12 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m) newe = coerce_to_common_type(pstate, e, newm->minmaxtype, - "GREATEST/LEAST"); + funcname); newcoercedargs = lappend(newcoercedargs, newe); } newm->args = newcoercedargs; + newm->location = m->location; return (Node *) newm; } @@ -1538,6 +1565,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x) newx->name = map_sql_identifier_to_xml_name(x->name, false, false); else newx->name = NULL; + newx->xmloption = x->xmloption; + newx->location = x->location; /* * gram.y built the named args as a list of ResTarget. Transform each, @@ -1566,33 +1595,32 @@ 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 */ } + /* reject duplicate argnames in XMLELEMENT only */ + if (x->op == IS_XMLELEMENT) + { + ListCell *lc2; + + foreach(lc2, newx->arg_names) + { + if (strcmp(argname, strVal(lfirst(lc2))) == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + 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)); } - newx->xmloption = x->xmloption; - - if (x->op == IS_XMLELEMENT) - { - foreach(lc, newx->arg_names) - { - ListCell *lc2; - - for_each_cell(lc2, lnext(lc)) - { - if (strcmp(strVal(lfirst(lc)), strVal(lfirst(lc2))) == 0) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("XML attribute name \"%s\" appears more than once", strVal(lfirst(lc))))); - } - } - } - /* The other arguments are of varying types depending on the function */ newx->args = NIL; i = 0; @@ -1639,6 +1667,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x) break; case IS_XMLSERIALIZE: /* not handled here */ + Assert(false); break; case IS_DOCUMENT: newe = coerce_to_specific_type(pstate, newe, XMLOID, @@ -1655,9 +1684,10 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x) static Node * transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) { + Node *result; + XmlExpr *xexpr; Oid targetType; int32 targetTypmod; - XmlExpr *xexpr; xexpr = makeNode(XmlExpr); xexpr->op = IS_XMLSERIALIZE; @@ -1669,6 +1699,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) targetType = typenameTypeId(pstate, xs->typename, &targetTypmod); xexpr->xmloption = xs->xmloption; + xexpr->location = xs->location; /* We actually only need these to be able to parse back the expression. */ xexpr->type = targetType; xexpr->typmod = targetTypmod; @@ -1679,8 +1710,18 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) * from text. This way, user-defined text-like data types automatically * fit in. */ - return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); + result = coerce_to_target_type(pstate, (Node *) xexpr, + TEXTOID, targetType, targetTypmod, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); + if (result == NULL) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast XMLSERIALIZE result to %s", + format_type_be(targetType)), + parser_errposition(pstate, xexpr->location))); + return result; } static Node * @@ -1773,7 +1814,7 @@ static Node * transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, int location) { - Node *result; + Var *result; RangeTblEntry *rte; int vnum; int sublevels_up; @@ -1800,22 +1841,22 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, if (!OidIsValid(toid)) elog(ERROR, "could not find type OID for relation %u", rte->relid); - result = (Node *) makeVar(vnum, - InvalidAttrNumber, - toid, - -1, - sublevels_up); + result = makeVar(vnum, + InvalidAttrNumber, + toid, + -1, + sublevels_up); break; case RTE_FUNCTION: toid = exprType(rte->funcexpr); if (type_is_rowtype(toid)) { /* func returns composite; same as relation case */ - result = (Node *) makeVar(vnum, - InvalidAttrNumber, - toid, - -1, - sublevels_up); + result = makeVar(vnum, + InvalidAttrNumber, + toid, + -1, + sublevels_up); } else { @@ -1825,21 +1866,21 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, * seems a tad inconsistent, especially if "f.*" was * explicitly written ...) */ - result = (Node *) makeVar(vnum, - 1, - toid, - -1, - sublevels_up); + result = makeVar(vnum, + 1, + toid, + -1, + sublevels_up); } break; case RTE_VALUES: toid = RECORDOID; /* returns composite; same as relation case */ - result = (Node *) makeVar(vnum, - InvalidAttrNumber, - toid, - -1, - sublevels_up); + result = makeVar(vnum, + InvalidAttrNumber, + toid, + -1, + sublevels_up); break; default: @@ -1849,48 +1890,64 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, * expanded to a RowExpr during planning, but that is not our * concern here.) */ - result = (Node *) makeVar(vnum, - InvalidAttrNumber, - RECORDOID, - -1, - sublevels_up); + result = makeVar(vnum, + InvalidAttrNumber, + RECORDOID, + -1, + sublevels_up); break; } - return result; + /* location is not filled in by makeVar */ + result->location = location; + + return (Node *) result; } /* * Handle an explicit CAST construct. * - * The given expr has already been transformed, but we need to lookup - * the type name and then apply any necessary coercion function(s). + * Transform the argument, then look up the type name and apply any necessary + * coercion function(s). */ static Node * -typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) +transformTypeCast(ParseState *pstate, TypeCast *tc) { + Node *result; + Node *expr = transformExpr(pstate, tc->arg); Oid inputType = exprType(expr); Oid targetType; int32 targetTypmod; + int location; - targetType = typenameTypeId(pstate, typename, &targetTypmod); + targetType = typenameTypeId(pstate, tc->typename, &targetTypmod); if (inputType == InvalidOid) return expr; /* do nothing if NULL input */ - expr = coerce_to_target_type(pstate, expr, inputType, - targetType, targetTypmod, - COERCION_EXPLICIT, - COERCE_EXPLICIT_CAST); - if (expr == NULL) + /* + * Location of the coercion is preferentially the location of the :: or + * CAST symbol, but if there is none then use the location of the type + * name (this can happen in TypeName 'string' syntax, for instance). + */ + location = tc->location; + if (location < 0) + location = tc->typename->location; + + result = coerce_to_target_type(pstate, expr, inputType, + targetType, targetTypmod, + COERCION_EXPLICIT, + COERCE_EXPLICIT_CAST, + location); + if (result == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", format_type_be(inputType), format_type_be(targetType)), - parser_errposition(pstate, typename->location))); + parser_coercion_errposition(pstate, location, expr))); - return expr; + return result; } /* @@ -2043,9 +2100,9 @@ make_row_comparison_op(ParseState *pstate, List *opname, * the system thinks BoolExpr is N-argument anyway. */ if (rctype == ROWCOMPARE_EQ) - return (Node *) makeBoolExpr(AND_EXPR, opexprs); + return (Node *) makeBoolExpr(AND_EXPR, opexprs, location); if (rctype == ROWCOMPARE_NE) - return (Node *) makeBoolExpr(OR_EXPR, opexprs); + return (Node *) makeBoolExpr(OR_EXPR, opexprs, location); /* * Otherwise we need to choose exactly which opfamily to associate with @@ -2138,7 +2195,8 @@ make_row_distinct_op(ParseState *pstate, List *opname, result = cmp; else result = (Node *) makeBoolExpr(OR_EXPR, - list_make2(result, cmp)); + list_make2(result, cmp), + location); } if (result == NULL) diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index b1de6264aa..31317800c1 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.205 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -173,7 +173,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, */ return coerce_type(pstate, linitial(fargs), actual_arg_types[0], rettype, -1, - COERCION_EXPLICIT, COERCE_EXPLICIT_CALL); + COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); } else if (fdresult == FUNCDETAIL_NORMAL) { @@ -272,6 +272,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, errmsg("could not find array type for data type %s", format_type_be(newa->element_typeid)))); newa->multidims = false; + newa->location = exprLocation((Node *) vargs); fargs = lappend(fargs, newa); } @@ -286,6 +287,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, funcexpr->funcretset = retset; funcexpr->funcformat = COERCE_EXPLICIT_CALL; funcexpr->args = fargs; + funcexpr->location = location; retval = (Node *) funcexpr; } @@ -299,6 +301,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, aggref->args = fargs; aggref->aggstar = agg_star; aggref->aggdistinct = agg_distinct; + aggref->location = location; /* * Reject attempt to call a parameterless aggregate without (*) @@ -1009,7 +1012,8 @@ make_fn_arguments(ParseState *pstate, actual_arg_types[i], declared_arg_types[i], -1, COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); } i++; } diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 8cc531b350..1760e49285 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.101 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -117,8 +117,9 @@ parser_errposition(ParseState *pstate, int location) * Build a Var node for an attribute identified by RTE and attrno */ Var * -make_var(ParseState *pstate, RangeTblEntry *rte, int attrno) +make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location) { + Var *result; int vnum, sublevels_up; Oid vartypeid; @@ -126,7 +127,9 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno) vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod); - return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up); + result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up); + result->location = location; + return result; } /* @@ -243,11 +246,13 @@ transformArraySubscripts(ParseState *pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("array subscript must have type integer"))); + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(ai->lidx)))); } else { @@ -267,11 +272,13 @@ transformArraySubscripts(ParseState *pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("array subscript must have type integer"))); + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(ai->uidx)))); upperIndexpr = lappend(upperIndexpr, subexpr); } @@ -283,20 +290,24 @@ transformArraySubscripts(ParseState *pstate, { Oid typesource = exprType(assignFrom); Oid typeneeded = isSlice ? arrayType : elementType; + Node *newFrom; - assignFrom = coerce_to_target_type(pstate, - assignFrom, typesource, - typeneeded, elementTypMod, - COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); - if (assignFrom == NULL) + newFrom = coerce_to_target_type(pstate, + assignFrom, typesource, + typeneeded, elementTypMod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (newFrom == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("array assignment requires type %s" " but expression is of type %s", format_type_be(typeneeded), format_type_be(typesource)), - errhint("You will need to rewrite or cast the expression."))); + errhint("You will need to rewrite or cast the expression."), + parser_errposition(pstate, exprLocation(assignFrom)))); + assignFrom = newFrom; } /* @@ -333,7 +344,7 @@ transformArraySubscripts(ParseState *pstate, * too many examples that fail if we try. */ Const * -make_const(Value *value) +make_const(Value *value, int location) { Datum val; int64 val64; @@ -423,6 +434,7 @@ make_const(Value *value) (Datum) 0, true, false); + con->location = location; return con; default: @@ -436,6 +448,7 @@ make_const(Value *value) val, false, typebyval); + con->location = location; return con; } diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index f27615603b..0ff5b59d00 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.104 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.105 2008/08/28 23:09:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -857,6 +857,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, result->opresulttype = rettype; result->opretset = get_func_retset(opform->oprcode); result->args = args; + result->location = location; ReleaseSysCache(tup); @@ -984,6 +985,7 @@ make_scalar_array_op(ParseState *pstate, List *opname, result->opfuncid = opform->oprcode; result->useOr = useOr; result->args = args; + result->location = location; ReleaseSysCache(tup); diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 7bd53e2a94..f7eb825f5d 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.133 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -362,7 +362,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname, errmsg("column reference \"%s\" is ambiguous", colname), parser_errposition(pstate, location))); - result = (Node *) make_var(pstate, rte, attnum); + result = (Node *) make_var(pstate, rte, attnum, location); /* Require read access */ rte->requiredPerms |= ACL_SELECT; } @@ -390,7 +390,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname, Int16GetDatum(attnum), 0, 0)) { - result = (Node *) make_var(pstate, rte, attnum); + result = (Node *) make_var(pstate, rte, attnum, location); /* Require read access */ rte->requiredPerms |= ACL_SELECT; } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 70acb8382a..c7758e9add 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.161 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.162 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -318,7 +318,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle, * colname target column name (ie, name of attribute to be assigned to) * attrno target attribute number * indirection subscripts/field names for target column, if any - * location error cursor position, or -1 + * location error cursor position for the target column, or -1 * * Returns the modified expression. */ @@ -403,7 +403,8 @@ transformAssignedExpr(ParseState *pstate, */ colVar = (Node *) make_var(pstate, pstate->p_target_rangetblentry, - attrno); + attrno, + location); } expr = (Expr *) @@ -428,7 +429,8 @@ transformAssignedExpr(ParseState *pstate, (Node *) expr, type_id, attrtype, attrtypmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -677,7 +679,8 @@ transformAssignmentIndirection(ParseState *pstate, rhs, exprType(rhs), targetTypeId, targetTypMod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (result == NULL) { if (targetIsArray) diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 4bab055269..ae3ddeb202 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -19,7 +19,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.15 2008/08/25 22:42:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.16 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -380,9 +380,11 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, snamenode = makeNode(A_Const); snamenode->val.type = T_String; snamenode->val.val.str = qstring; + snamenode->location = -1; castnode = makeNode(TypeCast); castnode->typename = SystemTypeName("regclass"); castnode->arg = (Node *) snamenode; + castnode->location = -1; funccallnode = makeNode(FuncCall); funccallnode->funcname = SystemFuncName("nextval"); funccallnode->args = list_make1(castnode); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 5269fa63cd..a6e01a8b1c 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.178 2008/08/25 22:42:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.179 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -654,6 +654,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation, InvalidOid, -1, att_tup->atttypid, COERCE_IMPLICIT_CAST, + -1, false, false); } @@ -886,7 +887,8 @@ build_column_default(Relation rel, int attrno) expr, exprtype, atttype, atttypmod, COERCION_ASSIGNMENT, - COERCE_IMPLICIT_CAST); + COERCE_IMPLICIT_CAST, + -1); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -993,6 +995,7 @@ rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos) InvalidOid, -1, att_tup->atttypid, COERCE_IMPLICIT_CAST, + -1, false, false); } diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 840118bbf7..f75c1888ab 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.111 2008/08/25 22:42:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.112 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -933,6 +933,7 @@ resolve_one_var(Var *var, ResolveNew_context *context) InvalidOid, -1, var->vartype, COERCE_IMPLICIT_CAST, + -1, false, false); } @@ -989,6 +990,7 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context) rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; + rowexpr->location = -1; return (Node *) rowexpr; } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f5e28069a1..8e287a80db 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.480 2008/08/25 11:18:43 mha Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.481 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200808251 +#define CATALOG_VERSION_NO 200808281 #endif diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index eca8feee97..d8ffa44224 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.61 2008/01/01 19:45:58 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.62 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,7 +49,7 @@ extern Const *makeNullConst(Oid consttype, int32 consttypmod); extern Node *makeBoolConst(bool value, bool isnull); -extern Expr *makeBoolExpr(BoolExprType boolop, List *args); +extern Expr *makeBoolExpr(BoolExprType boolop, List *args, int location); extern Alias *makeAlias(const char *aliasname, List *colnames); diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index f699fc1b68..5ea2efe81e 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.27 2008/08/25 22:42:34 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.28 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,8 @@ extern int32 exprTypmod(Node *expr); extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod); extern bool expression_returns_set(Node *clause); +extern int exprLocation(Node *expr); + extern bool expression_tree_walker(Node *node, bool (*walker) (), void *context); extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (), diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 65c3698a84..6292ca237c 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3,11 +3,17 @@ * parsenodes.h * definitions for parse tree nodes * + * Many of the node types used in parsetrees include a "location" field. + * This is a byte (not character) offset in the original source text, to be + * used for positioning an error cursor when there is an error related to + * the node. Access to the original source text is needed to make use of + * the location. + * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.371 2008/08/07 01:11:51 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.372 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -141,11 +147,6 @@ typedef struct Query * Most of these node types appear in raw parsetrees output by the grammar, * and get transformed to something else by the analyzer. A few of them * are used as-is in transformed querytrees. - * - * Many of the node types used in raw parsetrees include a "location" field. - * This is a byte (not character) offset in the original source text, to be - * used for positioning an error cursor when there is an analysis-time - * error related to the node. ****************************************************************************/ /* @@ -199,6 +200,7 @@ typedef struct ParamRef { NodeTag type; int number; /* the number of the parameter */ + int location; /* token location, or -1 if unknown */ } ParamRef; /* @@ -235,6 +237,7 @@ typedef struct A_Const { NodeTag type; Value val; /* value (includes type info, see value.h) */ + int location; /* token location, or -1 if unknown */ } A_Const; /* @@ -245,6 +248,7 @@ typedef struct TypeCast NodeTag type; Node *arg; /* the expression being casted */ TypeName *typename; /* the target type */ + int location; /* token location, or -1 if unknown */ } TypeCast; /* @@ -305,6 +309,7 @@ typedef struct A_ArrayExpr { NodeTag type; List *elements; /* array element expressions */ + int location; /* token location, or -1 if unknown */ } A_ArrayExpr; /* @@ -459,14 +464,15 @@ typedef struct LockingClause } LockingClause; /* - * XMLSERIALIZE + * XMLSERIALIZE (in raw parse tree only) */ typedef struct XmlSerialize { NodeTag type; - XmlOptionType xmloption; + XmlOptionType xmloption; /* DOCUMENT or CONTENT */ Node *expr; TypeName *typename; + int location; /* token location, or -1 if unknown */ } XmlSerialize; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index f6da1adbfa..e4de091a75 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.139 2008/08/22 00:16:04 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.140 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -138,14 +138,12 @@ typedef struct Var * all */ Oid vartype; /* pg_type OID for the type of this var */ int32 vartypmod; /* pg_attribute typmod value */ - Index varlevelsup; - - /* - * for subquery variables referencing outer relations; 0 in a normal var, - * >0 means N levels up - */ + Index varlevelsup; /* for subquery variables referencing outer + * relations; 0 in a normal var, >0 means N + * levels up */ Index varnoold; /* original value of varno, for debugging */ AttrNumber varoattno; /* original value of varattno */ + int location; /* token location, or -1 if unknown */ } Var; /* @@ -164,6 +162,7 @@ typedef struct Const * If true, then all the information is stored * in the Datum. If false, then the Datum * contains a pointer to the information. */ + int location; /* token location, or -1 if unknown */ } Const; /* ---------------- @@ -204,6 +203,7 @@ typedef struct Param int paramid; /* numeric ID for parameter */ Oid paramtype; /* pg_type OID of parameter's datatype */ int32 paramtypmod; /* typmod value, if known */ + int location; /* token location, or -1 if unknown */ } Param; /* @@ -218,6 +218,7 @@ typedef struct Aggref Index agglevelsup; /* > 0 if agg belongs to outer query */ bool aggstar; /* TRUE if argument list was really '*' */ bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */ + int location; /* token location, or -1 if unknown */ } Aggref; /* ---------------- @@ -293,6 +294,7 @@ typedef struct FuncExpr bool funcretset; /* true if function returns set */ CoercionForm funcformat; /* how to display this function call */ List *args; /* arguments to the function */ + int location; /* token location, or -1 if unknown */ } FuncExpr; /* @@ -312,6 +314,7 @@ typedef struct OpExpr Oid opresulttype; /* PG_TYPE OID of result value */ bool opretset; /* true if operator returns set */ List *args; /* arguments to the operator (1 or 2) */ + int location; /* token location, or -1 if unknown */ } OpExpr; /* @@ -343,6 +346,7 @@ typedef struct ScalarArrayOpExpr Oid opfuncid; /* PG_PROC OID of underlying function */ bool useOr; /* true for ANY, false for ALL */ List *args; /* the scalar and array operands */ + int location; /* token location, or -1 if unknown */ } ScalarArrayOpExpr; /* @@ -350,9 +354,11 @@ typedef struct ScalarArrayOpExpr * * Notice the arguments are given as a List. For NOT, of course the list * must always have exactly one element. For AND and OR, the executor can - * handle any number of arguments. The parser treats AND and OR as binary - * and so it only produces two-element lists, but the optimizer will flatten - * trees of AND and OR nodes to produce longer lists when possible. + * handle any number of arguments. The parser generally treats AND and OR + * as binary and so it typically only produces two-element lists, but the + * optimizer will flatten trees of AND and OR nodes to produce longer lists + * when possible. There are also a few special cases where more arguments + * can appear before optimization. */ typedef enum BoolExprType { @@ -364,6 +370,7 @@ typedef struct BoolExpr Expr xpr; BoolExprType boolop; List *args; /* arguments to this expression */ + int location; /* token location, or -1 if unknown */ } BoolExpr; /* @@ -423,6 +430,7 @@ typedef struct SubLink Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */ List *operName; /* originally specified operator name */ Node *subselect; /* subselect as Query* or parsetree */ + int location; /* token location, or -1 if unknown */ } SubLink; /* @@ -570,6 +578,7 @@ typedef struct RelabelType Oid resulttype; /* output type of coercion expression */ int32 resulttypmod; /* output typmod (usually -1) */ CoercionForm relabelformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } RelabelType; /* ---------------- @@ -588,6 +597,7 @@ typedef struct CoerceViaIO Oid resulttype; /* output type of coercion */ /* output typmod is not stored, but is presumed -1 */ CoercionForm coerceformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } CoerceViaIO; /* ---------------- @@ -611,6 +621,7 @@ typedef struct ArrayCoerceExpr int32 resulttypmod; /* output typmod (also element typmod) */ bool isExplicit; /* conversion semantics flag to pass to func */ CoercionForm coerceformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } ArrayCoerceExpr; /* ---------------- @@ -632,6 +643,7 @@ typedef struct ConvertRowtypeExpr Oid resulttype; /* output type (always a composite type) */ /* result typmod is not stored, but must be -1; see RowExpr comments */ CoercionForm convertformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } ConvertRowtypeExpr; /*---------- @@ -663,6 +675,7 @@ typedef struct CaseExpr Expr *arg; /* implicit equality comparison argument */ List *args; /* the arguments (list of WHEN clauses) */ Expr *defresult; /* the default result (ELSE clause) */ + int location; /* token location, or -1 if unknown */ } CaseExpr; /* @@ -673,6 +686,7 @@ typedef struct CaseWhen Expr xpr; Expr *expr; /* condition expression */ Expr *result; /* substitution result */ + int location; /* token location, or -1 if unknown */ } CaseWhen; /* @@ -705,6 +719,7 @@ typedef struct ArrayExpr Oid element_typeid; /* common type of array elements */ List *elements; /* the array elements or sub-arrays */ bool multidims; /* true if elements are sub-arrays */ + int location; /* token location, or -1 if unknown */ } ArrayExpr; /* @@ -733,6 +748,7 @@ typedef struct RowExpr * parsetrees. We must assume typmod -1 for a RowExpr node. */ CoercionForm row_format; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } RowExpr; /* @@ -778,6 +794,7 @@ typedef struct CoalesceExpr Expr xpr; Oid coalescetype; /* type of expression result */ List *args; /* the arguments */ + int location; /* token location, or -1 if unknown */ } CoalesceExpr; /* @@ -795,6 +812,7 @@ typedef struct MinMaxExpr Oid minmaxtype; /* common type of arguments and result */ MinMaxOp op; /* function to execute */ List *args; /* the arguments */ + int location; /* token location, or -1 if unknown */ } MinMaxExpr; /* @@ -833,6 +851,7 @@ typedef struct XmlExpr XmlOptionType xmloption; /* DOCUMENT or CONTENT */ Oid type; /* target type for XMLSERIALIZE */ int32 typmod; + int location; /* token location, or -1 if unknown */ } XmlExpr; /* @@ -905,6 +924,7 @@ typedef struct CoerceToDomain Oid resulttype; /* domain type ID (result type) */ int32 resulttypmod; /* output typmod (currently always -1) */ CoercionForm coercionformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ } CoerceToDomain; /* @@ -921,6 +941,7 @@ typedef struct CoerceToDomainValue Expr xpr; Oid typeId; /* type for substituted value */ int32 typeMod; /* typemod for substituted value */ + int location; /* token location, or -1 if unknown */ } CoerceToDomainValue; /* @@ -935,6 +956,7 @@ typedef struct SetToDefault Expr xpr; Oid typeId; /* type for substituted value */ int32 typeMod; /* typemod for substituted value */ + int location; /* token location, or -1 if unknown */ } SetToDefault; /* diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 68d5173378..85485812d8 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.76 2008/07/30 17:05:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.77 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,15 +39,17 @@ extern Node *coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, - CoercionForm cformat); + CoercionForm cformat, + int location); extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, CoercionContext ccontext); extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, - CoercionContext ccontext, CoercionForm cformat); + CoercionContext ccontext, CoercionForm cformat, int location); extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, - CoercionForm cformat, bool hideInputCoercion, + CoercionForm cformat, int location, + bool hideInputCoercion, bool lengthCoercionDone); extern Node *coerce_to_boolean(ParseState *pstate, Node *node, @@ -56,7 +58,12 @@ extern Node *coerce_to_specific_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *constructName); -extern Oid select_common_type(List *typeids, const char *context); +extern int parser_coercion_errposition(ParseState *pstate, + int coerce_location, + Node *input_expr); + +extern Oid select_common_type(ParseState *pstate, List *exprs, + const char *context, Node **which_expr); extern Node *coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context); diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index ed8f7fe3b3..fa6b14d4d3 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.54 2008/06/19 00:46:06 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.55 2008/08/28 23:09:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -86,7 +86,8 @@ extern ParseState *make_parsestate(ParseState *parentParseState); extern void free_parsestate(ParseState *pstate); extern int parser_errposition(ParseState *pstate, int location); -extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno); +extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, + int location); extern Oid transformArrayType(Oid arrayType); extern ArrayRef *transformArraySubscripts(ParseState *pstate, Node *arrayBase, @@ -95,6 +96,6 @@ extern ArrayRef *transformArraySubscripts(ParseState *pstate, int32 elementTypMod, List *indirection, Node *assignFrom); -extern Const *make_const(Value *value); +extern Const *make_const(Value *value, int location); #endif /* PARSE_NODE_H */ diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index bcb451e808..5103d6868d 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -787,6 +787,8 @@ select '{ }}'::text[]; ERROR: malformed array literal: "{ }}" select array[]; ERROR: cannot determine type of empty array +LINE 1: select array[]; + ^ HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[]. -- none of the above should be accepted -- all of the following should be accepted diff --git a/src/test/regress/expected/select_implicit.out b/src/test/regress/expected/select_implicit.out index 1ee7f9b735..14ee2b6205 100644 --- a/src/test/regress/expected/select_implicit.out +++ b/src/test/regress/expected/select_implicit.out @@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1; -- failure expected SELECT c, count(*) FROM test_missing_target GROUP BY 3; ERROR: GROUP BY position 3 is not in select list +LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3; + ^ -- group w/o existing GROUP BY and ORDER BY target under ambiguous condition -- failure expected SELECT count(*) FROM test_missing_target x, test_missing_target y diff --git a/src/test/regress/expected/select_implicit_1.out b/src/test/regress/expected/select_implicit_1.out index 85092ef046..feb33ec576 100644 --- a/src/test/regress/expected/select_implicit_1.out +++ b/src/test/regress/expected/select_implicit_1.out @@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1; -- failure expected SELECT c, count(*) FROM test_missing_target GROUP BY 3; ERROR: GROUP BY position 3 is not in select list +LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3; + ^ -- group w/o existing GROUP BY and ORDER BY target under ambiguous condition -- failure expected SELECT count(*) FROM test_missing_target x, test_missing_target y diff --git a/src/test/regress/expected/select_implicit_2.out b/src/test/regress/expected/select_implicit_2.out index 718eb09f05..fac106353f 100644 --- a/src/test/regress/expected/select_implicit_2.out +++ b/src/test/regress/expected/select_implicit_2.out @@ -115,6 +115,8 @@ SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1; -- failure expected SELECT c, count(*) FROM test_missing_target GROUP BY 3; ERROR: GROUP BY position 3 is not in select list +LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3; + ^ -- group w/o existing GROUP BY and ORDER BY target under ambiguous condition -- failure expected SELECT count(*) FROM test_missing_target x, test_missing_target y diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 45d82c7dda..f29c61b23c 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -54,6 +54,8 @@ SELECT xmlconcat('hello', 'you'); SELECT xmlconcat(1, 2); ERROR: argument of XMLCONCAT must be type xml, not type integer +LINE 1: SELECT xmlconcat(1, 2); + ^ SELECT xmlconcat('bad', '