nocfbot-0046-Tidy-up-forward-declarations-and-helper-placement.txt
text/plain
Filename: nocfbot-0046-Tidy-up-forward-declarations-and-helper-placement.txt
Type: text/plain
Part: 44
Message:
Re: Row pattern recognition
From a750e9af053c82f3d60ebcce0fb51840266c665e Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Fri, 5 Jun 2026 12:32:38 +0900
Subject: [PATCH 46/68] Tidy up forward declarations and helper placement for
row pattern recognition
Bring the row pattern recognition code in line with the surrounding
conventions for static helpers:
- each static helper has a forward declaration;
- static helpers are defined above the "API exposed" banner, public
entry points below;
- the forward-declaration block uses a single banner, not per-group
labels;
- forward declarations follow definition order.
Pure code movement and comments, no behavior change.
Per review comments from Tatsuo Ishii and Jian He.
---
src/backend/executor/execRPR.c | 108 ++++---
src/backend/executor/nodeWindowAgg.c | 454 +++++++++++++--------------
src/backend/optimizer/plan/rpr.c | 12 +-
src/backend/parser/parse_rpr.c | 2 +-
4 files changed, 288 insertions(+), 288 deletions(-)
diff --git a/src/backend/executor/execRPR.c b/src/backend/executor/execRPR.c
index 61d94684e03..9bed6eab1c2 100644
--- a/src/backend/executor/execRPR.c
+++ b/src/backend/executor/execRPR.c
@@ -83,8 +83,6 @@ static bool nfa_eval_var_match(WindowAggState *winstate,
RPRPatternElement *elem, bool *varMatched);
static void nfa_match(WindowAggState *winstate, RPRNFAContext *ctx,
bool *varMatched);
-static void nfa_advance_state(WindowAggState *winstate, RPRNFAContext *ctx,
- RPRNFAState *state, int64 currentPos);
static void nfa_route_to_elem(WindowAggState *winstate, RPRNFAContext *ctx,
RPRNFAState *state, RPRPatternElement *nextElem,
int64 currentPos);
@@ -100,9 +98,15 @@ static void nfa_advance_end(WindowAggState *winstate, RPRNFAContext *ctx,
static void nfa_advance_var(WindowAggState *winstate, RPRNFAContext *ctx,
RPRNFAState *state, RPRPatternElement *elem,
int64 currentPos);
+static void nfa_advance_state(WindowAggState *winstate, RPRNFAContext *ctx,
+ RPRNFAState *state, int64 currentPos);
static void nfa_advance(WindowAggState *winstate, RPRNFAContext *ctx,
int64 currentPos);
+static void nfa_reevaluate_dependent_vars(WindowAggState *winstate,
+ RPRNFAContext *ctx,
+ int64 currentPos);
+
/*
* NFA-based pattern matching implementation
*
@@ -1552,6 +1556,56 @@ nfa_advance(WindowAggState *winstate, RPRNFAContext *ctx, int64 currentPos)
}
}
+/*
+ * nfa_reevaluate_dependent_vars
+ * Re-evaluate match_start-dependent DEFINE variables for a specific
+ * context whose matchStartRow differs from the shared evaluation's
+ * nav_match_start.
+ *
+ * Only variables in defineMatchStartDependent are re-evaluated. The
+ * current row's slot (ecxt_outertuple) must already be set up by
+ * nfa_evaluate_row().
+ */
+static void
+nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
+ int64 currentPos)
+{
+ ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
+ int64 saved_match_start = winstate->nav_match_start;
+ int64 saved_pos = winstate->currentpos;
+ int varIdx = 0;
+ ListCell *lc;
+
+ /* Temporarily set nav_match_start and currentpos for FIRST/LAST */
+ winstate->nav_match_start = ctx->matchStartRow;
+ winstate->currentpos = currentPos;
+
+ /* Invalidate nav_slot cache since match_start changed */
+ winstate->nav_slot_pos = -1;
+
+ foreach(lc, winstate->defineClauseList)
+ {
+ if (bms_is_member(varIdx, winstate->defineMatchStartDependent))
+ {
+ ExprState *exprState = (ExprState *) lfirst(lc);
+ Datum result;
+ bool isnull;
+
+ result = ExecEvalExpr(exprState, econtext, &isnull);
+ winstate->nfaVarMatched[varIdx] = (!isnull && DatumGetBool(result));
+ }
+
+ varIdx++;
+ if (varIdx >= list_length(winstate->defineVariableList))
+ break;
+ }
+
+ /* Restore original match_start, currentpos, and invalidate cache */
+ winstate->nav_match_start = saved_match_start;
+ winstate->currentpos = saved_pos;
+ winstate->nav_slot_pos = -1;
+}
+
/***********************************************************************
* API exposed to nodeWindowAgg.c
@@ -1696,56 +1750,6 @@ ExecRPRRecordContextFailure(WindowAggState *winstate, int64 failedLen)
}
}
-/*
- * nfa_reevaluate_dependent_vars
- * Re-evaluate match_start-dependent DEFINE variables for a specific
- * context whose matchStartRow differs from the shared evaluation's
- * nav_match_start.
- *
- * Only variables in defineMatchStartDependent are re-evaluated. The
- * current row's slot (ecxt_outertuple) must already be set up by
- * nfa_evaluate_row().
- */
-static void
-nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
- int64 currentPos)
-{
- ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
- int64 saved_match_start = winstate->nav_match_start;
- int64 saved_pos = winstate->currentpos;
- int varIdx = 0;
- ListCell *lc;
-
- /* Temporarily set nav_match_start and currentpos for FIRST/LAST */
- winstate->nav_match_start = ctx->matchStartRow;
- winstate->currentpos = currentPos;
-
- /* Invalidate nav_slot cache since match_start changed */
- winstate->nav_slot_pos = -1;
-
- foreach(lc, winstate->defineClauseList)
- {
- if (bms_is_member(varIdx, winstate->defineMatchStartDependent))
- {
- ExprState *exprState = (ExprState *) lfirst(lc);
- Datum result;
- bool isnull;
-
- result = ExecEvalExpr(exprState, econtext, &isnull);
- winstate->nfaVarMatched[varIdx] = (!isnull && DatumGetBool(result));
- }
-
- varIdx++;
- if (varIdx >= list_length(winstate->defineVariableList))
- break;
- }
-
- /* Restore original match_start, currentpos, and invalidate cache */
- winstate->nav_match_start = saved_match_start;
- winstate->currentpos = saved_pos;
- winstate->nav_slot_pos = -1;
-}
-
/*
* ExecRPRProcessRow
*
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 0b0196e7e40..8a3535e03f9 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -4621,6 +4621,233 @@ nfa_evaluate_row(WindowObject winobj, int64 pos, bool *varMatched)
return true; /* Row exists */
}
+/*
+ * WinGetSlotInFrame
+ * slot: TupleTableSlot to store the result
+ * relpos: signed rowcount offset from the seek position
+ * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL
+ * set_mark: If the row is found/in frame and set_mark is true, the mark is
+ * moved to the row as a side-effect.
+ * isnull: output argument, receives isnull status of result
+ * isout: output argument, set to indicate whether target row position
+ * is out of frame (can pass NULL if caller doesn't care about this)
+ *
+ * Returns 0 if we successfully got the slot, or nonzero if out of frame.
+ * (isout is also set in the latter case.)
+ */
+static int
+WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
+ int relpos, int seektype, bool set_mark,
+ bool *isnull, bool *isout)
+{
+ WindowAggState *winstate;
+ int64 abs_pos;
+ int64 mark_pos;
+ int64 num_reduced_frame;
+
+ Assert(WindowObjectIsValid(winobj));
+ winstate = winobj->winstate;
+
+ switch (seektype)
+ {
+ case WINDOW_SEEK_CURRENT:
+ elog(ERROR, "WINDOW_SEEK_CURRENT is not supported for WinGetFuncArgInFrame");
+ abs_pos = mark_pos = 0; /* keep compiler quiet */
+ break;
+ case WINDOW_SEEK_HEAD:
+ /* rejecting relpos < 0 is easy and simplifies code below */
+ if (relpos < 0)
+ goto out_of_frame;
+ update_frameheadpos(winstate);
+ abs_pos = winstate->frameheadpos + relpos;
+ mark_pos = abs_pos;
+
+ /*
+ * Account for exclusion option if one is active, but advance only
+ * abs_pos not mark_pos. This prevents changes of the current
+ * row's peer group from resulting in trying to fetch a row before
+ * some previous mark position.
+ *
+ * Note that in some corner cases such as current row being
+ * outside frame, these calculations are theoretically too simple,
+ * but it doesn't matter because we'll end up deciding the row is
+ * out of frame. We do not attempt to avoid fetching rows past
+ * end of frame; that would happen in some cases anyway.
+ */
+ switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
+ {
+ case 0:
+ /* no adjustment needed */
+ break;
+ case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
+ if (abs_pos >= winstate->currentpos &&
+ winstate->currentpos >= winstate->frameheadpos)
+ abs_pos++;
+ break;
+ case FRAMEOPTION_EXCLUDE_GROUP:
+ update_grouptailpos(winstate);
+ if (abs_pos >= winstate->groupheadpos &&
+ winstate->grouptailpos > winstate->frameheadpos)
+ {
+ int64 overlapstart = Max(winstate->groupheadpos,
+ winstate->frameheadpos);
+
+ abs_pos += winstate->grouptailpos - overlapstart;
+ }
+ break;
+ case FRAMEOPTION_EXCLUDE_TIES:
+ update_grouptailpos(winstate);
+ if (abs_pos >= winstate->groupheadpos &&
+ winstate->grouptailpos > winstate->frameheadpos)
+ {
+ int64 overlapstart = Max(winstate->groupheadpos,
+ winstate->frameheadpos);
+
+ if (abs_pos == overlapstart)
+ abs_pos = winstate->currentpos;
+ else
+ abs_pos += winstate->grouptailpos - overlapstart - 1;
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized frame option state: 0x%x",
+ winstate->frameOptions);
+ break;
+ }
+ num_reduced_frame = row_is_in_reduced_frame(winobj,
+ winstate->frameheadpos);
+ if (num_reduced_frame < 0)
+ goto out_of_frame;
+ else if (num_reduced_frame > 0)
+ if (relpos >= num_reduced_frame)
+ goto out_of_frame;
+ break;
+ case WINDOW_SEEK_TAIL:
+ /* rejecting relpos > 0 is easy and simplifies code below */
+ if (relpos > 0)
+ goto out_of_frame;
+
+ /*
+ * RPR cares about frame head pos. Need to call
+ * update_frameheadpos
+ */
+ update_frameheadpos(winstate);
+
+ update_frametailpos(winstate);
+ abs_pos = winstate->frametailpos - 1 + relpos;
+
+ /*
+ * Account for exclusion option if one is active. If there is no
+ * exclusion, we can safely set the mark at the accessed row. But
+ * if there is, we can only mark the frame start, because we can't
+ * be sure how far back in the frame the exclusion might cause us
+ * to fetch in future. Furthermore, we have to actually check
+ * against frameheadpos here, since it's unsafe to try to fetch a
+ * row before frame start if the mark might be there already.
+ */
+ switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
+ {
+ case 0:
+ /* no adjustment needed */
+ mark_pos = abs_pos;
+ break;
+ case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
+ if (abs_pos <= winstate->currentpos &&
+ winstate->currentpos < winstate->frametailpos)
+ abs_pos--;
+ update_frameheadpos(winstate);
+ if (abs_pos < winstate->frameheadpos)
+ goto out_of_frame;
+ mark_pos = winstate->frameheadpos;
+ break;
+ case FRAMEOPTION_EXCLUDE_GROUP:
+ update_grouptailpos(winstate);
+ if (abs_pos < winstate->grouptailpos &&
+ winstate->groupheadpos < winstate->frametailpos)
+ {
+ int64 overlapend = Min(winstate->grouptailpos,
+ winstate->frametailpos);
+
+ abs_pos -= overlapend - winstate->groupheadpos;
+ }
+ update_frameheadpos(winstate);
+ if (abs_pos < winstate->frameheadpos)
+ goto out_of_frame;
+ mark_pos = winstate->frameheadpos;
+ break;
+ case FRAMEOPTION_EXCLUDE_TIES:
+ update_grouptailpos(winstate);
+ if (abs_pos < winstate->grouptailpos &&
+ winstate->groupheadpos < winstate->frametailpos)
+ {
+ int64 overlapend = Min(winstate->grouptailpos,
+ winstate->frametailpos);
+
+ if (abs_pos == overlapend - 1)
+ abs_pos = winstate->currentpos;
+ else
+ abs_pos -= overlapend - 1 - winstate->groupheadpos;
+ }
+ update_frameheadpos(winstate);
+ if (abs_pos < winstate->frameheadpos)
+ goto out_of_frame;
+ mark_pos = winstate->frameheadpos;
+ break;
+ default:
+ elog(ERROR, "unrecognized frame option state: 0x%x",
+ winstate->frameOptions);
+ mark_pos = 0; /* keep compiler quiet */
+ break;
+ }
+
+ num_reduced_frame = row_is_in_reduced_frame(winobj,
+ winstate->frameheadpos);
+ if (num_reduced_frame < 0)
+ goto out_of_frame;
+ else if (num_reduced_frame > 0)
+ {
+ if (-relpos >= num_reduced_frame)
+ goto out_of_frame;
+ abs_pos = winstate->frameheadpos + relpos +
+ num_reduced_frame - 1;
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized window seek type: %d", seektype);
+ abs_pos = mark_pos = 0; /* keep compiler quiet */
+ break;
+ }
+
+ if (!window_gettupleslot(winobj, abs_pos, slot))
+ goto out_of_frame;
+
+ /* The code above does not detect all out-of-frame cases, so check */
+ if (row_is_in_frame(winobj, abs_pos, slot, false) <= 0)
+ goto out_of_frame;
+
+ if (isout)
+ *isout = false;
+ if (set_mark)
+ {
+ /*
+ * If RPR is enabled and seek type is WINDOW_SEEK_TAIL, we set the
+ * mark position unconditionally to frameheadpos. In this case the
+ * frame always starts at CURRENT_ROW and never goes back, thus
+ * setting the mark at the position is safe.
+ */
+ if (winstate->rpPattern != NULL && seektype == WINDOW_SEEK_TAIL)
+ mark_pos = winstate->frameheadpos;
+ WinSetMarkPosition(winobj, mark_pos);
+ }
+ return 0;
+
+out_of_frame:
+ if (isout)
+ *isout = true;
+ *isnull = true;
+ return -1;
+}
+
/***********************************************************************
* API exposed to window functions
@@ -5013,233 +5240,6 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
return (Datum) 0;
}
-/*
- * WinGetSlotInFrame
- * slot: TupleTableSlot to store the result
- * relpos: signed rowcount offset from the seek position
- * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL
- * set_mark: If the row is found/in frame and set_mark is true, the mark is
- * moved to the row as a side-effect.
- * isnull: output argument, receives isnull status of result
- * isout: output argument, set to indicate whether target row position
- * is out of frame (can pass NULL if caller doesn't care about this)
- *
- * Returns 0 if we successfully got the slot, or nonzero if out of frame.
- * (isout is also set in the latter case.)
- */
-static int
-WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
- int relpos, int seektype, bool set_mark,
- bool *isnull, bool *isout)
-{
- WindowAggState *winstate;
- int64 abs_pos;
- int64 mark_pos;
- int64 num_reduced_frame;
-
- Assert(WindowObjectIsValid(winobj));
- winstate = winobj->winstate;
-
- switch (seektype)
- {
- case WINDOW_SEEK_CURRENT:
- elog(ERROR, "WINDOW_SEEK_CURRENT is not supported for WinGetFuncArgInFrame");
- abs_pos = mark_pos = 0; /* keep compiler quiet */
- break;
- case WINDOW_SEEK_HEAD:
- /* rejecting relpos < 0 is easy and simplifies code below */
- if (relpos < 0)
- goto out_of_frame;
- update_frameheadpos(winstate);
- abs_pos = winstate->frameheadpos + relpos;
- mark_pos = abs_pos;
-
- /*
- * Account for exclusion option if one is active, but advance only
- * abs_pos not mark_pos. This prevents changes of the current
- * row's peer group from resulting in trying to fetch a row before
- * some previous mark position.
- *
- * Note that in some corner cases such as current row being
- * outside frame, these calculations are theoretically too simple,
- * but it doesn't matter because we'll end up deciding the row is
- * out of frame. We do not attempt to avoid fetching rows past
- * end of frame; that would happen in some cases anyway.
- */
- switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
- {
- case 0:
- /* no adjustment needed */
- break;
- case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
- if (abs_pos >= winstate->currentpos &&
- winstate->currentpos >= winstate->frameheadpos)
- abs_pos++;
- break;
- case FRAMEOPTION_EXCLUDE_GROUP:
- update_grouptailpos(winstate);
- if (abs_pos >= winstate->groupheadpos &&
- winstate->grouptailpos > winstate->frameheadpos)
- {
- int64 overlapstart = Max(winstate->groupheadpos,
- winstate->frameheadpos);
-
- abs_pos += winstate->grouptailpos - overlapstart;
- }
- break;
- case FRAMEOPTION_EXCLUDE_TIES:
- update_grouptailpos(winstate);
- if (abs_pos >= winstate->groupheadpos &&
- winstate->grouptailpos > winstate->frameheadpos)
- {
- int64 overlapstart = Max(winstate->groupheadpos,
- winstate->frameheadpos);
-
- if (abs_pos == overlapstart)
- abs_pos = winstate->currentpos;
- else
- abs_pos += winstate->grouptailpos - overlapstart - 1;
- }
- break;
- default:
- elog(ERROR, "unrecognized frame option state: 0x%x",
- winstate->frameOptions);
- break;
- }
- num_reduced_frame = row_is_in_reduced_frame(winobj,
- winstate->frameheadpos);
- if (num_reduced_frame < 0)
- goto out_of_frame;
- else if (num_reduced_frame > 0)
- if (relpos >= num_reduced_frame)
- goto out_of_frame;
- break;
- case WINDOW_SEEK_TAIL:
- /* rejecting relpos > 0 is easy and simplifies code below */
- if (relpos > 0)
- goto out_of_frame;
-
- /*
- * RPR cares about frame head pos. Need to call
- * update_frameheadpos
- */
- update_frameheadpos(winstate);
-
- update_frametailpos(winstate);
- abs_pos = winstate->frametailpos - 1 + relpos;
-
- /*
- * Account for exclusion option if one is active. If there is no
- * exclusion, we can safely set the mark at the accessed row. But
- * if there is, we can only mark the frame start, because we can't
- * be sure how far back in the frame the exclusion might cause us
- * to fetch in future. Furthermore, we have to actually check
- * against frameheadpos here, since it's unsafe to try to fetch a
- * row before frame start if the mark might be there already.
- */
- switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
- {
- case 0:
- /* no adjustment needed */
- mark_pos = abs_pos;
- break;
- case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
- if (abs_pos <= winstate->currentpos &&
- winstate->currentpos < winstate->frametailpos)
- abs_pos--;
- update_frameheadpos(winstate);
- if (abs_pos < winstate->frameheadpos)
- goto out_of_frame;
- mark_pos = winstate->frameheadpos;
- break;
- case FRAMEOPTION_EXCLUDE_GROUP:
- update_grouptailpos(winstate);
- if (abs_pos < winstate->grouptailpos &&
- winstate->groupheadpos < winstate->frametailpos)
- {
- int64 overlapend = Min(winstate->grouptailpos,
- winstate->frametailpos);
-
- abs_pos -= overlapend - winstate->groupheadpos;
- }
- update_frameheadpos(winstate);
- if (abs_pos < winstate->frameheadpos)
- goto out_of_frame;
- mark_pos = winstate->frameheadpos;
- break;
- case FRAMEOPTION_EXCLUDE_TIES:
- update_grouptailpos(winstate);
- if (abs_pos < winstate->grouptailpos &&
- winstate->groupheadpos < winstate->frametailpos)
- {
- int64 overlapend = Min(winstate->grouptailpos,
- winstate->frametailpos);
-
- if (abs_pos == overlapend - 1)
- abs_pos = winstate->currentpos;
- else
- abs_pos -= overlapend - 1 - winstate->groupheadpos;
- }
- update_frameheadpos(winstate);
- if (abs_pos < winstate->frameheadpos)
- goto out_of_frame;
- mark_pos = winstate->frameheadpos;
- break;
- default:
- elog(ERROR, "unrecognized frame option state: 0x%x",
- winstate->frameOptions);
- mark_pos = 0; /* keep compiler quiet */
- break;
- }
-
- num_reduced_frame = row_is_in_reduced_frame(winobj,
- winstate->frameheadpos);
- if (num_reduced_frame < 0)
- goto out_of_frame;
- else if (num_reduced_frame > 0)
- {
- if (-relpos >= num_reduced_frame)
- goto out_of_frame;
- abs_pos = winstate->frameheadpos + relpos +
- num_reduced_frame - 1;
- }
- break;
- default:
- elog(ERROR, "unrecognized window seek type: %d", seektype);
- abs_pos = mark_pos = 0; /* keep compiler quiet */
- break;
- }
-
- if (!window_gettupleslot(winobj, abs_pos, slot))
- goto out_of_frame;
-
- /* The code above does not detect all out-of-frame cases, so check */
- if (row_is_in_frame(winobj, abs_pos, slot, false) <= 0)
- goto out_of_frame;
-
- if (isout)
- *isout = false;
- if (set_mark)
- {
- /*
- * If RPR is enabled and seek type is WINDOW_SEEK_TAIL, we set the
- * mark position unconditionally to frameheadpos. In this case the
- * frame always starts at CURRENT_ROW and never goes back, thus
- * setting the mark at the position is safe.
- */
- if (winstate->rpPattern != NULL && seektype == WINDOW_SEEK_TAIL)
- mark_pos = winstate->frameheadpos;
- WinSetMarkPosition(winobj, mark_pos);
- }
- return 0;
-
-out_of_frame:
- if (isout)
- *isout = true;
- *isnull = true;
- return -1;
-}
-
/*
* WinGetFuncArgCurrent
* Evaluate a window function's argument expression on the current row.
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 3205559c03a..43114088c3f 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -44,14 +44,12 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/rpr.h"
-/* Forward declarations - pattern comparison */
+/* Forward declarations */
static bool rprPatternEqual(RPRPatternNode *a, RPRPatternNode *b);
static bool rprPatternChildrenEqual(List *a, List *b);
-/* Forward declarations - pattern optimization (shared) */
static RPRPatternNode *tryUnwrapSingleChild(RPRPatternNode *pattern);
-/* Forward declarations - SEQ optimization */
static List *flattenSeqChildren(List *children);
static List *mergeConsecutiveVars(List *children);
static List *mergeConsecutiveGroups(List *children);
@@ -59,20 +57,16 @@ static List *mergeConsecutiveAlts(List *children);
static List *mergeGroupPrefixSuffix(List *children);
static RPRPatternNode *optimizeSeqPattern(RPRPatternNode *pattern);
-/* Forward declarations - ALT optimization */
static List *flattenAltChildren(List *children);
static List *removeDuplicateAlternatives(List *children);
static RPRPatternNode *optimizeAltPattern(RPRPatternNode *pattern);
-/* Forward declarations - GROUP optimization */
static RPRPatternNode *tryMultiplyQuantifiers(RPRPatternNode *pattern);
static RPRPatternNode *tryUnwrapGroup(RPRPatternNode *pattern);
static RPRPatternNode *optimizeGroupPattern(RPRPatternNode *pattern);
-/* Forward declarations - optimization dispatcher */
static RPRPatternNode *optimizeRPRPattern(RPRPatternNode *pattern);
-/* Forward declarations - pattern compilation */
static int collectDefineVariables(List *defineVariableList, char **varNames);
static void scanRPRPatternRecursive(RPRPatternNode *node, char **varNames,
int *numVars, int *numElements,
@@ -92,7 +86,6 @@ static bool fillRPRPattern(RPRPatternNode *node, RPRPattern *pat,
int *idx, RPRDepth depth);
static void finalizeRPRPattern(RPRPattern *result);
-/* Forward declarations - context absorption */
static bool isFixedLengthChildren(RPRPattern *pattern, RPRElemIdx idx,
RPRDepth scopeDepth);
static bool isUnboundedStart(RPRPattern *pattern, RPRElemIdx idx);
@@ -101,6 +94,9 @@ static void computeAbsorbabilityRecursive(RPRPattern *pattern,
bool *hasAbsorbable);
static void computeAbsorbability(RPRPattern *pattern);
+static void collectPatternVariablesRecursive(RPRPatternNode *node,
+ List **varNames);
+
/*
* rprPatternEqual
* Compare two RPRPatternNode trees for equality.
diff --git a/src/backend/parser/parse_rpr.c b/src/backend/parser/parse_rpr.c
index 3872035110a..c9469b56b7b 100644
--- a/src/backend/parser/parse_rpr.c
+++ b/src/backend/parser/parse_rpr.c
@@ -61,8 +61,8 @@ static void validateRPRPatternVarCount(ParseState *pstate, RPRPatternNode *node,
List *rpDefs, List **varNames);
static List *transformDefineClause(ParseState *pstate, WindowClause *wc,
WindowDef *windef, List **targetlist);
-static bool define_walker(Node *node, void *context);
static bool nav_volatile_func_checker(Oid funcid, void *context);
+static bool define_walker(Node *node, void *context);
/*
* transformRPR
--
2.50.1 (Apple Git-155)