Skip to content

Commit abb1646

Browse files
committed
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>
1 parent 80f66a9 commit abb1646

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

src/backend/parser/parse_expr.c

+29-5
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,14 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
857857
emit_precedence_warnings(pstate, opgroup, opname,
858858
lexpr, rexpr,
859859
a->location);
860+
861+
/* Look through AEXPR_PAREN nodes so they don't affect tests below */
862+
while (lexpr && IsA(lexpr, A_Expr) &&
863+
((A_Expr *) lexpr)->kind == AEXPR_PAREN)
864+
lexpr = ((A_Expr *) lexpr)->lexpr;
865+
while (rexpr && IsA(rexpr, A_Expr) &&
866+
((A_Expr *) rexpr)->kind == AEXPR_PAREN)
867+
rexpr = ((A_Expr *) rexpr)->lexpr;
860868
}
861869

862870
/*
@@ -1903,6 +1911,11 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
19031911
Node *e = (Node *) lfirst(element);
19041912
Node *newe;
19051913

1914+
/* Look through AEXPR_PAREN nodes so they don't affect test below */
1915+
while (e && IsA(e, A_Expr) &&
1916+
((A_Expr *) e)->kind == AEXPR_PAREN)
1917+
e = ((A_Expr *) e)->lexpr;
1918+
19061919
/*
19071920
* If an element is itself an A_ArrayExpr, recurse directly so that we
19081921
* can pass down any target type we were given.
@@ -2453,29 +2466,40 @@ transformWholeRowRef(ParseState *pstate, RangeTblEntry *rte, int location)
24532466
/*
24542467
* Handle an explicit CAST construct.
24552468
*
2456-
* Transform the argument, then look up the type name and apply any necessary
2469+
* Transform the argument, look up the type name, and apply any necessary
24572470
* coercion function(s).
24582471
*/
24592472
static Node *
24602473
transformTypeCast(ParseState *pstate, TypeCast *tc)
24612474
{
24622475
Node *result;
2476+
Node *arg = tc->arg;
24632477
Node *expr;
24642478
Oid inputType;
24652479
Oid targetType;
24662480
int32 targetTypmod;
24672481
int location;
24682482

2483+
/* Look up the type name first */
24692484
typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
24702485

2486+
/*
2487+
* Look through any AEXPR_PAREN nodes that may have been inserted thanks
2488+
* to operator_precedence_warning. Otherwise, ARRAY[]::foo[] behaves
2489+
* differently from (ARRAY[])::foo[].
2490+
*/
2491+
while (arg && IsA(arg, A_Expr) &&
2492+
((A_Expr *) arg)->kind == AEXPR_PAREN)
2493+
arg = ((A_Expr *) arg)->lexpr;
2494+
24712495
/*
24722496
* If the subject of the typecast is an ARRAY[] construct and the target
24732497
* type is an array type, we invoke transformArrayExpr() directly so that
24742498
* we can pass down the type information. This avoids some cases where
24752499
* transformArrayExpr() might not infer the correct type. Otherwise, just
24762500
* transform the argument normally.
24772501
*/
2478-
if (IsA(tc->arg, A_ArrayExpr))
2502+
if (IsA(arg, A_ArrayExpr))
24792503
{
24802504
Oid targetBaseType;
24812505
int32 targetBaseTypmod;
@@ -2493,16 +2517,16 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
24932517
if (OidIsValid(elementType))
24942518
{
24952519
expr = transformArrayExpr(pstate,
2496-
(A_ArrayExpr *) tc->arg,
2520+
(A_ArrayExpr *) arg,
24972521
targetBaseType,
24982522
elementType,
24992523
targetBaseTypmod);
25002524
}
25012525
else
2502-
expr = transformExprRecurse(pstate, tc->arg);
2526+
expr = transformExprRecurse(pstate, arg);
25032527
}
25042528
else
2505-
expr = transformExprRecurse(pstate, tc->arg);
2529+
expr = transformExprRecurse(pstate, arg);
25062530

25072531
inputType = exprType(expr);
25082532
if (inputType == InvalidOid)

0 commit comments

Comments
 (0)