diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2014-06-16 15:55:05 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2014-06-16 15:55:30 -0400 |
commit | 2146f13408cdb85c738364fe8f7965209e08c6be (patch) | |
tree | 9c5989a33d072788a51411dd7ee1bedb14f2280d /src/backend/parser/parse_expr.c | |
parent | ac608fe758455804f26179ea7c556e7752e453e8 (diff) | |
download | postgresql-2146f13408cdb85c738364fe8f7965209e08c6be.tar.gz postgresql-2146f13408cdb85c738364fe8f7965209e08c6be.zip |
Avoid recursion when processing simple lists of AND'ed or OR'ed clauses.
Since most of the system thinks AND and OR are N-argument expressions
anyway, let's have the grammar generate a representation of that form when
dealing with input like "x AND y AND z AND ...", rather than generating
a deeply-nested binary tree that just has to be flattened later by the
planner. This avoids stack overflow in parse analysis when dealing with
queries having more than a few thousand such clauses; and in any case it
removes some rather unsightly inconsistencies, since some parts of parse
analysis were generating N-argument ANDs/ORs already.
It's still possible to get a stack overflow with weirdly parenthesized
input, such as "x AND (y AND (z AND ( ... )))", but such cases are not
mainstream usage. The maximum depth of parenthesization is already
limited by Bison's stack in such cases, anyway, so that the limit is
probably fairly platform-independent.
Patch originally by Gurjeet Singh, heavily revised by me
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 98 |
1 files changed, 41 insertions, 57 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 088224573f3..83e20db2768 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -41,15 +41,13 @@ bool Transform_null_equals = false; static Node *transformExprRecurse(ParseState *pstate, Node *expr); static Node *transformParamRef(ParseState *pstate, ParamRef *pref); static Node *transformAExprOp(ParseState *pstate, A_Expr *a); -static Node *transformAExprAnd(ParseState *pstate, A_Expr *a); -static Node *transformAExprOr(ParseState *pstate, A_Expr *a); -static Node *transformAExprNot(ParseState *pstate, A_Expr *a); static Node *transformAExprOpAny(ParseState *pstate, A_Expr *a); static Node *transformAExprOpAll(ParseState *pstate, A_Expr *a); static Node *transformAExprDistinct(ParseState *pstate, A_Expr *a); static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a); static Node *transformAExprOf(ParseState *pstate, A_Expr *a); static Node *transformAExprIn(ParseState *pstate, A_Expr *a); +static Node *transformBoolExpr(ParseState *pstate, BoolExpr *a); static Node *transformFuncCall(ParseState *pstate, FuncCall *fn); static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c); static Node *transformSubLink(ParseState *pstate, SubLink *sublink); @@ -223,15 +221,6 @@ transformExprRecurse(ParseState *pstate, Node *expr) case AEXPR_OP: result = transformAExprOp(pstate, a); break; - case AEXPR_AND: - result = transformAExprAnd(pstate, a); - break; - case AEXPR_OR: - result = transformAExprOr(pstate, a); - break; - case AEXPR_NOT: - result = transformAExprNot(pstate, a); - break; case AEXPR_OP_ANY: result = transformAExprOpAny(pstate, a); break; @@ -258,6 +247,10 @@ transformExprRecurse(ParseState *pstate, Node *expr) break; } + case T_BoolExpr: + result = transformBoolExpr(pstate, (BoolExpr *) expr); + break; + case T_FuncCall: result = transformFuncCall(pstate, (FuncCall *) expr); break; @@ -337,7 +330,6 @@ transformExprRecurse(ParseState *pstate, Node *expr) case T_DistinctExpr: case T_NullIfExpr: case T_ScalarArrayOpExpr: - case T_BoolExpr: case T_FieldSelect: case T_FieldStore: case T_RelabelType: @@ -919,46 +911,6 @@ transformAExprOp(ParseState *pstate, A_Expr *a) } static Node * -transformAExprAnd(ParseState *pstate, A_Expr *a) -{ - Node *lexpr = transformExprRecurse(pstate, a->lexpr); - Node *rexpr = transformExprRecurse(pstate, a->rexpr); - - lexpr = coerce_to_boolean(pstate, lexpr, "AND"); - rexpr = coerce_to_boolean(pstate, rexpr, "AND"); - - return (Node *) makeBoolExpr(AND_EXPR, - list_make2(lexpr, rexpr), - a->location); -} - -static Node * -transformAExprOr(ParseState *pstate, A_Expr *a) -{ - Node *lexpr = transformExprRecurse(pstate, a->lexpr); - Node *rexpr = transformExprRecurse(pstate, a->rexpr); - - lexpr = coerce_to_boolean(pstate, lexpr, "OR"); - rexpr = coerce_to_boolean(pstate, rexpr, "OR"); - - return (Node *) makeBoolExpr(OR_EXPR, - list_make2(lexpr, rexpr), - a->location); -} - -static Node * -transformAExprNot(ParseState *pstate, A_Expr *a) -{ - Node *rexpr = transformExprRecurse(pstate, a->rexpr); - - rexpr = coerce_to_boolean(pstate, rexpr, "NOT"); - - return (Node *) makeBoolExpr(NOT_EXPR, - list_make1(rexpr), - a->location); -} - -static Node * transformAExprOpAny(ParseState *pstate, A_Expr *a) { Node *lexpr = transformExprRecurse(pstate, a->lexpr); @@ -1238,6 +1190,42 @@ transformAExprIn(ParseState *pstate, A_Expr *a) } static Node * +transformBoolExpr(ParseState *pstate, BoolExpr *a) +{ + List *args = NIL; + const char *opname; + ListCell *lc; + + switch (a->boolop) + { + case AND_EXPR: + opname = "AND"; + break; + case OR_EXPR: + opname = "OR"; + break; + case NOT_EXPR: + opname = "NOT"; + break; + default: + elog(ERROR, "unrecognized boolop: %d", (int) a->boolop); + opname = NULL; /* keep compiler quiet */ + break; + } + + foreach(lc, a->args) + { + Node *arg = (Node *) lfirst(lc); + + arg = transformExprRecurse(pstate, arg); + arg = coerce_to_boolean(pstate, arg, opname); + args = lappend(args, arg); + } + + return (Node *) makeBoolExpr(a->boolop, args, a->location); +} + +static Node * transformFuncCall(ParseState *pstate, FuncCall *fn) { List *targs; @@ -2428,10 +2416,6 @@ make_row_comparison_op(ParseState *pstate, List *opname, /* * For = and <> cases, we just combine the pairwise operators with AND or * OR respectively. - * - * Note: this is presently the only place where the parser generates - * BoolExpr with more than two arguments. Should be OK since the rest of - * the system thinks BoolExpr is N-argument anyway. */ if (rctype == ROWCOMPARE_EQ) return (Node *) makeBoolExpr(AND_EXPR, opexprs, location); |