aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-06-16 15:55:05 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2014-06-16 15:55:30 -0400
commit2146f13408cdb85c738364fe8f7965209e08c6be (patch)
tree9c5989a33d072788a51411dd7ee1bedb14f2280d /src/backend/parser/parse_expr.c
parentac608fe758455804f26179ea7c556e7752e453e8 (diff)
downloadpostgresql-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.c98
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);