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.98.2) (envelope-from ) id 1xIbd2-00000003msV-0Nu9 for pgsql-hackers@arkaria.postgresql.org; Mon, 19 Oct 2026 00:53:28 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1xIbd0-00000004kCT-3060 for pgsql-hackers@arkaria.postgresql.org; Mon, 19 Oct 2026 00:53:26 +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.98.2) (envelope-from ) id 1xIbd0-00000004kCL-18iv for pgsql-hackers@lists.postgresql.org; Mon, 19 Oct 2026 00:53:26 +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 1xIbcw-00000002il5-1FRZ for pgsql-hackers@postgresql.org; Mon, 19 Oct 2026 00:53:25 +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=2KFpw9b8CZ/JIg8qxqPfDAYkeVSwd6bYqhJBH1ZwK/Q=; b=CaJ0HrSxCOXnYZcmRB52SQ5xeJ 1ISbdnWLbZhUHytPiPdx2XZPT5k9sgFcTkmEsTytbmXZOtd0zkgN7B/QjLbi+C20WtEyBjoEL/qf2 c/TfsKgPZE+CX6YCWuHxWKrC4Rm4fHWG8hxdRT7duZfQDas+/6Xj8a9e94+ZSZFSJZRRHtuvirPI3 tzGJDWIWuYVtfNO636SzUBToAV9OKP2Iv9RXkoGjib64YWK/11//3eE5ECgNax1ZzINNt0fW5v3i4 jZJ8dDWrhCNyZFlxr9+JO/sXX+uaBT3+BYgjvCYajWTFITd4tb5OM1SHFITtM08jgFh5A9M5CvT6A L5XOhmZA==; Received: from [2409:11:4120:300:7e57:6175:be08:19f5] (helo=localhost) by meldrar.postgresql.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1xIbcr-00000006Cbh-0rsg; Mon, 19 Oct 2026 00:53:19 +0000 Date: Mon, 19 Oct 2026 09:52:59 +0900 (JST) Message-Id: <20261019.095259.1988929700676866808.ishii@postgresql.org> To: assam258@gmail.com, jian.universality@gmail.com Cc: zsolt.parragi@percona.com, sjjang112233@gmail.com, vik@postgresfriends.org, er@xs4all.nl, jacob.champion@enterprisedb.com, david.g.johnston@gmail.com, peter@eisentraut.org, li.evan.chao@gmail.com, pgsql-hackers@postgresql.org Subject: Re: Row pattern recognition From: Tatsuo Ishii In-Reply-To: References: X-Mailer: Mew version 6.8 on Emacs 29.3 Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Host-Lookup-Failed: Reverse DNS lookup failed for 2409:11:4120:300:7e57:6175:be08:19f5 (failed) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi Henson and Jian, > This is an increment on top of v53. It is ten patches, named > nocfbot-XXXX-*.txt as before. Thank you for the patches! I looked through nocfbot-0001 to 0010. Since all the comments are minor, I think I can build v54 from the ten patches as it is. If you think differently, please let me know. > 0001 Let a row pattern DEFINE clause take part in grouping > [wrong result] > v53 left DEFINE out of the GROUP BY substitution, so a grouping > set that nulls a column made setrefs.c fail with "wrong > varnullingrels". DEFINE now goes through the same steps as the > target list. Also fixes PREV(k / 0) failing at plan time when > k is a USING column of mixed types. Looks good to me. Minor point. + /* + * A row pattern DEFINE clause carries GROUP Vars of its own; expand + * them, or the deparsed text would name the grouping step rather than + * the expression the user wrote, and the view would not re-parse. + */ + foreach(lc, query->windowClause) Can we use foreach_node instead or foreach? In the same patch foreach_node is used. > 0002 Tighten parse analysis of DEFINE clauses and row pattern > syntax [wrong result] > Whole-row references, ROW(t.*), names qualified by a function > name or block label, and the FILTER or ORDER BY of an aggregate > got around the qualifier rule of ISO/IEC 19075-5 6.5. They > are rejected now, and a few SQLSTATEs change. Looks good to me. > 0003 Fix DEFINE memory leak and empty-iteration looping in RPR > executor [wrong result] > An empty first iteration kept a derivation the standard > excludes, so some patterns matched different rows than Perl; > query results change for such patterns. Also fixes the DEFINE > memory leak (94MB down to 18MB on 300k rows) and adds an > interrupt check. I briefly looked through this. No objection from me. > 0004 Move DEFINE input tracking from parse analysis to the planner > [wrong result] > Parse analysis planted DEFINE's Vars in the target list, and > planning could fail with "variable not found in subplan target > list". DEFINE is now handled the way havingQual is. Also > stops subquery pull-up from folding a navigation argument, and > fixes a crash on a navigation offset. I still need to learn more about planner, but the direction looks right to me. > 0005 Make a deparsed DEFINE clause re-parse as written > [wrong result] > A view holding a DEFINE clause could not be dumped and restored > once another column carried the same name. The names DEFINE > reads are now settled first and reserved. Also changes > pg_get_viewdef() output for some queries without row pattern > recognition; the commit message lists them. +/* + * reserve_colname: keep any other RTE from being given this column name + */ +static void +reserve_colname(deparse_namespace *dpns, char *colname) +{ + ListCell *lc; + + foreach(lc, dpns->using_names) + { + if (strcmp((char *) lfirst(lc), colname) == 0) + return; + } + dpns->using_names = lappend(dpns->using_names, colname); +} colname should be duplicated using pstrdup() before passing to lappend? As some of callers of this function might pass a string literal. + if (rte->rtekind == RTE_RELATION) + reserve_colname(dpns, get_rte_attribute_name(rte, attno)); > > 0006 Tighten RPRPattern node I/O and reuse existing helpers in RPR > code [latent] > A malformed node string now fails with an internal error > instead of being misread. Existing helpers replace > hand-written code. Overall looks good. Minor point: @@ -728,23 +727,27 @@ _outRPRPattern(StringInfo str, const RPRPattern *node) WRITE_INT_FIELD(maxDepth); WRITE_INT_FIELD(numElements); - /* Write varNames array as list of strings */ + /* + * Write varNames array as list of strings. makeRPRPattern() guarantees + * the array, so the list has exactly one spelling and the read side has + * no second shape to interpret. + */ I think "makeRPRPattern() guarantees the array" should be "makeRPRPattern() guarantees the array exists." to make what it means cleaner. > 0007 Record two RPR costs and correct comments the code no longer > matches [comments, asserts] > Comments, plus five checks the executor cannot reach, now > Asserts: two elog(ERROR) calls and three early returns. > Records two known costs as XXX: the state comparison in > nfa_states_equal(), and nav_winobj's shared read pointer. I had no time to read the details. > 0008 Tidy and extend the row pattern recognition regression tests > [tests] > Tests only: rpr_ prefixes, fewer redundant ORDER BY, new tests, > and fixes for tests that tested less than their comments said. I had no time to read the details. > 0009 Bring the row pattern recognition documentation up to date > [docs] > Documentation only: SGML and README.rpr checked against the > code. Looks good except: --- a/src/backend/executor/README.rpr +++ b/src/backend/executor/README.rpr + Related code, by the phase each file serves. A file appears once, + under the phase where its row pattern work belongs: + + Parser scan.l seems missed in the list. In perform.sgml there are few lines using tag for ANALYZE command. The tag should be , rather than . Under ANALYZE, a node that was executed shows the bound resolved for its last scan instead of runtime: a row count, retain all or infinite. Under ANALYZE, further lines report counters for the > 0010 Reorder README.rpr by processing order [docs] > Moves the chapters into the order a query goes through the > code: parsing, DEFINE planning, PATTERN compilation, the > executor, the worked example, deparse and EXPLAIN, and the > summary last. Text moves; section numbers and cross references > follow, and the Chapter IV title is reworded. Looks good. > Open questions > > Tatsuo, four items need your decision on the direction or on whether > to go ahead: > > - State explosion. To keep the preference order from giving wrong > answers, the cycle guard marks only a nullable END, since marking > anything else loses legitimate matches. That bounds cycles but not > cost: alternations whose branches are all nullable enumerate paths > rather than states, as an XXX in nfa_advance_state() records. A > runtime bound, on the work in one expansion or on the states held, > is the first answer; rejecting quantified subpatterns that can > match empty, as Oracle does with ORA-62513, is the alternative. I need more time to answer to the question. > - Names. You accepted the RPR* policy for the typedefs on 07-14 [1] > and asked whether it reaches struct members too. I would say yes: > rpSkipTo becomes rprSkipTo along with the types, in one mechanical > patch after the defects are settled. Agreed on this direction. > - WindowAggState. On 05-31 [2] you agreed with Jian's idea [3] of > putting the row pattern members behind one struct, for the size > and for the move to R010, but not for v48. On 07-14 [1] you asked > when to do it, saying it has to be done to make the code > committable. I would group the members before the commit, since > that only changes structure, and leave the R010 redesign for > after. The struct needs a name other than RPRContext, since > rprContext is already the ExprContext DEFINE runs in. In the last this is necessary but it does not need to be hurry. > - sql_features.txt still says R020 is NO although the patch > implements it. It has to change before the commit. Whether it > says YES with a note or NO, partially supported is your call. When I implemented RPR alone, there were too many missing features. So I thought the status should be "NO". Now many features in R020 are implemneted in the current patch. However, we still miss a big features: range variable qualified pattern variables and MEASURES clause. So someone might say that the current patch is not eligible to be marked as "R020 is supported". However I personally think even without those two features, current patch is useful enough to enjoy the split of R020. This is really the community's decision. Until the decision is made, I would like to change it "YES with a note". > None of these is urgent, and none is a structural problem that puts > the quality of the patch at risk. Each is a matter of direction or > timing that can wait until the code has settled, and I will follow > whichever way you decide. Regards, -- Tatsuo Ishii SRA OSS K.K. English: http://www.sraoss.co.jp/index_en/ Japanese:http://www.sraoss.co.jp