1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

SEARCH and CYCLE clauses

This adds the SQL standard feature that adds the SEARCH and CYCLE
clauses to recursive queries to be able to do produce breadth- or
depth-first search orders and detect cycles.  These clauses can be
rewritten into queries using existing syntax, and that is what this
patch does in the rewriter.

Reviewed-by: Vik Fearing <vik@postgresfriends.org>
Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/db80ceee-6f97-9b4a-8ee8-3ba0c58e5be2@2ndquadrant.com
This commit is contained in:
Peter Eisentraut
2021-02-01 13:54:59 +01:00
parent bb513b364b
commit 3696a600e2
28 changed files with 2301 additions and 33 deletions

View File

@ -1566,6 +1566,12 @@ exprLocation(const Node *expr)
case T_OnConflictClause:
loc = ((const OnConflictClause *) expr)->location;
break;
case T_CTESearchClause:
loc = ((const CTESearchClause *) expr)->location;
break;
case T_CTECycleClause:
loc = ((const CTECycleClause *) expr)->location;
break;
case T_CommonTableExpr:
loc = ((const CommonTableExpr *) expr)->location;
break;
@ -1909,6 +1915,7 @@ expression_tree_walker(Node *node,
case T_NextValueExpr:
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
/* primitive node types with no expression subnodes */
break;
case T_WithCheckOption:
@ -2148,6 +2155,16 @@ expression_tree_walker(Node *node,
return true;
}
break;
case T_CTECycleClause:
{
CTECycleClause *cc = (CTECycleClause *) node;
if (walker(cc->cycle_mark_value, context))
return true;
if (walker(cc->cycle_mark_default, context))
return true;
}
break;
case T_CommonTableExpr:
{
CommonTableExpr *cte = (CommonTableExpr *) node;
@ -2156,7 +2173,13 @@ expression_tree_walker(Node *node,
* Invoke the walker on the CTE's Query node, so it can
* recurse into the sub-query if it wants to.
*/
return walker(cte->ctequery, context);
if (walker(cte->ctequery, context))
return true;
if (walker(cte->search_clause, context))
return true;
if (walker(cte->cycle_clause, context))
return true;
}
break;
case T_List:
@ -2615,6 +2638,7 @@ expression_tree_mutator(Node *node,
case T_NextValueExpr:
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
return (Node *) copyObject(node);
case T_WithCheckOption:
{
@ -3019,6 +3043,17 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
case T_CTECycleClause:
{
CTECycleClause *cc = (CTECycleClause *) node;
CTECycleClause *newnode;
FLATCOPY(newnode, cc, CTECycleClause);
MUTATE(newnode->cycle_mark_value, cc->cycle_mark_value, Node *);
MUTATE(newnode->cycle_mark_default, cc->cycle_mark_default, Node *);
return (Node *) newnode;
}
break;
case T_CommonTableExpr:
{
CommonTableExpr *cte = (CommonTableExpr *) node;
@ -3031,6 +3066,10 @@ expression_tree_mutator(Node *node,
* recurse into the sub-query if it wants to.
*/
MUTATE(newnode->ctequery, cte->ctequery, Node *);
MUTATE(newnode->search_clause, cte->search_clause, CTESearchClause *);
MUTATE(newnode->cycle_clause, cte->cycle_clause, CTECycleClause *);
return (Node *) newnode;
}
break;
@ -3913,6 +3952,7 @@ raw_expression_tree_walker(Node *node,
}
break;
case T_CommonTableExpr:
/* search_clause and cycle_clause are not interesting here */
return walker(((CommonTableExpr *) node)->ctequery, context);
default:
elog(ERROR, "unrecognized node type: %d",