未验证 提交 78fb79d9 编写于 作者: M Maksim Milyutin 提交者: GitHub

Fix server crash under rebuilding of RTEs and RelOptInfos

The GROUPING SETS statement with multiple canonical rollups working on
randomly distributed partitioned table causes rebuilding of
root->simple_rte_array and root->simple_rel_array on planning stage by
PostgreSQL optimizer. The rebuilding process initializes both RTEs and
RelOptInfos item by item and doesn't take into account that the
build_simple_rel() routine is recursive for inherited relations and
requires a full list of already initialized child RTEs inside
root->simple_rte_array. As a result, the call of build_simple_rel() fails
on the access to child RTEs.

The current fix segregates loops of building root->simple_rte_array and
root->simple_rel_array trying to leave a whole semantics unchanged.
上级 5f87e80a
......@@ -2241,7 +2241,6 @@ rebuild_append_simple_rel_and_rte(PlannerInfo *root,
int i;
int array_size;
ListCell *l1, *l2, *l3;
RelOptInfo *rel;
if (root->simple_rel_array)
pfree(root->simple_rel_array);
......@@ -2259,23 +2258,56 @@ rebuild_append_simple_rel_and_rte(PlannerInfo *root,
Assert(list_length(rtable) == list_length(subplans));
Assert(list_length(subplans) == list_length(subroots));
/*
* Build RTE array before initialization of RelOptInfos because
* build_simple_rel() routine called from inside the next loop is recursive
* for inherited relations that require a full list of already initialized
* child RTEs.
*/
i = 0;
forthree(l1, rtable, l2, subroots, l3, subplans)
foreach(l1, rtable)
{
RangeTblEntry *rte = (RangeTblEntry *)lfirst(l1);
/* the first array entry is not indexed */
i++;
/* skip empty RTE and join */
if (rte == NULL || rte->rtekind == RTE_JOIN)
continue;
root->simple_rte_array[i] = rte;
}
i = 0;
forboth(l2, subroots, l3, subplans)
{
SubqueryScan *splan;
PlannerInfo *sroot;
RangeTblEntry *rte;
RelOptInfo *rel;
/* skip the first one */
/* the first array entry is not indexed */
i++;
rte = (RangeTblEntry *)lfirst(l1);
if (rte == NULL || rte->rtekind == RTE_JOIN)
rte = root->simple_rte_array[i];
rel = root->simple_rel_array[i];
/* skip empty RTE and already initialized RelOptInfo */
if (rte == NULL || rel != NULL)
continue;
root->simple_rte_array[i] = rte;
if (rte->rtekind == RTE_VOID)
{
rel = makeNode(RelOptInfo);
/*
* XXX: save empty RelOptInfo that corresponds to deleted RTE
* (former pulled up subquery) in common array. This can be
* incorrect decision.
*/
root->simple_rel_array[i] = rel;
}
else
rel = build_simple_rel(root, i, RELOPT_BASEREL);
......
......@@ -36,3 +36,55 @@ FROM
| Bed | 300
(6 rows)
--
-- Case for partitioned table
--
--
-- Create new table bar
--
CREATE TABLE pfoo(type INTEGER, prod VARCHAR, quantity NUMERIC)
DISTRIBUTED RANDOMLY
PARTITION BY RANGE (quantity) (
partition "1" start (0) end (100),
partition "2" start (100) end (200),
partition "3" start (200) end (300),
partition "4" start (300) end (400)
);
NOTICE: CREATE TABLE will create partition "pfoo_1_prt_1" for table "pfoo"
NOTICE: CREATE TABLE will create partition "pfoo_1_prt_2" for table "pfoo"
NOTICE: CREATE TABLE will create partition "pfoo_1_prt_3" for table "pfoo"
NOTICE: CREATE TABLE will create partition "pfoo_1_prt_4" for table "pfoo"
--
-- Insert some values
--
INSERT INTO pfoo VALUES
(1, 'Table', 100),
(2, 'Chair', 250),
(3, 'Bed', 300);
--
-- Turn off GPORCA
--
set optimizer to off;
--
-- Select query with grouping sets
--
SELECT type, prod, sum(quantity) s_quant
FROM (
SELECT * FROM pfoo
) AS t
GROUP BY GROUPING SETS((type), (prod))
ORDER BY type, s_quant;
type | prod | s_quant
------+-------+---------
1 | | 100
2 | | 250
3 | | 300
| Table | 100
| Chair | 250
| Bed | 300
(6 rows)
--
-- Reset settings
--
reset optimizer;
......@@ -155,8 +155,8 @@ test: catalog
test: bfv_catalog bfv_index bfv_olap bfv_aggregate bfv_partition bfv_partition_plans DML_over_joins gporca bfv_statistic
# NOTE: gporca_faults uses gp_fault_injector - so do not add to a parallel group
test: gporca_faults
test: aggregate_with_groupingsets
test: aggregate_with_groupingsets
test: nested_case_null sort bb_mpph
test: bb_memory_quota memconsumption
......
......@@ -26,3 +26,48 @@ FROM
FROM foo F1
LIMIT 3
) F2 GROUP BY GROUPING SETS((type, prod), (prod)) ORDER BY type, s_quant;
--
-- Case for partitioned table
--
--
-- Create new table bar
--
CREATE TABLE pfoo(type INTEGER, prod VARCHAR, quantity NUMERIC)
DISTRIBUTED RANDOMLY
PARTITION BY RANGE (quantity) (
partition "1" start (0) end (100),
partition "2" start (100) end (200),
partition "3" start (200) end (300),
partition "4" start (300) end (400)
);
--
-- Insert some values
--
INSERT INTO pfoo VALUES
(1, 'Table', 100),
(2, 'Chair', 250),
(3, 'Bed', 300);
--
-- Turn off GPORCA
--
set optimizer to off;
--
-- Select query with grouping sets
--
SELECT type, prod, sum(quantity) s_quant
FROM (
SELECT * FROM pfoo
) AS t
GROUP BY GROUPING SETS((type), (prod))
ORDER BY type, s_quant;
--
-- Reset settings
--
reset optimizer;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册