nocfbot-0010-redundant-conditions.txt

text/plain

Filename: nocfbot-0010-redundant-conditions.txt
Type: text/plain
Part: 9
Message: Re: Row pattern recognition
From 64856e7964bb234e3d87599aafcc13a1d79902c9 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
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)