Hi Tatsuo,

I found a small typo in a function comment: non-ASCII letter was
> used. In my understanding, using non-ASCII letters in the program
> files are not recommended. Patch attached.
>

Thank you for catching this! You are absolutely right. I apologize for
using non-ASCII characters in the code comments.

I've reviewed all the RPR-related files and found additional instances
of non-ASCII characters:
- Arrows "→" instead of "->"
- Superscript "²" instead of "^2"
- Greater-than-or-equal "≥" instead of ">="

Found in:
- src/backend/optimizer/plan/rpr.c (1 instance)
- src/backend/executor/nodeWindowAgg.c (5 instances)
- src/include/nodes/execnodes.h (4 instances)
- src/test/regress/sql/rpr.sql (7 instances)
- src/test/regress/sql/rpr_base.sql (15 instances)
- src/test/regress/expected/rpr.out (7 instances)
- src/test/regress/expected/rpr_base.out (15 instances)

Total: 54 instances across 7 files.

To ensure comprehensive coverage, I created a Python verification tool
that checks for non-ASCII characters and reports their Unicode code
points. I've verified all 46 files changed in the v42 patch series,
and confirmed no additional non-ASCII characters remain.

I'll be more careful going forward to use only ASCII characters in
source files and comments. Updated patch attached.

Best regards,
Henson
From 1cc2ebd59597c672b752d7b6912dedc2bde88d66 Mon Sep 17 00:00:00 2001
From: Henson Choi <[email protected]>
Date: Tue, 3 Feb 2026 17:30:06 +0900
Subject: [PATCH] Fix non-ASCII characters in RPR code and comments

---
 src/backend/executor/nodeWindowAgg.c   | 10 ++++-----
 src/backend/optimizer/plan/rpr.c       |  2 +-
 src/include/nodes/execnodes.h          |  8 ++++----
 src/test/regress/expected/rpr.out      | 14 ++++++-------
 src/test/regress/expected/rpr_base.out | 28 +++++++++++++-------------
 src/test/regress/sql/rpr.sql           | 14 ++++++-------
 src/test/regress/sql/rpr_base.sql      | 28 +++++++++++++-------------
 7 files changed, 52 insertions(+), 52 deletions(-)

diff --git a/src/backend/executor/nodeWindowAgg.c 
b/src/backend/executor/nodeWindowAgg.c
index bcdf8b6db81..1176df04b2c 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -4977,7 +4977,7 @@ register_result:
  * These functions implement direct NFA execution using the compiled
  * RPRPattern structure, avoiding regex compilation overhead.
  *
- * Execution Flow: match → absorb → advance
+ * Execution Flow: match -> absorb -> advance
  * -----------------------------------------
  * The NFA execution follows a three-phase cycle for each row:
  *
@@ -4997,7 +4997,7 @@ register_result:
  *
  * Key Design Decisions:
  * ---------------------
- * - VAR→END transition in match phase: When a simple VAR (max=1) matches
+ * - VAR->END transition in match phase: When a simple VAR (max=1) matches
  *   and the next element is END, we transition immediately in the match
  *   phase rather than waiting for advance. This is necessary for correct
  *   absorption: states must be at END to be marked absorbable before the
@@ -5008,7 +5008,7 @@ register_result:
  *   This ensures patterns like "A B? C" work correctly - we need a state
  *   waiting for B AND a state that has already skipped to C.
  *
- * - END→END count increment: When transitioning from one END to another
+ * - END->END count increment: When transitioning from one END to another
  *   END within advance, we must increment the outer END's count. This
  *   handles nested groups like "((A|B)+)+" correctly - exiting the inner
  *   group counts as one iteration of the outer group.
@@ -6092,7 +6092,7 @@ nfa_advance_end(WindowAggState *winstate, RPRNFAContext 
*ctx,
                state->elemIdx = elem->next;
                nextElem = &elements[state->elemIdx];
 
-               /* END→END: increment outer END's count */
+               /* END->END: increment outer END's count */
                if (RPRElemIsEnd(nextElem) && state->counts[nextElem->depth] < 
RPR_COUNT_MAX)
                        state->counts[nextElem->depth]++;
 
@@ -6123,7 +6123,7 @@ nfa_advance_end(WindowAggState *winstate, RPRNFAContext 
*ctx,
                exitState->counts[depth] = 0;
                nextElem = &elements[exitState->elemIdx];
 
-               /* END→END: increment outer END's count */
+               /* END->END: increment outer END's count */
                if (RPRElemIsEnd(nextElem) && 
exitState->counts[nextElem->depth] < RPR_COUNT_MAX)
                        exitState->counts[nextElem->depth]++;
 
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 230c545a631..50043c416c6 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -1379,7 +1379,7 @@ isUnboundedStart(RPRPattern *pattern, RPRElemIdx idx, 
RPRDepth parentDepth)
  *
  * Context absorption eliminates redundant match searches by absorbing
  * newer contexts that cannot produce longer matches than older contexts.
- * This achieves O(n²) → O(n) performance improvement.
+ * This achieves O(n^2) -> O(n) performance improvement.
  *
  * Only greedy unbounded quantifiers at pattern start can be absorbable.
  * Reluctant quantifiers are excluded because they don't maintain monotonic
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b6d6d942de9..e0704742d16 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2545,11 +2545,11 @@ typedef struct RPRNFAState
  * RPRNFAContext - context for NFA pattern matching execution
  *
  * Two-flag absorption design:
- *   hasAbsorbableState: can this context absorb others? (≥1 absorbable state)
- *     - Monotonic: true→false only, cannot recover once false
+ *   hasAbsorbableState: can this context absorb others? (>=1 absorbable state)
+ *     - Monotonic: true->false only, cannot recover once false
  *     - Used to skip absorption attempts once all absorbable states are gone
  *   allStatesAbsorbable: can this context be absorbed? (ALL states absorbable)
- *     - Dynamic: can change false→true (when non-absorbable states die)
+ *     - Dynamic: can change false->true (when non-absorbable states die)
  *     - Used to determine if this context is eligible for absorption
  */
 typedef struct RPRNFAContext
@@ -2564,7 +2564,7 @@ typedef struct RPRNFAContext
        RPRNFAState *matchedState;      /* FIN state for greedy fallback 
(cloned) */
 
        /* Two-flag absorption optimization */
-       bool            hasAbsorbableState; /* can absorb others (≥1 absorbable
+       bool            hasAbsorbableState; /* can absorb others (>=1 absorbable
                                                                         * 
state) */
        bool            allStatesAbsorbable;    /* can be absorbed (ALL states
                                                                                
 * absorbable) */
diff --git a/src/test/regress/expected/rpr.out 
b/src/test/regress/expected/rpr.out
index c4794c5cd88..d4298860865 100644
--- a/src/test/regress/expected/rpr.out
+++ b/src/test/regress/expected/rpr.out
@@ -3099,11 +3099,11 @@ WINDOW w AS (
   5 | {E,_} |             |          
 (5 rows)
 
--- Row 1: A=T, B=T → matches A
--- Row 2: B=T, C=T → matches B
--- Row 3: C=T, D=T → matches C
--- Row 4: D=T, E=T → matches D
--- Row 5: E=T      → matches E
+-- Row 1: A=T, B=T -> matches A
+-- Row 2: B=T, C=T -> matches B
+-- Row 3: C=T, D=T -> matches C
+-- Row 4: D=T, E=T -> matches D
+-- Row 5: E=T      -> matches E
 -- Result: match 1-5 (A B C D E)
 -- Test 6: Diagonal pattern with multi-TRUE (shifted overlap)
 WITH test_diagonal AS (
@@ -3138,8 +3138,8 @@ WINDOW w AS (
 (5 rows)
 
 -- Possible matches:
---   Start Row 1: A(1) B(2) C(3) D(4) → 1-4
---   Start Row 2: A(2) B(3) C(4) D(5) → 2-5 (because Row 2 has A too!)
+--   Start Row 1: A(1) B(2) C(3) D(4) -> 1-4
+--   Start Row 2: A(2) B(3) C(4) D(5) -> 2-5 (because Row 2 has A too!)
 -- ===================================================================
 -- Context Absorption Tests
 -- ===================================================================
diff --git a/src/test/regress/expected/rpr_base.out 
b/src/test/regress/expected/rpr_base.out
index b34b9e59d25..23851c5a11c 100644
--- a/src/test/regress/expected/rpr_base.out
+++ b/src/test/regress/expected/rpr_base.out
@@ -336,9 +336,9 @@ INSERT INTO rpr_frame VALUES
 -- Valid frame options
 -- ROWS: counts physical rows (1 FOLLOWING = next 1 physical row)
 -- Expected result: Each row can see 1 physical row ahead
--- id=1,2,3 (val=10): can see next row → cnt=2
--- id=4,5 (val=20): can see next row → cnt=2
--- id=6 (val=30): no next row → cnt=1
+-- id=1,2,3 (val=10): can see next row -> cnt=2
+-- id=4,5 (val=20): can see next row -> cnt=2
+-- id=6 (val=30): no next row -> cnt=1
 -- Result: [2,2,2,2,2,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -598,11 +598,11 @@ ORDER BY id;
 
 -- RANGE: includes all rows with same ORDER BY value
 -- Expected result: Includes peer rows (same val) in range calculation
--- id=1 (val=10): range [10,20] includes all val=10 and val=20 peers → cnt=2 
(only first in peer group gets match)
--- id=2,3 (val=10): already matched by id=1 → cnt=0
--- id=4 (val=20): range [20,30] includes all val=20 and val=30 peers → cnt=2
--- id=5 (val=20): already matched by id=4 → cnt=0
--- id=6 (val=30): range [30,40] includes only val=30 → cnt=1
+-- id=1 (val=10): range [10,20] includes all val=10 and val=20 peers -> cnt=2 
(only first in peer group gets match)
+-- id=2,3 (val=10): already matched by id=1 -> cnt=0
+-- id=4 (val=20): range [20,30] includes all val=20 and val=30 peers -> cnt=2
+-- id=5 (val=20): already matched by id=4 -> cnt=0
+-- id=6 (val=30): range [30,40] includes only val=30 -> cnt=1
 -- Result: [2,0,0,2,0,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -626,11 +626,11 @@ ORDER BY id;
 
 -- GROUPS: treats rows with same value as one group (1 FOLLOWING = next group)
 -- Expected result: 1 FOLLOWING means current group + 1 next group
--- id=1 (val=10): groups [val=10, val=20] → cnt=2 (only first in group gets 
match)
--- id=2,3 (val=10): already matched by id=1 → cnt=0
--- id=4 (val=20): groups [val=20, val=30] → cnt=2
--- id=5 (val=20): already matched by id=4 → cnt=0
--- id=6 (val=30): groups [val=30] (no next group) → cnt=1
+-- id=1 (val=10): groups [val=10, val=20] -> cnt=2 (only first in group gets 
match)
+-- id=2,3 (val=10): already matched by id=1 -> cnt=0
+-- id=4 (val=20): groups [val=20, val=30] -> cnt=2
+-- id=5 (val=20): already matched by id=4 -> cnt=0
+-- id=6 (val=30): groups [val=30] (no next group) -> cnt=1
 -- Result: [2,0,0,2,0,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -3549,7 +3549,7 @@ WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND 10 
FOLLOWING
 -- ============================================================
 -- Absorption Analysis Tests
 -- ============================================================
--- Tests context absorption optimization (O(n²) → O(n))
+-- Tests context absorption optimization (O(n^2) -> O(n))
 -- Files: rpr.c (computeAbsorbability)
 -- Simple Absorbable Pattern: A+ B
 -- Pattern starts with unbounded VAR
diff --git a/src/test/regress/sql/rpr.sql b/src/test/regress/sql/rpr.sql
index 8ab1daf87d6..788a77e5279 100644
--- a/src/test/regress/sql/rpr.sql
+++ b/src/test/regress/sql/rpr.sql
@@ -1527,11 +1527,11 @@ WINDOW w AS (
         D AS 'D' = ANY(flags),
         E AS 'E' = ANY(flags)
 );
--- Row 1: A=T, B=T → matches A
--- Row 2: B=T, C=T → matches B
--- Row 3: C=T, D=T → matches C
--- Row 4: D=T, E=T → matches D
--- Row 5: E=T      → matches E
+-- Row 1: A=T, B=T -> matches A
+-- Row 2: B=T, C=T -> matches B
+-- Row 3: C=T, D=T -> matches C
+-- Row 4: D=T, E=T -> matches D
+-- Row 5: E=T      -> matches E
 -- Result: match 1-5 (A B C D E)
 
 -- Test 6: Diagonal pattern with multi-TRUE (shifted overlap)
@@ -1558,8 +1558,8 @@ WINDOW w AS (
         D AS 'D' = ANY(flags)
 );
 -- Possible matches:
---   Start Row 1: A(1) B(2) C(3) D(4) → 1-4
---   Start Row 2: A(2) B(3) C(4) D(5) → 2-5 (because Row 2 has A too!)
+--   Start Row 1: A(1) B(2) C(3) D(4) -> 1-4
+--   Start Row 2: A(2) B(3) C(4) D(5) -> 2-5 (because Row 2 has A too!)
 
 -- ===================================================================
 -- Context Absorption Tests
diff --git a/src/test/regress/sql/rpr_base.sql 
b/src/test/regress/sql/rpr_base.sql
index 88f0a2c2083..a5a66d2ca81 100644
--- a/src/test/regress/sql/rpr_base.sql
+++ b/src/test/regress/sql/rpr_base.sql
@@ -280,9 +280,9 @@ INSERT INTO rpr_frame VALUES
 
 -- ROWS: counts physical rows (1 FOLLOWING = next 1 physical row)
 -- Expected result: Each row can see 1 physical row ahead
--- id=1,2,3 (val=10): can see next row → cnt=2
--- id=4,5 (val=20): can see next row → cnt=2
--- id=6 (val=30): no next row → cnt=1
+-- id=1,2,3 (val=10): can see next row -> cnt=2
+-- id=4,5 (val=20): can see next row -> cnt=2
+-- id=6 (val=30): no next row -> cnt=1
 -- Result: [2,2,2,2,2,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -464,11 +464,11 @@ ORDER BY id;
 
 -- RANGE: includes all rows with same ORDER BY value
 -- Expected result: Includes peer rows (same val) in range calculation
--- id=1 (val=10): range [10,20] includes all val=10 and val=20 peers → cnt=2 
(only first in peer group gets match)
--- id=2,3 (val=10): already matched by id=1 → cnt=0
--- id=4 (val=20): range [20,30] includes all val=20 and val=30 peers → cnt=2
--- id=5 (val=20): already matched by id=4 → cnt=0
--- id=6 (val=30): range [30,40] includes only val=30 → cnt=1
+-- id=1 (val=10): range [10,20] includes all val=10 and val=20 peers -> cnt=2 
(only first in peer group gets match)
+-- id=2,3 (val=10): already matched by id=1 -> cnt=0
+-- id=4 (val=20): range [20,30] includes all val=20 and val=30 peers -> cnt=2
+-- id=5 (val=20): already matched by id=4 -> cnt=0
+-- id=6 (val=30): range [30,40] includes only val=30 -> cnt=1
 -- Result: [2,0,0,2,0,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -483,11 +483,11 @@ ORDER BY id;
 
 -- GROUPS: treats rows with same value as one group (1 FOLLOWING = next group)
 -- Expected result: 1 FOLLOWING means current group + 1 next group
--- id=1 (val=10): groups [val=10, val=20] → cnt=2 (only first in group gets 
match)
--- id=2,3 (val=10): already matched by id=1 → cnt=0
--- id=4 (val=20): groups [val=20, val=30] → cnt=2
--- id=5 (val=20): already matched by id=4 → cnt=0
--- id=6 (val=30): groups [val=30] (no next group) → cnt=1
+-- id=1 (val=10): groups [val=10, val=20] -> cnt=2 (only first in group gets 
match)
+-- id=2,3 (val=10): already matched by id=1 -> cnt=0
+-- id=4 (val=20): groups [val=20, val=30] -> cnt=2
+-- id=5 (val=20): already matched by id=4 -> cnt=0
+-- id=6 (val=30): groups [val=30] (no next group) -> cnt=1
 -- Result: [2,0,0,2,0,1]
 SELECT id, val, COUNT(*) OVER w as cnt
 FROM rpr_frame
@@ -2331,7 +2331,7 @@ WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND 10 
FOLLOWING
 -- ============================================================
 -- Absorption Analysis Tests
 -- ============================================================
--- Tests context absorption optimization (O(n²) → O(n))
+-- Tests context absorption optimization (O(n^2) -> O(n))
 -- Files: rpr.c (computeAbsorbability)
 
 -- Simple Absorbable Pattern: A+ B
-- 
2.50.1 (Apple Git-155)

Reply via email to