From 8d6348f8b09543ba2589bcfb74bc7924c35c46c7 Mon Sep 17 00:00:00 2001 From: Denis Hirn Date: Tue, 23 Mar 2021 12:58:36 +0100 Subject: [PATCH] Allow multiple linear recursive self-references --- .../src/backend/executor/nodeWorktablescan.c | 13 +++++++------ postgres/src/backend/parser/parse_cte.c | 18 +++++++++++++++--- postgres/src/include/nodes/execnodes.h | 1 + 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/postgres/src/backend/executor/nodeWorktablescan.c b/postgres/src/backend/executor/nodeWorktablescan.c index e8f5caf..b2e1423 100644 --- a/postgres/src/backend/executor/nodeWorktablescan.c +++ b/postgres/src/backend/executor/nodeWorktablescan.c @@ -42,10 +42,6 @@ WorkTableScanNext(WorkTableScanState *node) * worktable plan node, since it cannot appear high enough in the plan * tree of a scrollable cursor to be exposed to a backward-scan * requirement. So it's not worth expending effort to support it. - * - * Note: we are also assuming that this node is the only reader of the - * worktable. Therefore, we don't need a private read pointer for the - * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy. */ Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction)); @@ -55,6 +51,7 @@ WorkTableScanNext(WorkTableScanState *node) * Get the next tuple from tuplestore. Return NULL if no more tuples. */ slot = node->ss.ss_ScanTupleSlot; + tuplestore_select_read_pointer(tuplestorestate, node->readptr); (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot); return slot; } @@ -99,7 +96,8 @@ ExecWorkTableScan(PlanState *pstate) Assert(!param->isnull); node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value)); Assert(node->rustate); - + node->readptr = tuplestore_alloc_read_pointer(node->rustate->working_table, 0); + Assert(node->readptr != -1); /* * The scan tuple type (ie, the rowtype we expect to find in the work * table) is the same as the result rowtype of the ancestor @@ -147,6 +145,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; scanstate->ss.ps.ExecProcNode = ExecWorkTableScan; + scanstate->readptr = -1; /* we'll see this later */ scanstate->rustate = NULL; /* we'll set this later */ /* @@ -218,6 +217,8 @@ ExecReScanWorkTableScan(WorkTableScanState *node) ExecScanReScan(&node->ss); /* No need (or way) to rescan if ExecWorkTableScan not called yet */ - if (node->rustate) + if (node->rustate) { + if(node->readptr != -1) tuplestore_select_read_pointer(node->rustate->working_table, node->readptr); tuplestore_rescan(node->rustate->working_table); + } } diff --git a/postgres/src/backend/parser/parse_cte.c b/postgres/src/backend/parser/parse_cte.c index 1fca748..fbfdf30 100644 --- a/postgres/src/backend/parser/parse_cte.c +++ b/postgres/src/backend/parser/parse_cte.c @@ -924,9 +924,21 @@ checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate) { case SETOP_NONE: case SETOP_UNION: - raw_expression_tree_walker((Node *) stmt, - checkWellFormedRecursionWalker, - (void *) cstate); + /* Check selfrefcount for each recursive member individually */ + if((Node *) stmt->larg != NULL && (Node *) stmt->rarg != NULL) { + int selfrefcount = cstate->selfrefcount; + + checkWellFormedRecursionWalker((Node *) stmt->larg, cstate); + + /* Restore selfrefcount to allow multiple linear recursive references */ + cstate->selfrefcount = selfrefcount; + + checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate); + } else { + raw_expression_tree_walker((Node *) stmt, + checkWellFormedRecursionWalker, + (void *) cstate); + } break; case SETOP_INTERSECT: if (stmt->all) diff --git a/postgres/src/include/nodes/execnodes.h b/postgres/src/include/nodes/execnodes.h index 015bfc0..e894c41 100644 --- a/postgres/src/include/nodes/execnodes.h +++ b/postgres/src/include/nodes/execnodes.h @@ -1782,6 +1782,7 @@ typedef struct NamedTuplestoreScanState typedef struct WorkTableScanState { ScanState ss; /* its first field is NodeTag */ + int readptr; /* index of my tuplestore read pointer */ RecursiveUnionState *rustate; } WorkTableScanState; -- 2.30.1