Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/backend/distributed/planner/distributed_planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ int PlannerLevel = 0;

static bool ListContainsDistributedTableRTE(List *rangeTableList,
bool *maybeHasForeignDistributedTable);
static bool PlanContainsDistributedSubPlanRTE(List *subPlanList);
static bool PlanContainsDistributedSubPlanRTE(DistributedPlanningContext *planContext);
static PlannedStmt * CreateDistributedPlannedStmt(DistributedPlanningContext *
planContext);
static PlannedStmt * InlineCtesAndCreateDistributedPlannedStmt(uint64 planId,
Expand Down Expand Up @@ -436,8 +436,9 @@ ListContainsDistributedTableRTE(List *rangeTableList,


/*
* PlanContainsDistributedSubPlanRTE checks whether any of the subplans in the given
* subPlanList is a Read Intermediate Result function scan.
* PlanContainsDistributedSubPlanRTE checks whether any of the subplans in the
* plan context's PlannedStmt->subplans list is a Read Intermediate Result
* function scan.
*
* It is used by the check after standard_planner() to determine whether the plan
* still requires distributed planning; in addition to checking the range table for
Expand All @@ -446,14 +447,26 @@ ListContainsDistributedTableRTE(List *rangeTableList,
* that distributed planning is required.
*/
static bool
PlanContainsDistributedSubPlanRTE(List *subPlanList)
PlanContainsDistributedSubPlanRTE(DistributedPlanningContext *planContext)
{
/*
* We iterate over planContext->plan->subplans, which is PostgreSQL's
* PlannedStmt->subplans list. PostgreSQL's setrefs.c (set_plan_references)
* resolves AlternativeSubPlan nodes by picking one alternative and setting
* the discarded subplan entries to NULL. We must therefore skip NULL entries.
*/
List *subPlanList = planContext->plan->subplans;
ListCell *subPlanCell = NULL;

foreach(subPlanCell, subPlanList)
{
Node *planRoot = (Node *) lfirst(subPlanCell);

if (planRoot == NULL)
{
continue;
}

if (!IsA(planRoot, FunctionScan))
{
continue;
Expand Down Expand Up @@ -2975,7 +2988,7 @@ CheckPostPlanDistribution(DistributedPlanningContext *planContext, bool
/* ..or a distributed subplan */
planHasDistribution = planHasDistribution ||
PlanContainsDistributedSubPlanRTE(
planContext->plan->subplans);
planContext);

/*
* The plan has a distributed relation, so we know for sure that
Expand Down
65 changes: 65 additions & 0 deletions src/test/regress/expected/subquery_in_where.out
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,71 @@ WHERE true OR NOT EXISTS (SELECT 1 FROM t1);
1
(1 row)

-- Test crash fix for issue #8548
-- A query with LEFT JOIN to a distributed table and correlated subqueries
-- could crash because PostgreSQL's setrefs.c sets subplan list entries to
-- NULL when AlternativeSubPlan resolution discards unused alternatives.
-- PlanContainsDistributedSubPlanRTE must skip NULL entries.
CREATE TABLE t4 (vkey integer, pkey integer, c30 integer, c31 integer, c32 text);
CREATE TABLE t5 (vkey integer, pkey integer, c33 text, c34 integer, c35 integer,
c36 timestamp without time zone);
CREATE TABLE t2 (vkey integer, pkey integer, c15 numeric, c16 timestamp without time zone,
c17 text, c18 text, c19 timestamp without time zone,
c20 timestamp without time zone, c21 integer);
CREATE TABLE t22 (vkey integer, pkey integer, c37 numeric, c38 text, c39 numeric,
c40 numeric, c41 numeric, c42 integer,
c43 timestamp without time zone, c44 numeric,
colocated_key numeric);
SELECT create_distributed_table('t22', 'colocated_key');
create_distributed_table
---------------------------------------------------------------------

(1 row)

-- This query should not crash (issue #8548)
SELECT
70 AS c_0
FROM
(
SELECT
(
EXISTS (
SELECT ref_5.c33 AS c_0
FROM t5 AS ref_5
WHERE (make_timestamp(2001, 7, 13, 17, 53, 31)) = (ref_1.c43)
)
) AS c_0
FROM
(
t4 AS ref_0
LEFT OUTER JOIN t22 AS ref_1
ON (ref_0.vkey = ref_1.vkey)
)
WHERE
(
(ref_0.c31) >= (
SELECT ref_1.pkey AS c_0
FROM t2 AS ref_2
WHERE (true) < ((ref_2.c17) ^@ (ref_0.c32))
ORDER BY c_0 DESC
LIMIT 1
)
) IN (
SELECT (ref_1.c40) <= (ref_1.c37) AS c_0
FROM t7 AS ref_4
WHERE NOT ((ref_1.c40) <> (ref_1.c41))
)
) AS subq_0
WHERE
(TRUE) < (TRUE);
c_0
---------------------------------------------------------------------
(0 rows)

DROP TABLE t4;
DROP TABLE t5;
DROP TABLE t2;
DROP TABLE t22;
DROP TABLE local_table;
DROP TABLE t0;
DROP TABLE t1;
Expand Down
Loading
Loading