fix-grouping-sets-pullup-v2.patch
text/x-diff
Filename: fix-grouping-sets-pullup-v2.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/optimizer/prep/prepjointree.c | 0 | 0 |
| src/test/regress/expected/groupingsets.out | 0 | 0 |
| src/test/regress/sql/groupingsets.sql | 0 | 0 |
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 0e2a220..45d82da 100644
*** a/src/backend/optimizer/prep/prepjointree.c
--- b/src/backend/optimizer/prep/prepjointree.c
*************** pull_up_simple_subquery(PlannerInfo *roo
*** 1003,1013 ****
/*
* The subquery's targetlist items are now in the appropriate form to
! * insert into the top query, but if we are under an outer join then
! * non-nullable items and lateral references may have to be turned into
! * PlaceHolderVars. If we are dealing with an appendrel member then
! * anything that's not a simple Var has to be turned into a
! * PlaceHolderVar. Set up required context data for pullup_replace_vars.
*/
rvcontext.root = root;
rvcontext.targetlist = subquery->targetList;
--- 1003,1010 ----
/*
* The subquery's targetlist items are now in the appropriate form to
! * insert into the top query, except that we may need to wrap them in
! * PlaceHolderVars. Set up required context data for pullup_replace_vars.
*/
rvcontext.root = root;
rvcontext.targetlist = subquery->targetList;
*************** pull_up_simple_subquery(PlannerInfo *roo
*** 1019,1032 ****
rvcontext.relids = NULL;
rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
rvcontext.varno = varno;
! rvcontext.need_phvs = (lowest_nulling_outer_join != NULL ||
! containing_appendrel != NULL);
! rvcontext.wrap_non_vars = (containing_appendrel != NULL);
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
sizeof(Node *));
/*
* Replace all of the top query's references to the subquery's outputs
* with copies of the adjusted subtlist items, being careful not to
* replace any of the jointree structure. (This'd be a lot cleaner if we
--- 1016,1064 ----
rvcontext.relids = NULL;
rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
rvcontext.varno = varno;
! /* these flags will be set below, if needed */
! rvcontext.need_phvs = false;
! rvcontext.wrap_non_vars = false;
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
sizeof(Node *));
/*
+ * If we are under an outer join then non-nullable items and lateral
+ * references may have to be turned into PlaceHolderVars.
+ */
+ if (lowest_nulling_outer_join != NULL)
+ rvcontext.need_phvs = true;
+
+ /*
+ * If we are dealing with an appendrel member then anything that's not a
+ * simple Var has to be turned into a PlaceHolderVar. We force this to
+ * ensure that what we pull up doesn't get merged into a surrounding
+ * expression during later processing and then fail to match the
+ * expression actually available from the appendrel.
+ */
+ if (containing_appendrel != NULL)
+ {
+ rvcontext.need_phvs = true;
+ rvcontext.wrap_non_vars = true;
+ }
+
+ /*
+ * If the parent query uses grouping sets, we need a PlaceHolderVar for
+ * anything that's not a simple Var. Again, this ensures that expressions
+ * retain their separate identity so that they will match grouping set
+ * columns when appropriate. (It'd be sufficient to wrap values used in
+ * grouping set columns, and do so only in non-aggregated portions of the
+ * tlist and havingQual, but that would require a lot of infrastructure
+ * that pullup_replace_vars hasn't currently got.)
+ */
+ if (parse->groupingSets)
+ {
+ rvcontext.need_phvs = true;
+ rvcontext.wrap_non_vars = true;
+ }
+
+ /*
* Replace all of the top query's references to the subquery's outputs
* with copies of the adjusted subtlist items, being careful not to
* replace any of the jointree structure. (This'd be a lot cleaner if we
diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out
index 833d515..cbfdbfd 100644
*** a/src/test/regress/expected/groupingsets.out
--- b/src/test/regress/expected/groupingsets.out
*************** select g as alias1, g as alias2
*** 389,394 ****
--- 389,439 ----
3 |
(6 rows)
+ -- check that pulled-up subquery outputs still go to null when appropriate
+ select four, x
+ from (select four, ten, 'foo'::text as x from tenk1) as t
+ group by grouping sets (four, x)
+ having x = 'foo';
+ four | x
+ ------+-----
+ | foo
+ (1 row)
+
+ select four, x || 'x'
+ from (select four, ten, 'foo'::text as x from tenk1) as t
+ group by grouping sets (four, x)
+ order by four;
+ four | ?column?
+ ------+----------
+ 0 |
+ 1 |
+ 2 |
+ 3 |
+ | foox
+ (5 rows)
+
+ select (x+y)*1, sum(z)
+ from (select 1 as x, 2 as y, 3 as z) s
+ group by grouping sets (x+y, x);
+ ?column? | sum
+ ----------+-----
+ 3 | 3
+ | 3
+ (2 rows)
+
+ select x, not x as not_x, q2 from
+ (select *, q1 = 1 as x from int8_tbl i1) as t
+ group by grouping sets(x, q2)
+ order by x, q2;
+ x | not_x | q2
+ ---+-------+-------------------
+ f | t |
+ | | -4567890123456789
+ | | 123
+ | | 456
+ | | 4567890123456789
+ (5 rows)
+
-- simple rescan tests
select a, b, sum(v.x)
from (values (1),(2)) v(x), gstest_data(v.x)
diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql
index 2b4ab69..b28d821 100644
*** a/src/test/regress/sql/groupingsets.sql
--- b/src/test/regress/sql/groupingsets.sql
*************** select g as alias1, g as alias2
*** 152,157 ****
--- 152,177 ----
from generate_series(1,3) g
group by alias1, rollup(alias2);
+ -- check that pulled-up subquery outputs still go to null when appropriate
+ select four, x
+ from (select four, ten, 'foo'::text as x from tenk1) as t
+ group by grouping sets (four, x)
+ having x = 'foo';
+
+ select four, x || 'x'
+ from (select four, ten, 'foo'::text as x from tenk1) as t
+ group by grouping sets (four, x)
+ order by four;
+
+ select (x+y)*1, sum(z)
+ from (select 1 as x, 2 as y, 3 as z) s
+ group by grouping sets (x+y, x);
+
+ select x, not x as not_x, q2 from
+ (select *, q1 = 1 as x from int8_tbl i1) as t
+ group by grouping sets(x, q2)
+ order by x, q2;
+
-- simple rescan tests
select a, b, sum(v.x)