aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-04-21 23:17:36 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2016-04-21 23:17:36 -0400
commitabb164655c703a5013b7fcf83f855a071895dc91 (patch)
treee194dc92caf724447439fdeb445687d91f116a42 /src/backend/parser/parse_expr.c
parent80f66a9ad06eafa91ffc5ff19c725c7f393c242e (diff)
downloadpostgresql-abb164655c703a5013b7fcf83f855a071895dc91.tar.gz
postgresql-abb164655c703a5013b7fcf83f855a071895dc91.zip
Fix unexpected side-effects of operator_precedence_warning.
The implementation of that feature involves injecting nodes into the raw parsetree where explicit parentheses appear. Various places in parse_expr.c that test to see "is this child node of type Foo" need to look through such nodes, else we'll get different behavior when operator_precedence_warning is on than when it is off. Note that we only need to handle this when testing untransformed child nodes, since the AEXPR_PAREN nodes will be gone anyway after transformExprRecurse. Per report from Scott Ribe and additional code-reading. Back-patch to 9.5 where this feature was added. Report: <ED37E303-1B0A-4CD8-8E1E-B9C4C2DD9A17@elevated-dev.com>
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index ebda55dfd15..8b285165d5f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -857,6 +857,14 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
emit_precedence_warnings(pstate, opgroup, opname,
lexpr, rexpr,
a->location);
+
+ /* Look through AEXPR_PAREN nodes so they don't affect tests below */
+ while (lexpr && IsA(lexpr, A_Expr) &&
+ ((A_Expr *) lexpr)->kind == AEXPR_PAREN)
+ lexpr = ((A_Expr *) lexpr)->lexpr;
+ while (rexpr && IsA(rexpr, A_Expr) &&
+ ((A_Expr *) rexpr)->kind == AEXPR_PAREN)
+ rexpr = ((A_Expr *) rexpr)->lexpr;
}
/*
@@ -1903,6 +1911,11 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
Node *e = (Node *) lfirst(element);
Node *newe;
+ /* Look through AEXPR_PAREN nodes so they don't affect test below */
+ while (e && IsA(e, A_Expr) &&
+ ((A_Expr *) e)->kind == AEXPR_PAREN)
+ e = ((A_Expr *) e)->lexpr;
+
/*
* If an element is itself an A_ArrayExpr, recurse directly so that we
* can pass down any target type we were given.
@@ -2453,29 +2466,40 @@ transformWholeRowRef(ParseState *pstate, RangeTblEntry *rte, int location)
/*
* Handle an explicit CAST construct.
*
- * Transform the argument, then look up the type name and apply any necessary
+ * Transform the argument, look up the type name, and apply any necessary
* coercion function(s).
*/
static Node *
transformTypeCast(ParseState *pstate, TypeCast *tc)
{
Node *result;
+ Node *arg = tc->arg;
Node *expr;
Oid inputType;
Oid targetType;
int32 targetTypmod;
int location;
+ /* Look up the type name first */
typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
/*
+ * Look through any AEXPR_PAREN nodes that may have been inserted thanks
+ * to operator_precedence_warning. Otherwise, ARRAY[]::foo[] behaves
+ * differently from (ARRAY[])::foo[].
+ */
+ while (arg && IsA(arg, A_Expr) &&
+ ((A_Expr *) arg)->kind == AEXPR_PAREN)
+ arg = ((A_Expr *) arg)->lexpr;
+
+ /*
* If the subject of the typecast is an ARRAY[] construct and the target
* type is an array type, we invoke transformArrayExpr() directly so that
* we can pass down the type information. This avoids some cases where
* transformArrayExpr() might not infer the correct type. Otherwise, just
* transform the argument normally.
*/
- if (IsA(tc->arg, A_ArrayExpr))
+ if (IsA(arg, A_ArrayExpr))
{
Oid targetBaseType;
int32 targetBaseTypmod;
@@ -2493,16 +2517,16 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
if (OidIsValid(elementType))
{
expr = transformArrayExpr(pstate,
- (A_ArrayExpr *) tc->arg,
+ (A_ArrayExpr *) arg,
targetBaseType,
elementType,
targetBaseTypmod);
}
else
- expr = transformExprRecurse(pstate, tc->arg);
+ expr = transformExprRecurse(pstate, arg);
}
else
- expr = transformExprRecurse(pstate, tc->arg);
+ expr = transformExprRecurse(pstate, arg);
inputType = exprType(expr);
if (inputType == InvalidOid)