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.94.2) (envelope-from ) id 1suUx4-007DWo-M7 for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Sep 2024 10:45:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1suUw4-006R6J-5q for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Sep 2024 10:44:24 +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.94.2) (envelope-from ) id 1suUw3-006R6B-JN for pgsql-hackers@lists.postgresql.org; Sat, 28 Sep 2024 10:44:23 +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.94.2) (envelope-from ) id 1suUw0-001SzV-My for pgsql-hackers@postgresql.org; Sat, 28 Sep 2024 10:44:22 +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=h6Ou9yUmAwfoud7wIxRRqhzAAqv+5INIeczLinSN2Lc=; b=0sgT1Z4emCY8gw3aJVtxPmvnUu pLoQ/RnrCrN8fy0H6fDCA5GyFTQ8+DHhcUjVd5e7dHun8rD1CRppEm0n+zdlE+j/WGjh5QoGENvLH vphgTj+F9PZY2mcqPOdhlZnjhC+//AvzSczVC+wAY+myIz3wDHrB8P9iOhcvSDSkHndrNR8keb+iP 3/MvrThfCJUhF9OpJ+ACLTTQS/cMrt033sHCb5UDAAetOKQO4+El61IdTH4y9kQsx6tcq9e2sT8g7 UDW7Epd1DFproVoWCylOeWjOr5MEQKFo2LoHed+khuZYMaWYrbTI5MzOjyG5TNQy/APm932Mryi/z NSQ6V1qA==; Received: from [2409:11:4120:300:f127:2396:499e:13f2] (helo=localhost) by meldrar.postgresql.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (Exim 4.94.2) (envelope-from ) id 1suUvt-0049xC-CG; Sat, 28 Sep 2024 10:44:17 +0000 Date: Sat, 28 Sep 2024 19:43:59 +0900 (JST) Message-Id: <20240928.194359.1327378331465099656.ishii@postgresql.org> To: jacob.champion@enterprisedb.com Cc: vik@postgresfriends.org, pgsql-hackers@postgresql.org, er@xs4all.nl, peter@eisentraut.org Subject: Re: Row pattern recognition From: Tatsuo Ishii In-Reply-To: References: <20240826.133947.1024518999214322700.ishii@postgresql.org> <20240919.135947.296030969313721973.ishii@postgresql.org> X-Mailer: Mew version 6.8 on Emacs 26.3 Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="--Next_Part(Sat_Sep_28_19_43_59_2024_223)--" Content-Transfer-Encoding: 7bit X-Host-Lookup-Failed: Reverse DNS lookup failed for 2409:11:4120:300:f127:2396:499e:13f2 (failed) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ----Next_Part(Sat_Sep_28_19_43_59_2024_223)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit > With some bigger partitions, I hit an `ERROR: wrong pos: 1024`. A > test that reproduces it is attached. Thanks for the report. Attached is a patch on top of v22 patches to fix the bug. We keep info in an array (WindowAggState.reduced_frame_map) to track the rpr pattern match result status for each row in a frame. If pattern match succeeds, the first row in the reduced frame has status RF_FRAME_HEAD and rest of rows have RF_SKIPPED state. A row with pattern match failure state has RF_UNMATCHED state. Any row which is never tested has state RF_NOT_DETERMINED. At begining the map is initialized with 1024 entries with all RF_NOT_DETERMINED state. Eventually they are replaced with other than RF_NOT_DETERMINED state. In the error case rpr engine tries to find 1024 th row's state in the map and failed because the row's state has not been tested yet. I think we should treat it as RF_NOT_DETERMINED rather than an error. Attached patch does it. > While playing with the feature, I've been trying to identify runs of > matched rows by eye. But it's pretty difficult -- the best I can do is > manually count rows using a `COUNT(*) OVER ...`. So I'd like to > suggest that MEASURES be part of the eventual v1 feature, if there's > no other way to determine whether a row was skipped by a previous > match. (That was less obvious to me before the fix in v17.) I think implementing MEASURES is challenging. Especially we need to find how our parser accepts "colname OVER window_definition". Currently PostgreSQL's parser only accepts "func() OVER window_definition" Even it is technically possible, I think the v1 patch size will become much larger than now due to this. How about inventing new window function that returns row state instead? - match found (yes/no) - skipped due to AFTER MATCH SKIP PAST LAST ROW (no match) For the rest of the mail I need more time to understand. I will reply back after studying it. For now, I just want to thank you for the valuable information! > -- > > I've been working on an implementation [1] of SQL/RPR's "parenthesized > language" and preferment order. (These are defined in SQL/Foundation > 2023, section 9.41.) The tool gives you a way to figure out, for a > given pattern, what matches are supposed to be attempted and in what > order: > > $ ./src/test/modules/rpr/rpr_prefer "a b? a" > ( ( a ( b ) ) a ) > ( ( a ( ) ) a ) > > Many simple patterns result in an infinite set of possible matches. So > if you use an unbounded quantifiers, you have to also use --max-rows > to limit the size of the hypothetical window frame: > > $ ./src/test/modules/rpr/rpr_prefer --max-rows 2 "^ PERMUTE(a*, b+)? $" > ( ( ^ ( ( ( ( ( ( a ) ( b ) ) ) - ) ) ) ) $ ) > ( ( ^ ( ( ( ( ( ( ) ( b b ) ) ) - ) ) ) ) $ ) > ( ( ^ ( ( ( ( ( ( ) ( b ) ) ) - ) ) ) ) $ ) > ( ( ^ ( ( ( - ( ( ( b b ) ( ) ) ) ) ) ) ) $ ) > ( ( ^ ( ( ( - ( ( ( b ) ( a ) ) ) ) ) ) ) $ ) > ( ( ^ ( ( ( - ( ( ( b ) ( ) ) ) ) ) ) ) $ ) > ( ( ^ ( ) ) $ ) > > I've found this useful to check my personal understanding of the spec > and the match behavior, but it could also potentially be used to > generate test cases, or to help users debug their own patterns. For > example, a pattern that has a bunch of duplicate sequences in its PL > is probably not very well optimized: > > $ ./src/test/modules/rpr/rpr_prefer --max-rows 4 "a+ a+" > ( ( a a a ) ( a ) ) > ( ( a a ) ( a a ) ) > ( ( a a ) ( a ) ) > ( ( a ) ( a a a ) ) > ( ( a ) ( a a ) ) > ( ( a ) ( a ) ) > > And patterns with catastrophic backtracking behavior tend to show a > "sawtooth" pattern in the output, with a huge number of potential > matches being generated relative to the number of rows in the frame. > > My implementation is really messy -- it leaks memory like a sieve, and > I cannibalized the parser from ECPG, which just ended up as an > exercise in teaching myself flex/bison. But if there's interest in > having this kind of tool in the tree, I can work on making it > reviewable. Either way, I should be able to use it to double-check > more complicated test cases. > > A while back [2], you were wondering whether our Bison implementation > would be able to parse the PATTERN grammar directly. I think this tool > proves that the answer is "yes", but PERMUTE in particular causes a > shift/reduce conflict. To fix it, I applied the same precedence > workaround that we use for CUBE and ROLLUP. > > Thanks again! > --Jacob > > [1] https://github.com/jchampio/postgres/tree/dev/rpr > [2] https://www.postgresql.org/message-id/20230721.151648.412762379013769790.t-ishii%40sranhm.sra.co.jp ----Next_Part(Sat_Sep_28_19_43_59_2024_223)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="rpr_fix.txt" diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index e46a3dd1b7..4a5a6fbf07 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -4148,9 +4148,15 @@ int get_reduced_frame_map(WindowAggState *winstate, int64 pos) { Assert(winstate->reduced_frame_map != NULL); + Assert(pos >= 0); - if (pos < 0 || pos >= winstate->alloc_sz) - elog(ERROR, "wrong pos: " INT64_FORMAT, pos); + /* + * If pos is not in the reduced frame map, it means that any info + * regarding the pos has not been registered yet. So we return + * RF_NOT_DETERMINED. + */ + if (pos >= winstate->alloc_sz) + return RF_NOT_DETERMINED; return winstate->reduced_frame_map[pos]; } ----Next_Part(Sat_Sep_28_19_43_59_2024_223)----