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:
@ -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",
|
||||
|
Reference in New Issue
Block a user