From d479e37e3d20efad8b178e0f1e468c086a7519a8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 19 Jan 2017 18:20:48 -0500 Subject: [PATCH] Fix Assert failure induced by commit 215b43cdc. I'd somehow talked myself into believing that set_append_rel_size doesn't need to worry about getting back an AND clause when it applies eval_const_expressions to the result of adjust_appendrel_attrs (that is, transposing the appendrel parent's restriction clauses for one child). But that is nonsense, and Andreas Seltenreich's fuzz tester soon turned up a counterexample. Put back the make_ands_implicit step that was there before, and add a regression test covering the case. Report: https://postgr.es/m/878tq6vja6.fsf@ansel.ydns.eu --- src/backend/optimizer/path/allpaths.c | 43 ++++++++++++++++----------- src/test/regress/expected/union.out | 30 +++++++++++++++++++ src/test/regress/sql/union.sql | 13 ++++++++ 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 7c017fe1e4..5c189874ef 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -896,7 +896,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, { RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); Node *childqual; - bool pseudoconstant; + ListCell *lc2; Assert(IsA(rinfo, RestrictInfo)); childqual = adjust_appendrel_attrs(root, @@ -916,25 +916,32 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, /* Restriction reduces to constant TRUE, so drop it */ continue; } - /* check for pseudoconstant (no Vars or volatile functions) */ - pseudoconstant = - !contain_vars_of_level(childqual, 0) && - !contain_volatile_functions(childqual); - if (pseudoconstant) + /* might have gotten an AND clause, if so flatten it */ + foreach(lc2, make_ands_implicit((Expr *) childqual)) { - /* tell createplan.c to check for gating quals */ - root->hasPseudoConstantQuals = true; + Node *onecq = (Node *) lfirst(lc2); + bool pseudoconstant; + + /* check for pseudoconstant (no Vars or volatile functions) */ + pseudoconstant = + !contain_vars_of_level(onecq, 0) && + !contain_volatile_functions(onecq); + if (pseudoconstant) + { + /* tell createplan.c to check for gating quals */ + root->hasPseudoConstantQuals = true; + } + /* reconstitute RestrictInfo with appropriate properties */ + childquals = lappend(childquals, + make_restrictinfo((Expr *) onecq, + rinfo->is_pushed_down, + rinfo->outerjoin_delayed, + pseudoconstant, + rinfo->security_level, + NULL, NULL, NULL)); + /* track minimum security level among child quals */ + cq_min_security = Min(cq_min_security, rinfo->security_level); } - /* reconstitute RestrictInfo with appropriate properties */ - childquals = lappend(childquals, - make_restrictinfo((Expr *) childqual, - rinfo->is_pushed_down, - rinfo->outerjoin_delayed, - pseudoconstant, - rinfo->security_level, - NULL, NULL, NULL)); - /* track minimum security level among child quals */ - cq_min_security = Min(cq_min_security, rinfo->security_level); } /* diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index d22db69c7d..4d697bada7 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -720,3 +720,33 @@ select * from drop table t3; drop function expensivefunc(int); +-- Test handling of appendrel quals that const-simplify into an AND +explain (costs off) +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); + QUERY PLAN +--------------------------------------------- + Append + -> Seq Scan on int8_tbl a + -> Seq Scan on int8_tbl b + Filter: ((q1 >= q2) AND (q1 <= q2)) +(4 rows) + +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); + q1 | q2 | x +------------------+-------------------+--- + 123 | 456 | 0 + 123 | 4567890123456789 | 0 + 4567890123456789 | 123 | 0 + 4567890123456789 | 4567890123456789 | 0 + 4567890123456789 | -4567890123456789 | 0 + 4567890123456789 | 4567890123456789 | 1 +(6 rows) + diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index debd99ed51..48e6850798 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -322,3 +322,16 @@ select * from drop table t3; drop function expensivefunc(int); + +-- Test handling of appendrel quals that const-simplify into an AND +explain (costs off) +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); -- 2.40.0