diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 327557e..61a1cd9 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -40,8 +40,7 @@ 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 *transformAExprAndOr(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); @@ -223,10 +222,10 @@ transformExprRecurse(ParseState *pstate, Node *expr) result = transformAExprOp(pstate, a); break; case AEXPR_AND: - result = transformAExprAnd(pstate, a); + result = transformAExprAndOr(pstate, a); break; case AEXPR_OR: - result = transformAExprOr(pstate, a); + result = transformAExprAndOr(pstate, a); break; case AEXPR_NOT: result = transformAExprNot(pstate, a); @@ -920,27 +916,72 @@ 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); -} +/* + * Transform the AND/OR trees non-recursively. + * + * The parser turns a list of consecutive AND expressions into a left-deep tree. + * + * a AND b AND c + * + * AND + * / \ + * AND c + * / \ + * a b + * + * For very long lists, it gets deep enough that processing it recursively causes + * check_stack_depth() to raise error and abort the query. Hence, it is necessary + * that we process these trees iteratively. + */ +static Node * +transformAExprAndOr(ParseState *pstate, A_Expr *a) +{ + List *exprs = NIL; + List *pending = NIL; + Node *expr; + A_Expr *root = a; + A_Expr_Kind root_expr_kind = a->kind; + char *root_expr_name = (root_expr_kind == AEXPR_AND ? "AND" : "OR"); + BoolExprType root_bool_expr_type = (root_expr_kind == AEXPR_AND ? AND_EXPR : OR_EXPR); + + pending = lappend(pending, a); + + while (list_length(pending) > 0) + { + Node *tmp; + a = (A_Expr*) linitial(pending); + + pending = list_delete_first(pending); + + /* + * Follow the left links to walk the left-deep tree, and process all the + * right branches. + * + * If a right branch is also the same kind of tree as the root, then + * append it to the 'pending' list. The pending list is also processed + * in this function call iteratively rather than recursively. This + * allows us to process even bushy trees, not just left-deep trees. + */ + tmp = (Node*)a; + do { + a = (A_Expr*) tmp; + + if (IsA(a->rexpr, A_Expr) && ((A_Expr*)a->rexpr)->kind == root_expr_kind) + { + pending = lappend(pending, a->rexpr); + } + else + { + expr = transformExprRecurse(pstate, a->rexpr); + expr = coerce_to_boolean(pstate, expr, root_expr_name); + exprs = lcons(expr, exprs); + } + + tmp = a->lexpr; + } while (IsA(tmp, A_Expr) && ((A_Expr*)tmp)->kind == root_expr_kind); + + /* Now process the last left expression */ + expr = transformExprRecurse(pstate, a->lexpr); + expr = coerce_to_boolean(pstate, expr, root_expr_name); + exprs = lcons(expr, exprs); + } + + return (Node *) makeBoolExpr(root_bool_expr_type, exprs, root->location); +} diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 57ae842..42f0ece 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2092,7 +2092,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem | int4smaller(rsh.sh_avail, rsl.sl_avail) AS total_avail + | FROM shoe rsh, + | shoelace rsl + - | WHERE (((rsl.sl_color = rsh.slcolor) AND (rsl.sl_len_cm >= rsh.slminlen_cm)) AND (rsl.sl_len_cm <= rsh.slmaxlen_cm)); + | WHERE ((rsl.sl_color = rsh.slcolor) AND (rsl.sl_len_cm >= rsh.slminlen_cm) AND (rsl.sl_len_cm <= rsh.slmaxlen_cm)); shoelace | SELECT s.sl_name, + | s.sl_avail, + | s.sl_color, +