Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vuibV-002xjU-0p for pgsql-hackers@arkaria.postgresql.org; Tue, 24 Feb 2026 02:56:53 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vuibT-00GWg5-0w for pgsql-hackers@arkaria.postgresql.org; Tue, 24 Feb 2026 02:56:51 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vuibS-00GWfx-2y for pgsql-hackers@lists.postgresql.org; Tue, 24 Feb 2026 02:56:50 +0000 Received: from meldrar.postgresql.org ([2a02:c0:301:0:ffff::31]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vuibN-00000000tQX-3tFt for pgsql-hackers@postgresql.org; Tue, 24 Feb 2026 02:56:50 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Content-Transfer-Encoding:Content-Type: Mime-Version:References:In-Reply-To:From:Subject:Cc:To:Message-Id:Date:Sender :Reply-To:Content-ID:Content-Description; bh=jeQ7MWj5gwQxAzfYD8BDBJDigymZ4tv/4M3RUOeCe+s=; b=jE3xdcWtHzwUkhiPRtDkh3uOVl fyRRxaFToNyPhOHaLBdtKGTwpWGo244cvUBd+PWDp/eGpfo6m6XoRY8GQHlLtPPiX6e+FwvGc8uAA vIVibBG+ZOb8l5KxjaJQOQidZyzhu6hmQNhHdFjCfs6kW4MvetEKo5ivcij/whBQEeo6DS0dGiAsu xprYgGrhfx2PgzzOmibbqaa79XbNYrlvXr7BdOdqItE4dF0BCU7Cm7sITExekDX9QaXN3nIVNpeor zXab5FQdhJ0Yhwj96Z3djoj4TmKaRK/Qb4rjQDbRcPgr7BUYkPxsWftztY1KTtF9KR1hry/i3a3Ao fCzq4bEA==; Received: from [2409:11:4120:300:c394:7646:7fb3:ecf2] (helo=localhost) by meldrar.postgresql.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vuibG-0029PX-0k; Tue, 24 Feb 2026 02:56:41 +0000 Date: Tue, 24 Feb 2026 11:56:25 +0900 (JST) Message-Id: <20260224.115625.1966558814200895991.ishii@postgresql.org> To: assam258@gmail.com Cc: vik@postgresfriends.org, er@xs4all.nl, jacob.champion@enterprisedb.com, david.g.johnston@gmail.com, peter@eisentraut.org, pgsql-hackers@postgresql.org Subject: Re: Row pattern recognition From: Tatsuo Ishii In-Reply-To: References: <20260223.192646.1862474650359229532.ishii@postgresql.org> X-Mailer: Mew version 6.8 on Emacs 29.3 Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="--Next_Part(Tue_Feb_24_11_56_25_2026_815)--" Content-Transfer-Encoding: 7bit X-Host-Lookup-Failed: Reverse DNS lookup failed for 2409:11:4120:300:c394:7646:7fb3:ecf2 (failed) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ----Next_Part(Tue_Feb_24_11_56_25_2026_815)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hi Henson, > Hi Tatsuo, > > Here are six incremental patches on top of v43. > > nocfbot-0001 through nocfbot-0004 are the same patches from the > previous round (32-bit test fix, PREV/NEXT restriction, ALT lexical > ordering, reluctant quantifiers). > > nocfbot-0005: Detect zero-consumption NFA cycles > > Adds a per-element visited bitmap to detect zero-consumption cycles > during DFS epsilon expansion. Before each state's DFS, the bitmap > is cleared; as nfa_advance_state() recurses through epsilon > transitions, each elemIdx is marked visited. If the same elemIdx > is reached again within the same DFS, it means an epsilon-only > loop -- the state is freed immediately. > > The ad-hoc (count == 0 && min == 0) exit condition in > nfa_advance_end() is removed. The FIXME test cases are resolved > and renamed to "Zero-Consumption Cycle Detection". > > nocfbot-0006: Allow A{0} quantifier > > With cycle detection in place, this becomes straightforward. > Lowers the {n} bound minimum from 1 to 0. A{0} is treated as an > epsilon transition -- the variable is skipped entirely. Great! > Next I plan to work on test reorganization, cross-database result > comparison, and a review pass over the NFA executor. Looking forward to seeing next patches. BTW, in create_windowagg_plan (createplan.c), around: /* Build RPR pattern and filter defineClause */ collectPatternVariables, filterDefineClause and buildRPRPattern are called in a block without any if or any other conditional statements. This is an unusual codiing style in PostgreSQL. I suggest to fix this. Attached is a proposed patch for this. Best regards, -- Tatsuo Ishii SRA OSS K.K. English: http://www.sraoss.co.jp/index_en/ Japanese:http://www.sraoss.co.jp ----Next_Part(Tue_Feb_24_11_56_25_2026_815)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="fix_plan.txt" diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index bbc2c7e71f4..e7aafc89700 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2484,6 +2484,10 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path) Oid *ordOperators; Oid *ordCollations; ListCell *lc; + List *defineVariableList = NIL; + List *filteredDefineClause = NIL; + RPRPattern *compiledPattern = NULL; + /* * Choice of tlist here is motivated by the fact that WindowAgg will be @@ -2535,50 +2539,45 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path) } /* Build RPR pattern and filter defineClause */ + if (wc->rpPattern) { - List *defineVariableList = NIL; - List *filteredDefineClause = NIL; - RPRPattern *compiledPattern = NULL; - - if (wc->rpPattern) - { - List *patternVars; + List *patternVars; - /* - * Filter defineClause to include only variables used in PATTERN. - * This eliminates unnecessary DEFINE evaluations at runtime. - */ - patternVars = collectPatternVariables(wc->rpPattern); - filteredDefineClause = filterDefineClause(wc->defineClause, - patternVars, - &defineVariableList); - - compiledPattern = buildRPRPattern(wc->rpPattern, - defineVariableList, - wc->rpSkipTo, - wc->frameOptions); - } - - /* And finally we can make the WindowAgg node */ - plan = make_windowagg(tlist, - wc, - partNumCols, - partColIdx, - partOperators, - partCollations, - ordNumCols, - ordColIdx, - ordOperators, - ordCollations, - best_path->runCondition, - wc->rpSkipTo, - compiledPattern, - filteredDefineClause, - best_path->qual, - best_path->topwindow, - subplan); + /* + * Filter defineClause to include only variables used in PATTERN. This + * eliminates unnecessary DEFINE evaluations at runtime. + */ + patternVars = collectPatternVariables(wc->rpPattern); + filteredDefineClause = filterDefineClause(wc->defineClause, + patternVars, + &defineVariableList); + + /* Compile and optimize RPR patterns */ + compiledPattern = buildRPRPattern(wc->rpPattern, + defineVariableList, + wc->rpSkipTo, + wc->frameOptions); } + /* And finally we can make the WindowAgg node */ + plan = make_windowagg(tlist, + wc, + partNumCols, + partColIdx, + partOperators, + partCollations, + ordNumCols, + ordColIdx, + ordOperators, + ordCollations, + best_path->runCondition, + wc->rpSkipTo, + compiledPattern, + filteredDefineClause, + best_path->qual, + best_path->topwindow, + subplan); + copy_generic_path_info(&plan->plan, (Path *) best_path); return plan; ----Next_Part(Tue_Feb_24_11_56_25_2026_815)----