diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 595cdfddb8b..e5ba730874c 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.1 2008/10/25 17:19:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.2 2008/10/26 02:46:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -804,12 +804,14 @@ transformAExprOf(ParseState *pstate, A_Expr *a) static Node * transformAExprIn(ParseState *pstate, A_Expr *a) { + Node *result = NULL; Node *lexpr; List *rexprs; + List *rvars; + List *rnonvars; List *typeids; bool useOr; bool haveRowExpr; - Node *result; ListCell *l; /* @@ -825,43 +827,37 @@ transformAExprIn(ParseState *pstate, A_Expr *a) * possible if the inputs are all scalars (no RowExprs) and there is a * suitable array type available. If not, we fall back to a boolean * condition tree with multiple copies of the lefthand expression. + * Also, any IN-list items that contain Vars are handled as separate + * boolean conditions, because that gives the planner more scope for + * optimization on such clauses. * * First step: transform all the inputs, and detect whether any are - * RowExprs. + * RowExprs or contain Vars. */ lexpr = transformExpr(pstate, a->lexpr); haveRowExpr = (lexpr && IsA(lexpr, RowExpr)); typeids = list_make1_oid(exprType(lexpr)); - rexprs = NIL; + rexprs = rvars = rnonvars = NIL; foreach(l, (List *) a->rexpr) { Node *rexpr = transformExpr(pstate, lfirst(l)); haveRowExpr |= (rexpr && IsA(rexpr, RowExpr)); rexprs = lappend(rexprs, rexpr); - typeids = lappend_oid(typeids, exprType(rexpr)); + if (contain_vars_of_level(rexpr, 0)) + rvars = lappend(rvars, rexpr); + else + { + rnonvars = lappend(rnonvars, rexpr); + typeids = lappend_oid(typeids, exprType(rexpr)); + } } /* - * We prefer a boolean tree to ScalarArrayOpExpr if any of these are true: - * - * 1. We have a RowExpr anywhere. - * - * 2. There's only one righthand expression --- best to just generate a - * simple = comparison. - * - * 3. There's a reasonably small number of righthand expressions and - * they contain any Vars. This is a heuristic to support cases like - * WHERE '555-1212' IN (tab.home_phone, tab.work_phone), which can be - * optimized into an OR of indexscans on different indexes so long as - * it's left as an OR tree. (It'd be better to leave this decision - * to the planner, no doubt, but the amount of code required to reformat - * the expression later on seems out of proportion to the benefit.) + * ScalarArrayOpExpr is only going to be useful if there's more than + * one non-Var righthand item. Also, it won't work for RowExprs. */ - if (!(haveRowExpr || - list_length(rexprs) == 1 || - (list_length(rexprs) <= 32 && - contain_vars_of_level((Node *) rexprs, 0)))) + if (!haveRowExpr && list_length(rnonvars) > 1) { Oid scalar_type; Oid array_type; @@ -881,14 +877,14 @@ transformAExprIn(ParseState *pstate, A_Expr *a) if (array_type != InvalidOid) { /* - * OK: coerce all the right-hand inputs to the common type and - * build an ArrayExpr for them. + * OK: coerce all the right-hand non-Var inputs to the common type + * and build an ArrayExpr for them. */ List *aexprs; ArrayExpr *newa; aexprs = NIL; - foreach(l, rexprs) + foreach(l, rnonvars) { Node *rexpr = (Node *) lfirst(l); @@ -903,19 +899,21 @@ transformAExprIn(ParseState *pstate, A_Expr *a) newa->elements = aexprs; newa->multidims = false; - return (Node *) make_scalar_array_op(pstate, - a->name, - useOr, - lexpr, - (Node *) newa, - a->location); + result = (Node *) make_scalar_array_op(pstate, + a->name, + useOr, + lexpr, + (Node *) newa, + a->location); + + /* Consider only the Vars (if any) in the loop below */ + rexprs = rvars; } } /* * Must do it the hard way, ie, with a boolean expression tree. */ - result = NULL; foreach(l, rexprs) { Node *rexpr = (Node *) lfirst(l);