From 91d56b2e522890cc0c3a1cf554c352e2b2ce7efd Mon Sep 17 00:00:00 2001 From: Henson Choi Date: Wed, 15 Jul 2026 08:25:12 +0900 Subject: [PATCH] Bound the END search in row pattern absorption analysis isUnboundedStart() walks ->next to the END that closes a group, exiting only when an element is shallower than the first child. With startDepth 0 that never happens -- RPRDepth is unsigned and even FIN has depth 0 -- so the walk runs past FIN, whose next is RPR_ELEMIDX_INVALID, and reads outside the element array. Stop at FIN instead and let the existing END test reject the sequence. No test accompanies this, and none can: the walk is not reachable with startDepth 0. Getting to it requires isFixedLengthChildren() to succeed at that depth, and it cannot, because the chain always ends at FIN, whose depth is 0 as well. FIN is neither a VAR nor a BEGIN, so at scope depth 0 it enters the loop body and falls to the branch that returns false. The bound is therefore defensive: it keeps the walk inside the array should that ever stop holding. --- src/backend/optimizer/plan/rpr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c index ea2c232a134..ef6f2163b17 100644 --- a/src/backend/optimizer/plan/rpr.c +++ b/src/backend/optimizer/plan/rpr.c @@ -1623,9 +1623,14 @@ isUnboundedStart(RPRPattern *pattern, RPRElemIdx idx) if (!isFixedLengthChildren(pattern, idx, startDepth)) return false; - /* Find the END element at startDepth - 1 */ + /* + * Find the END that closes the group beginning at idx, at startDepth - 1. + * FIN bounds the walk: depth alone cannot when startDepth is 0, and FIN's + * next is RPR_ELEMIDX_INVALID, so the walk would read outside the array. + * Only a tree optimizeRPRPattern() did not produce reaches it that way. + */ e = &pattern->elements[idx]; - while (e->depth >= startDepth) + while (e->depth >= startDepth && !RPRElemIsFin(e)) e = &pattern->elements[e->next]; /* END must be unbounded greedy */