From 64856e7964bb234e3d87599aafcc13a1d79902c9 Mon Sep 17 00:00:00 2001 From: Henson Choi Date: Thu, 26 Feb 2026 22:06:17 +0900 Subject: [PATCH 10/10] Remove redundant conditions in NFA executor --- src/backend/executor/nodeWindowAgg.c | 77 ++++++++++------------------ 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index cd41eff394e..701e83b519b 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -5066,8 +5066,8 @@ nfa_process_row(WindowAggState *winstate, int64 currentPos, bool *varMatched = winstate->nfaVarMatched; /* - * Phase 1: Match all contexts (convergence) Evaluate VAR elements, update - * counts, remove dead states. + * Phase 1: Match all contexts (convergence). Evaluate VAR elements, + * update counts, remove dead states. */ for (ctx = winstate->nfaContext; ctx != NULL; ctx = ctx->next) { @@ -5092,8 +5092,8 @@ nfa_process_row(WindowAggState *winstate, int64 currentPos, } /* - * Phase 2: Absorb redundant contexts After match phase, states have - * converged - ideal for absorption. First update absorption flags that + * Phase 2: Absorb redundant contexts. After match phase, states have + * converged - ideal for absorption. First update absorption flags that * may have changed due to state removal. */ if (winstate->rpPattern->isAbsorbable) @@ -5105,7 +5105,7 @@ nfa_process_row(WindowAggState *winstate, int64 currentPos, } /* - * Phase 3: Advance all contexts (divergence) Create new states + * Phase 3: Advance all contexts (divergence). Create new states * (loop/exit) from surviving matched states. */ for (ctx = winstate->nfaContext; ctx != NULL; ctx = ctx->next) @@ -5243,8 +5243,7 @@ nfa_states_equal(WindowAggState *winstate, RPRNFAState *s1, RPRNFAState *s2) elem = &pattern->elements[s1->elemIdx]; compareDepth = elem->depth + 1; /* depth 0 needs 1 count, etc. */ - if (compareDepth > 0 && - memcmp(s1->counts, s2->counts, sizeof(int32) * compareDepth) != 0) + if (memcmp(s1->counts, s2->counts, sizeof(int32) * compareDepth) != 0) return false; return true; @@ -5359,11 +5358,10 @@ nfa_context_alloc(WindowAggState *winstate) ctx->matchEndRow = -1; ctx->lastProcessedRow = -1; ctx->matchedState = NULL; + /* Initialize two-flag absorption design based on pattern */ - ctx->hasAbsorbableState = (winstate->rpPattern != NULL && - winstate->rpPattern->isAbsorbable); - ctx->allStatesAbsorbable = (winstate->rpPattern != NULL && - winstate->rpPattern->isAbsorbable); + ctx->hasAbsorbableState = winstate->rpPattern->isAbsorbable; + ctx->allStatesAbsorbable = winstate->rpPattern->isAbsorbable; /* Update statistics */ winstate->nfaContextsActive++; @@ -5436,40 +5434,23 @@ nfa_start_context(WindowAggState *winstate, int64 startPos) { RPRNFAContext *ctx; RPRPattern *pattern = winstate->rpPattern; + RPRPatternElement *elem; ctx = nfa_context_alloc(winstate); ctx->matchStartRow = startPos; ctx->states = nfa_state_alloc(winstate); /* initial state at elem 0 */ - /*-------------------------- - * Initialize two-flag absorption design: - * hasAbsorbableState: can this context absorb others? (>= 1 absorbable state) - * allStatesAbsorbable: can this context be absorbed? (ALL states absorbable) - * Both initialized from pattern->isAbsorbable at context start. - */ - ctx->hasAbsorbableState = (pattern != NULL && pattern->isAbsorbable); - ctx->allStatesAbsorbable = (pattern != NULL && pattern->isAbsorbable); + elem = &pattern->elements[0]; - if (ctx->states != NULL && pattern != NULL && pattern->numElements > 0) + if (RPRElemIsAbsorbableBranch(elem)) { - RPRPatternElement *elem = &pattern->elements[0]; - - /* - * Initial state at element 0. Check if element 0 is in absorbable - * branch. - */ - if (RPRElemIsAbsorbableBranch(elem)) - { - /* Element 0 is in absorbable branch - flags stay true */ - ctx->states->isAbsorbable = true; - } - else - { - /* Element 0 is NOT in absorbable branch - turn flags OFF */ - ctx->hasAbsorbableState = false; - ctx->allStatesAbsorbable = false; - ctx->states->isAbsorbable = false; - } + ctx->states->isAbsorbable = true; + } + else + { + ctx->hasAbsorbableState = false; + ctx->allStatesAbsorbable = false; + ctx->states->isAbsorbable = false; } /* Add to tail of active context list (doubly-linked, oldest-first) */ @@ -6369,11 +6350,8 @@ nfa_advance_var(WindowAggState *winstate, RPRNFAContext *ctx, cloneState->counts[depth] = 0; nextElem = &elements[cloneState->elemIdx]; - /* - * When exiting directly to an outer END, increment the END's - * iteration count. - */ - if (RPRElemIsEnd(nextElem) && count > 0) + /* When exiting directly to an outer END, increment its count */ + if (RPRElemIsEnd(nextElem)) { if (cloneState->counts[nextElem->depth] < RPR_COUNT_MAX) cloneState->counts[nextElem->depth]++; @@ -6411,14 +6389,11 @@ nfa_advance_var(WindowAggState *winstate, RPRNFAContext *ctx, nextElem = &elements[state->elemIdx]; /* - * When exiting directly to an outer END, increment the END's - * iteration count. Simple VARs (min=max=1) handle this via - * inline advance in nfa_match, but quantified VARs bypass that - * path. Only increment when the VAR actually consumed rows - * (count > 0) to preserve cycle prevention for zero-progress - * loops. + * When exiting directly to an outer END, increment its iteration + * count. Simple VARs (min=max=1) handle this via inline advance + * in nfa_match, but quantified VARs bypass that path. */ - if (RPRElemIsEnd(nextElem) && count > 0) + if (RPRElemIsEnd(nextElem)) { if (state->counts[nextElem->depth] < RPR_COUNT_MAX) state->counts[nextElem->depth]++; @@ -6443,7 +6418,7 @@ nfa_advance_var(WindowAggState *winstate, RPRNFAContext *ctx, nextElem = &elements[state->elemIdx]; /* See comment above: increment outer END count for quantified VARs */ - if (RPRElemIsEnd(nextElem) && count > 0) + if (RPRElemIsEnd(nextElem)) { if (state->counts[nextElem->depth] < RPR_COUNT_MAX) state->counts[nextElem->depth]++; -- 2.50.1 (Apple Git-155)