aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.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_clause.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_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index fcee1379c0c..4931dcad3b6 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -332,7 +332,8 @@ transformJoinUsingClause(ParseState *pstate,
RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
List *leftVars, List *rightVars)
{
- Node *result = NULL;
+ Node *result;
+ List *andargs = NIL;
ListCell *lvars,
*rvars;
@@ -358,18 +359,16 @@ transformJoinUsingClause(ParseState *pstate,
copyObject(lvar), copyObject(rvar),
-1);
- /* And combine into an AND clause, if multiple join columns */
- if (result == NULL)
- result = (Node *) e;
- else
- {
- A_Expr *a;
-
- a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e, -1);
- result = (Node *) a;
- }
+ /* Prepare to combine into an AND clause, if multiple join columns */
+ andargs = lappend(andargs, e);
}
+ /* Only need an AND if there's more than one join column */
+ if (list_length(andargs) == 1)
+ result = (Node *) linitial(andargs);
+ else
+ result = (Node *) makeBoolExpr(AND_EXPR, andargs, -1);
+
/*
* Since the references are already Vars, and are certainly from the input
* relations, we don't have to go through the same pushups that