1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-29 23:43:17 +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

@@ -2589,6 +2589,38 @@ _copyOnConflictClause(const OnConflictClause *from)
return newnode;
}
static CTESearchClause *
_copyCTESearchClause(const CTESearchClause *from)
{
CTESearchClause *newnode = makeNode(CTESearchClause);
COPY_NODE_FIELD(search_col_list);
COPY_SCALAR_FIELD(search_breadth_first);
COPY_STRING_FIELD(search_seq_column);
COPY_LOCATION_FIELD(location);
return newnode;
}
static CTECycleClause *
_copyCTECycleClause(const CTECycleClause *from)
{
CTECycleClause *newnode = makeNode(CTECycleClause);
COPY_NODE_FIELD(cycle_col_list);
COPY_STRING_FIELD(cycle_mark_column);
COPY_NODE_FIELD(cycle_mark_value);
COPY_NODE_FIELD(cycle_mark_default);
COPY_STRING_FIELD(cycle_path_column);
COPY_LOCATION_FIELD(location);
COPY_SCALAR_FIELD(cycle_mark_type);
COPY_SCALAR_FIELD(cycle_mark_typmod);
COPY_SCALAR_FIELD(cycle_mark_collation);
COPY_SCALAR_FIELD(cycle_mark_neop);
return newnode;
}
static CommonTableExpr *
_copyCommonTableExpr(const CommonTableExpr *from)
{
@@ -2598,6 +2630,8 @@ _copyCommonTableExpr(const CommonTableExpr *from)
COPY_NODE_FIELD(aliascolnames);
COPY_SCALAR_FIELD(ctematerialized);
COPY_NODE_FIELD(ctequery);
COPY_NODE_FIELD(search_clause);
COPY_NODE_FIELD(cycle_clause);
COPY_LOCATION_FIELD(location);
COPY_SCALAR_FIELD(cterecursive);
COPY_SCALAR_FIELD(cterefcount);
@@ -5682,6 +5716,12 @@ copyObjectImpl(const void *from)
case T_OnConflictClause:
retval = _copyOnConflictClause(from);
break;
case T_CTESearchClause:
retval = _copyCTESearchClause(from);
break;
case T_CTECycleClause:
retval = _copyCTECycleClause(from);
break;
case T_CommonTableExpr:
retval = _copyCommonTableExpr(from);
break;

View File

@@ -2841,6 +2841,34 @@ _equalOnConflictClause(const OnConflictClause *a, const OnConflictClause *b)
return true;
}
static bool
_equalCTESearchClause(const CTESearchClause *a, const CTESearchClause *b)
{
COMPARE_NODE_FIELD(search_col_list);
COMPARE_SCALAR_FIELD(search_breadth_first);
COMPARE_STRING_FIELD(search_seq_column);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalCTECycleClause(const CTECycleClause *a, const CTECycleClause *b)
{
COMPARE_NODE_FIELD(cycle_col_list);
COMPARE_STRING_FIELD(cycle_mark_column);
COMPARE_NODE_FIELD(cycle_mark_value);
COMPARE_NODE_FIELD(cycle_mark_default);
COMPARE_STRING_FIELD(cycle_path_column);
COMPARE_LOCATION_FIELD(location);
COMPARE_SCALAR_FIELD(cycle_mark_type);
COMPARE_SCALAR_FIELD(cycle_mark_typmod);
COMPARE_SCALAR_FIELD(cycle_mark_collation);
COMPARE_SCALAR_FIELD(cycle_mark_neop);
return true;
}
static bool
_equalCommonTableExpr(const CommonTableExpr *a, const CommonTableExpr *b)
{
@@ -2848,6 +2876,8 @@ _equalCommonTableExpr(const CommonTableExpr *a, const CommonTableExpr *b)
COMPARE_NODE_FIELD(aliascolnames);
COMPARE_SCALAR_FIELD(ctematerialized);
COMPARE_NODE_FIELD(ctequery);
COMPARE_NODE_FIELD(search_clause);
COMPARE_NODE_FIELD(cycle_clause);
COMPARE_LOCATION_FIELD(location);
COMPARE_SCALAR_FIELD(cterecursive);
COMPARE_SCALAR_FIELD(cterefcount);
@@ -3735,6 +3765,12 @@ equal(const void *a, const void *b)
case T_OnConflictClause:
retval = _equalOnConflictClause(a, b);
break;
case T_CTESearchClause:
retval = _equalCTESearchClause(a, b);
break;
case T_CTECycleClause:
retval = _equalCTECycleClause(a, b);
break;
case T_CommonTableExpr:
retval = _equalCommonTableExpr(a, b);
break;

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",

View File

@@ -3077,6 +3077,34 @@ _outWithClause(StringInfo str, const WithClause *node)
WRITE_LOCATION_FIELD(location);
}
static void
_outCTESearchClause(StringInfo str, const CTESearchClause *node)
{
WRITE_NODE_TYPE("CTESEARCHCLAUSE");
WRITE_NODE_FIELD(search_col_list);
WRITE_BOOL_FIELD(search_breadth_first);
WRITE_STRING_FIELD(search_seq_column);
WRITE_LOCATION_FIELD(location);
}
static void
_outCTECycleClause(StringInfo str, const CTECycleClause *node)
{
WRITE_NODE_TYPE("CTECYCLECLAUSE");
WRITE_NODE_FIELD(cycle_col_list);
WRITE_STRING_FIELD(cycle_mark_column);
WRITE_NODE_FIELD(cycle_mark_value);
WRITE_NODE_FIELD(cycle_mark_default);
WRITE_STRING_FIELD(cycle_path_column);
WRITE_LOCATION_FIELD(location);
WRITE_OID_FIELD(cycle_mark_type);
WRITE_INT_FIELD(cycle_mark_typmod);
WRITE_OID_FIELD(cycle_mark_collation);
WRITE_OID_FIELD(cycle_mark_neop);
}
static void
_outCommonTableExpr(StringInfo str, const CommonTableExpr *node)
{
@@ -3086,6 +3114,8 @@ _outCommonTableExpr(StringInfo str, const CommonTableExpr *node)
WRITE_NODE_FIELD(aliascolnames);
WRITE_ENUM_FIELD(ctematerialized, CTEMaterialize);
WRITE_NODE_FIELD(ctequery);
WRITE_NODE_FIELD(search_clause);
WRITE_NODE_FIELD(cycle_clause);
WRITE_LOCATION_FIELD(location);
WRITE_BOOL_FIELD(cterecursive);
WRITE_INT_FIELD(cterefcount);
@@ -4262,6 +4292,12 @@ outNode(StringInfo str, const void *obj)
case T_WithClause:
_outWithClause(str, obj);
break;
case T_CTESearchClause:
_outCTESearchClause(str, obj);
break;
case T_CTECycleClause:
_outCTECycleClause(str, obj);
break;
case T_CommonTableExpr:
_outCommonTableExpr(str, obj);
break;

View File

@@ -409,6 +409,44 @@ _readRowMarkClause(void)
READ_DONE();
}
/*
* _readCTESearchClause
*/
static CTESearchClause *
_readCTESearchClause(void)
{
READ_LOCALS(CTESearchClause);
READ_NODE_FIELD(search_col_list);
READ_BOOL_FIELD(search_breadth_first);
READ_STRING_FIELD(search_seq_column);
READ_LOCATION_FIELD(location);
READ_DONE();
}
/*
* _readCTECycleClause
*/
static CTECycleClause *
_readCTECycleClause(void)
{
READ_LOCALS(CTECycleClause);
READ_NODE_FIELD(cycle_col_list);
READ_STRING_FIELD(cycle_mark_column);
READ_NODE_FIELD(cycle_mark_value);
READ_NODE_FIELD(cycle_mark_default);
READ_STRING_FIELD(cycle_path_column);
READ_LOCATION_FIELD(location);
READ_OID_FIELD(cycle_mark_type);
READ_INT_FIELD(cycle_mark_typmod);
READ_OID_FIELD(cycle_mark_collation);
READ_OID_FIELD(cycle_mark_neop);
READ_DONE();
}
/*
* _readCommonTableExpr
*/
@@ -421,6 +459,8 @@ _readCommonTableExpr(void)
READ_NODE_FIELD(aliascolnames);
READ_ENUM_FIELD(ctematerialized, CTEMaterialize);
READ_NODE_FIELD(ctequery);
READ_NODE_FIELD(search_clause);
READ_NODE_FIELD(cycle_clause);
READ_LOCATION_FIELD(location);
READ_BOOL_FIELD(cterecursive);
READ_INT_FIELD(cterefcount);
@@ -2653,6 +2693,10 @@ parseNodeString(void)
return_value = _readWindowClause();
else if (MATCH("ROWMARKCLAUSE", 13))
return_value = _readRowMarkClause();
else if (MATCH("CTESEARCHCLAUSE", 15))
return_value = _readCTESearchClause();
else if (MATCH("CTECYCLECLAUSE", 14))
return_value = _readCTECycleClause();
else if (MATCH("COMMONTABLEEXPR", 15))
return_value = _readCommonTableExpr();
else if (MATCH("SETOPERATIONSTMT", 16))