提交 e9c0e77a 编写于 作者: D Daniel Gustafsson

Disallow joins between nested RECURSIVE clauses

Joining nested REURSIVE clauses is planned as a join between
two WorkTableScan nodes, which we currently cannot do. Detect
and disallow for now until we have the required infrastructure
to handle this class of queries. The below query is an example
of this:

  WITH RECURSIVE r1 AS (
      SELECT 1 AS a
      UNION ALL
       (
          WITH RECURSIVE r2 AS (
              SELECT 2 as b
              UNION ALL
              SELECT b FROM r1, r2
          )
          SELECT b FROM r2
      )
  )
  SELECT * FROM r1 LIMIT 1;

In upstream PostgreSQL, the resulting plan exhibits the same
behavior as in GPDB, but there is no restiction on WorkTableScan
on the inner side of joins in PostgreSQL:

                           QUERY PLAN
  -------------------------------------------------------------
   Limit
     CTE r1
       ->  Recursive Union
             ->  Result
             ->  CTE Scan on r2 r2_1
                   CTE r2
                     ->  Recursive Union
                           ->  Result
                           ->  Nested Loop
                                 ->  WorkTable Scan on r1 r1_1
                                 ->  WorkTable Scan on r2
     ->  CTE Scan on r1
  (12 rows)

Backport to 6X_STABLE as it's a live bug there.
上级 62e87534
......@@ -110,9 +110,21 @@ add_paths_to_joinrel(PlannerInfo *root,
Assert(innerrel->pathlist &&
innerrel->cheapest_total_path);
/* Don't consider paths that have WorkTableScan as inner rel */
/*
* Don't consider paths that have WorkTableScan as inner rel. If the outer
* rel has a WorkTableScan as well, we won't be able to produce a usable
* join so we need to error out. This case can happen when to RECURSIVE
* clauses are joined. RECURSIVE_CTE_FIXME: Revisit this when we gain
* rescannable motions.
*/
if (innerrel->cheapest_startup_path && cdbpath_contains_wts(innerrel->cheapest_startup_path))
{
if (outerrel->cheapest_startup_path && cdbpath_contains_wts(outerrel->cheapest_startup_path))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("joining nested RECURSIVE clauses is not supported")));
return;
}
if (cdbpath_contains_wts(innerrel->cheapest_total_path))
return;
......
......@@ -2163,3 +2163,21 @@ SELECT * FROM y;
1100 |
(15 rows)
-- Nested RECURSIVE queries with double self-referential joins are planned by
-- joining two WorkTableScans, which GPDB cannot do yet. Ensure that we error
-- out with a descriptive message.
SET gp_recursive_cte TO ON;
WITH RECURSIVE r1 AS (
SELECT 1 AS a
UNION ALL
(
WITH RECURSIVE r2 AS (
SELECT 2 AS b
UNION ALL
SELECT b FROM r1, r2
)
SELECT b FROM r2
)
)
SELECT * FROM r1 LIMIT 1;
ERROR: joining nested RECURSIVE clauses is not supported
......@@ -2162,3 +2162,21 @@ SELECT * FROM y;
1100 |
(15 rows)
-- Nested RECURSIVE queries with double self-referential joins are planned by
-- joining two WorkTableScans, which GPDB cannot do yet. Ensure that we error
-- out with a descriptive message.
SET gp_recursive_cte TO ON;
WITH RECURSIVE r1 AS (
SELECT 1 AS a
UNION ALL
(
WITH RECURSIVE r2 AS (
SELECT 2 AS b
UNION ALL
SELECT b FROM r1, r2
)
SELECT b FROM r2
)
)
SELECT * FROM r1 LIMIT 1;
ERROR: joining nested RECURSIVE clauses is not supported
......@@ -341,3 +341,21 @@ WITH t AS (
SELECT m BETWEEN 100 AND 1500 FROM t LIMIT 1;
SELECT * FROM y;
-- Nested RECURSIVE queries with double self-referential joins are planned by
-- joining two WorkTableScans, which GPDB cannot do yet. Ensure that we error
-- out with a descriptive message.
SET gp_recursive_cte TO ON;
WITH RECURSIVE r1 AS (
SELECT 1 AS a
UNION ALL
(
WITH RECURSIVE r2 AS (
SELECT 2 AS b
UNION ALL
SELECT b FROM r1, r2
)
SELECT b FROM r2
)
)
SELECT * FROM r1 LIMIT 1;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册