mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
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>
This commit is contained in:
@ -857,6 +857,14 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
|
|||||||
emit_precedence_warnings(pstate, opgroup, opname,
|
emit_precedence_warnings(pstate, opgroup, opname,
|
||||||
lexpr, rexpr,
|
lexpr, rexpr,
|
||||||
a->location);
|
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 *e = (Node *) lfirst(element);
|
||||||
Node *newe;
|
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
|
* If an element is itself an A_ArrayExpr, recurse directly so that we
|
||||||
* can pass down any target type we were given.
|
* can pass down any target type we were given.
|
||||||
@ -2453,21 +2466,32 @@ transformWholeRowRef(ParseState *pstate, RangeTblEntry *rte, int location)
|
|||||||
/*
|
/*
|
||||||
* Handle an explicit CAST construct.
|
* 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).
|
* coercion function(s).
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
transformTypeCast(ParseState *pstate, TypeCast *tc)
|
transformTypeCast(ParseState *pstate, TypeCast *tc)
|
||||||
{
|
{
|
||||||
Node *result;
|
Node *result;
|
||||||
|
Node *arg = tc->arg;
|
||||||
Node *expr;
|
Node *expr;
|
||||||
Oid inputType;
|
Oid inputType;
|
||||||
Oid targetType;
|
Oid targetType;
|
||||||
int32 targetTypmod;
|
int32 targetTypmod;
|
||||||
int location;
|
int location;
|
||||||
|
|
||||||
|
/* Look up the type name first */
|
||||||
typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
|
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
|
* If the subject of the typecast is an ARRAY[] construct and the target
|
||||||
* type is an array type, we invoke transformArrayExpr() directly so that
|
* type is an array type, we invoke transformArrayExpr() directly so that
|
||||||
@ -2475,7 +2499,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
|
|||||||
* transformArrayExpr() might not infer the correct type. Otherwise, just
|
* transformArrayExpr() might not infer the correct type. Otherwise, just
|
||||||
* transform the argument normally.
|
* transform the argument normally.
|
||||||
*/
|
*/
|
||||||
if (IsA(tc->arg, A_ArrayExpr))
|
if (IsA(arg, A_ArrayExpr))
|
||||||
{
|
{
|
||||||
Oid targetBaseType;
|
Oid targetBaseType;
|
||||||
int32 targetBaseTypmod;
|
int32 targetBaseTypmod;
|
||||||
@ -2493,16 +2517,16 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
|
|||||||
if (OidIsValid(elementType))
|
if (OidIsValid(elementType))
|
||||||
{
|
{
|
||||||
expr = transformArrayExpr(pstate,
|
expr = transformArrayExpr(pstate,
|
||||||
(A_ArrayExpr *) tc->arg,
|
(A_ArrayExpr *) arg,
|
||||||
targetBaseType,
|
targetBaseType,
|
||||||
elementType,
|
elementType,
|
||||||
targetBaseTypmod);
|
targetBaseTypmod);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
expr = transformExprRecurse(pstate, tc->arg);
|
expr = transformExprRecurse(pstate, arg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
expr = transformExprRecurse(pstate, tc->arg);
|
expr = transformExprRecurse(pstate, arg);
|
||||||
|
|
||||||
inputType = exprType(expr);
|
inputType = exprType(expr);
|
||||||
if (inputType == InvalidOid)
|
if (inputType == InvalidOid)
|
||||||
|
Reference in New Issue
Block a user