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 1vnYfo-008nJx-39 for pgsql-hackers@arkaria.postgresql.org; Wed, 04 Feb 2026 08:55:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vnYen-00A2hQ-36 for pgsql-hackers@arkaria.postgresql.org; Wed, 04 Feb 2026 08:54:41 +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 1vnYen-00A2hI-1N for pgsql-hackers@lists.postgresql.org; Wed, 04 Feb 2026 08:54:41 +0000 Received: from mail-pj1-x1036.google.com ([2607:f8b0:4864:20::1036]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1vnYel-00000000Unw-0AhI for pgsql-hackers@postgresql.org; Wed, 04 Feb 2026 08:54:40 +0000 Received: by mail-pj1-x1036.google.com with SMTP id 98e67ed59e1d1-34c3259da34so340650a91.2 for ; Wed, 04 Feb 2026 00:54:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1770195277; cv=none; d=google.com; s=arc-20240605; b=iNSlcR478LeNBAWlRzmR9mdo8JVDAos4aOAYsvMFohGf+Qlq40vqjSHBcH/Zkry0fb ZM12/QThLL2VTzSqOE+p6FfwoLs8xVAMLIXmSSJFK/FY2SIXs1UBIrOFpUttOyOjh17U 3egJqoEDJf45/J89r5R6l+Q9KLgWUAqiFevWig/cJp1m/N3gYheTKpRwCEqP6cDS43xk FXLC7ePqEB6DZBuQenBDa7Jl45JFT6Vw5O74rA9MORypo1GxdlCNou8o4TBdWT/MhwtU ad66xsSbe9hsrPNfClWPZgDN73liuhjseQ7YKiH+zY3goHMMUmhxgJKlsbNt0LkGrmkI 90tQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:dkim-signature; bh=+z9de6zReVWx2bSoJ+2LoP6nGJIebtIxnirKatW+IIo=; fh=NenyNWlV9t+iRiuwyYBTwJRk6c/VASxaZ5c8zH3Ga7I=; b=Fpj8h6biYo8BYFKCJV12w9Y1i6bgPC2g0AG2Ubsk2TrJNXmIteOABryosAEDweQi+0 vwGb1ydE3QYwGwv5IRPv+8SBIk1Pet856b6N308y4WhK6OewrireAmwValwjIPFACLl1 Vv1m2vZZpoDRCYg6RA0usXqf57ai1iPn77TvyJdEqPjeRfU5n8Z3sXo2YAbxvKkNMszN r+EAJBcacHdRKox/o23XijoZUZIc9pR+pXE0k/7UF/hqmxIrQmpSeeGZvtfCvD63TlO8 30jgQUYw2boFRteXEONsQhDVuypvKJpsMHVTWwP5L2PacWV2Zx5pDIh7B+1hH5OXFUIZ Kj/A==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770195277; x=1770800077; darn=postgresql.org; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=+z9de6zReVWx2bSoJ+2LoP6nGJIebtIxnirKatW+IIo=; b=W51v2Fx+21oBRd+yeyyQeFWeKclf+TeWexZszvBTrRh3wsldpZ+o5dItTM9axlhrQe Ld2lKa8qjNMHNxYbaiXP30hPvClifw+rszYVnFsZdFHJ4xsxgiqQVStxrqCxa61b8Whn 2LBWO4I20DAr+JbVKrDsf3aZd9Kb5xOO8HOkA1Te7GJncUQfAGM1qjdqYcouHelGwxzZ WyHou2qrCjncif7jjVDcK8KIMs/pMr/pSGL7znOrHMOSvzsC/NVRmpOZ5HepAnsX5xeh jdJujMuCAo3nVl3C6OESNYVXguUKs+1OC18VAhbFA68GDxPiMLTFMsF+TGsbsMRSkSZw GCTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770195277; x=1770800077; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=+z9de6zReVWx2bSoJ+2LoP6nGJIebtIxnirKatW+IIo=; b=TyjuNNy8PMqCSJApLMm+d7//t+RhuZeu41fwrLTckDSM83BVjzMK3Qx1/U2uTvEhc4 CZ/nKl2635Xlz5zzBHyQOH9MJI6W7cqmgbapJsNDS7lW/W+zsKYw0eGB3lFpWqQW3n66 40/hxj9Mm3Iw96fuJZ1MaMKvirYQCDg2O6Z/n9mR4JfXkL99ciuDIR92zv8fxyUkU/s8 LIDZZJQOuaOpmXewcBhWaRWeOwwdL0xd32JXS59prr5y++n3pHCPKcwkqbEnTzOUPBDs lH7vFgysD5gzLGhj57WAiHsnpns4gWKL9J242erx7N8ciff61zEujRQnkZYb3MlRtqLw uQXQ== X-Forwarded-Encrypted: i=1; AJvYcCV5Dzyg0OwlIG9mv72I2Q11nGXfoMG1LGA4mJ0ljR1na4gWFZblLE+kQjbhEC9G/nOqgcY4y5lOiWhvb8lH@postgresql.org X-Gm-Message-State: AOJu0YyKEetLscrQPrQiEtzjosuURgCr8YruC13+VaQissJTaoF0zhy2 mogmSkfdgKeELtGkggHeCLHYeVp1LJgN+7+61CXxYj5h2cqRN8VP1c1h/bWkGpcUaCLj7HjQIxW 5WeQ9VNja8gHKhm7hs5X5W+L5ng6kVjc= X-Gm-Gg: AZuq6aLaPU6jXAZ0cJ8Yk3q38E5obwlhNyF5yYIHT/5QtE+bLOAh95RhZJl0Cr8jZag UDwzFm+TWNoZajnu7crBIDFYUJDElOILvVKoxASW7kk+6xfWCorxyNvoQ7aWdrSd6omvjE0Je4N y6CxtjjqRfm2MFOR3EUNo0pyKHrbPeMPetV5VltQOOhFfvHMmb+gRqKEttxlyalr1rrFy53jLSE Rbm+SBgkL+rrUpMI0CpGTFh/cswMQlA8YWFk3FZ5uW4gsH8nzdBB2qBxxa22NJfLYrfXs5G509V KwK675rS6PN5WRtIxZmCoFrP84rx X-Received: by 2002:a17:90b:2e0d:b0:32d:d5f1:fe7f with SMTP id 98e67ed59e1d1-3548711595dmr2176114a91.15.1770195277448; Wed, 04 Feb 2026 00:54:37 -0800 (PST) MIME-Version: 1.0 References: <20260202.162000.2139438609347688347.ishii@postgresql.org> <20260203.090039.1140229154610300206.ishii@postgresql.org> <20260204.090451.1095005750732720998.ishii@postgresql.org> In-Reply-To: <20260204.090451.1095005750732720998.ishii@postgresql.org> Reply-To: assam258@gmail.com From: Henson Choi Date: Wed, 4 Feb 2026 17:54:26 +0900 X-Gm-Features: AZwV_Qg6GqL8JK6-k6ovBbReHu7fRVd0ojtym5xc8qkgvzv6XUTamvOt7U7KkMg Message-ID: Subject: Re: Row pattern recognition To: Tatsuo Ishii Cc: jacob.champion@enterprisedb.com, david.g.johnston@gmail.com, vik@postgresfriends.org, er@xs4all.nl, peter@eisentraut.org, pgsql-hackers@postgresql.org Content-Type: multipart/alternative; boundary="000000000000b20b300649fbb46f" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000b20b300649fbb46f Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Tatsuo, BTW, I have a question regarding NFA related objects initialization in > nodeWindowAgg.c. > > In release_partition(): > /* Reset NFA state for new partition */ > winstate->nfaContext =3D NULL; > winstate->nfaContextTail =3D NULL; > winstate->nfaContextFree =3D NULL; > winstate->nfaStateFree =3D NULL; > winstate->nfaLastProcessedRow =3D -1; > winstate->nfaStatesActive =3D 0; > winstate->nfaContextsActive =3D 0; > > While in ExecInitWindowAgg(): > /* Initialize NFA free lists for row pattern matching */ > winstate->nfaContext =3D NULL; > winstate->nfaContextTail =3D NULL; > winstate->nfaContextFree =3D NULL; > winstate->nfaStateFree =3D NULL; > winstate->nfaLastProcessedRow =3D -1; > > So the latter does not initialize winstate->nfaStatesActive and > winstate->nfaContextsActive. Can you please explain why? > You're absolutely right to notice this inconsistency. Let me explain: ## Why ExecInitWindowAgg() omits these two fields In ExecInitWindowAgg(), the WindowAggState structure is created via makeNode(WindowAggState), which internally uses palloc0(). This zero-initializes all memory, so: - All pointers =E2=86=92 NULL (0) - nfaStatesActive =E2=86=92 0 - nfaContextsActive =E2=86=92 0 - All other statistics counters =E2=86=92 0 Technically, only nfaLastProcessedRow =3D -1 truly needs explicit initialization since it requires a non-zero value. The nfaContext =3D NULL assignments are redundant but follow PostgreSQL's convention of explicitly setting pointers to NULL for code clarity and documentation. The pattern in ExecInitWindowAgg() follows PostgreSQL's common practice: - Pointers: explicitly initialized to NULL (for readability) - Counters: implicitly zero-initialized via palloc0() (intentionally omitted) This same pattern appears throughout the function for other fields too. For example, framehead_slot and frametail_slot are explicitly set to NULL, while framehead_valid and frametail_valid are left zero-initialized. ## What nfaStatesActive and nfaContextsActive do These two fields serve as internal counters for tracking active NFA resources: nfaStatesActive: Tracks the current number of active NFA states in memory. - Incremented in nfa_state_alloc() when allocating a new state - Decremented in nfa_state_free() when returning a state to the free list - Used to calculate nfaStatesMax (peak usage) for EXPLAIN ANALYZE nfaContextsActive: Tracks the current number of active NFA contexts. - Incremented in nfa_context_alloc() when creating a new context - Decremented in nfa_context_free() when recycling a context - Used to calculate nfaContextsMax (peak usage) for EXPLAIN ANALYZE Both counters start at 0 and are updated during NFA execution to track resource usage for performance monitoring. ## Why release_partition() must explicitly reset them release_partition() is called when moving to a new partition and must reset per-partition state. Unlike ExecInitWindowAgg() which creates a fresh structure, release_partition() reuses an existing structure that contains values from the previous partition. The root cause of the reset requirement is that release_partition() calls MemoryContextReset(winstate->partcontext), which frees all partition-local memory. This includes: - All NFA context structures pointed to by nfaContext - All NFA state nodes in the free lists (nfaContextFree, nfaStateFree) - All other partition-specific data As a consequence of this memory reset: 1. The NFA pointers (nfaContext, nfaContextFree, etc.) must be set to NULL to avoid dangling pointers 2. The active resource counters (nfaStatesActive, nfaContextsActive) must be reset to 0 since all the resources they were counting have been freed Example scenario: Partition 1 processing: - nfaStatesActive increments one-by-one as states are allocated, decrements as they are freed, fluctuates during execution, ends at some non-zero value (e.g., 3) - nfaContextsActive similarly fluctuates, ends at some value (e.g., 2) Partition 2 starts =E2=86=92 release_partition() called: - MemoryContextReset(partcontext) frees all NFA structures - nfaContext, nfaContextFree, etc. =E2=86=92 must set to NULL - nfaStatesActive: 3 =E2=86=92 must reset to 0 - nfaContextsActive: 2 =E2=86=92 must reset to 0 These counters track instantaneous active resources within a partition, so they must be reset to 0 when starting a new partition. In contrast, cumulative statistics like nfaStatesMax and nfaStatesTotalCreated are NOT reset because they track overall query-wide statistics across all partitions. ## Why only these two counters? You might wonder why I don't propose initializing all the other NFA statistics fields as well. ExecInitWindowAgg() currently omits explicit initialization for many statistics fields: Per-partition internal counters (reset at partition boundaries): - nfaStatesActive =3D 0; (omitted) - nfaContextsActive =3D 0; (omitted) Query-wide cumulative statistics (never reset): - nfaStatesMax =3D 0; (omitted) - nfaStatesTotalCreated =3D 0; (omitted) - nfaStatesMerged =3D 0; (omitted) - nfaContextsMax =3D 0; (omitted) - nfaContextsTotalCreated =3D 0; (omitted) - nfaContextsAbsorbed =3D 0; (omitted) - nfaContextsSkipped =3D 0; (omitted) - nfaContextsPruned =3D 0; (omitted) - nfaMatchesSucceeded =3D 0; (omitted) - nfaMatchesFailed =3D 0; (omitted) - nfaMatchLen =3D {0, 0, 0}; (omitted) - nfaFailLen =3D {0, 0, 0}; (omitted) - nfaAbsorbedLen =3D {0, 0, 0}; (omitted) - nfaSkippedLen =3D {0, 0, 0}; (omitted) The key distinction is that nfaStatesActive and nfaContextsActive are the ONLY statistics that get reset in release_partition(). All the other statistics are cumulative across the entire query and should never be reset between partitions. For example, nfaStatesMax tracks the peak number of active states across ALL partitions, not just within one partition. Similarly, nfaStatesTotalCreated accumulates the total count across all partitions. These cumulative statistics start at 0 (via palloc0) and only increase, never getting reset. Therefore, I believe it only makes sense to add explicit initialization for nfaStatesActive and nfaContextsActive, since these are the only two that release_partition() also explicitly resets. Adding explicit initialization for all the cumulative statistics would be misleading, as it might suggest they get reset somewhere (which they don't). ## Proposal for consistency For consistency with release_partition(), I can add just the two per-partition counter initializations to ExecInitWindowAgg(): /* Initialize NFA free lists for row pattern matching */ winstate->nfaContext =3D NULL; winstate->nfaContextTail =3D NULL; winstate->nfaContextFree =3D NULL; winstate->nfaStateFree =3D NULL; winstate->nfaLastProcessedRow =3D -1; winstate->nfaStatesActive =3D 0; // Add this winstate->nfaContextsActive =3D 0; // Add this This would make both ExecInitWindowAgg() and release_partition() initialize the same set of per-partition NFA fields, making the code more uniform and easier to review. The cumulative statistics fields remain omitted in both functions, which correctly reflects that they are never reset. Functionally, this change makes no difference since palloc0() already zeros these fields, but it improves code consistency and makes the per-partition vs. query-wide distinction clearer. Would you like me to include this change in the next patch? Best regards, Henson --000000000000b20b300649fbb46f Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Tatsuo,

<= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rg= b(204,204,204)"> BTW, I have a question regarding NFA related objects initialization in
nodeWindowAgg.c.

In release_partition():
=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Reset NFA state for new partition */
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContext =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContextTail =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContextFree =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaStateFree =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaLastProcessedRow =3D -1;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaStatesActive =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContextsActive =3D 0;

While in ExecInitWindowAgg():
=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Initialize NFA free lists for row pattern ma= tching */
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContext =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContextTail =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaContextFree =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaStateFree =3D NULL;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 winstate->nfaLastProcessedRow =3D -1;

So the latter does not initialize winstate->nfaStatesActive and
winstate->nfaContextsActive. Can you please explain why?

You're absolutely right to notice this incon= sistency. Let me explain:

## Why ExecInitWindowAgg() omits these two= fields

In ExecInitWindowAgg(), the WindowAggState structure is crea= ted via
makeNode(WindowAggState), which internally uses palloc0(). This<= br>zero-initializes all memory, so:

=C2=A0 - All pointers =E2=86=92 = NULL (0)
=C2=A0 - nfaStatesActive =E2=86=92 0
=C2=A0 - nfaContextsAct= ive =E2=86=92 0
=C2=A0 - All other statistics counters =E2=86=92 0
Technically, only nfaLastProcessedRow =3D -1 truly needs explicit
init= ialization since it requires a non-zero value. The nfaContext =3D NULL
a= ssignments are redundant but follow PostgreSQL's convention of
expli= citly setting pointers to NULL for code clarity and documentation.

T= he pattern in ExecInitWindowAgg() follows PostgreSQL's common practice:=
=C2=A0 - Pointers: explicitly initialized to NULL (for readability)
= =C2=A0 - Counters: implicitly zero-initialized via palloc0() (intentionally= omitted)

This same pattern appears throughout the function for othe= r fields too.
For example, framehead_slot and frametail_slot are explici= tly set to NULL,
while framehead_valid and frametail_valid are left zero= -initialized.

## What nfaStatesActive and nfaContextsActive do
These two fields serve as internal counters for tracking active NFA
re= sources:

nfaStatesActive: Tracks the current number of active NFA st= ates in memory.
=C2=A0 - Incremented in nfa_state_alloc() when allocatin= g a new state
=C2=A0 - Decremented in nfa_state_free() when returning a = state to the free list
=C2=A0 - Used to calculate nfaStatesMax (peak usa= ge) for EXPLAIN ANALYZE

nfaContextsActive: Tracks the current number= of active NFA contexts.
=C2=A0 - Incremented in nfa_context_alloc() whe= n creating a new context
=C2=A0 - Decremented in nfa_context_free() when= recycling a context
=C2=A0 - Used to calculate nfaContextsMax (peak usa= ge) for EXPLAIN ANALYZE

Both counters start at 0 and are updated dur= ing NFA execution to track
resource usage for performance monitoring.
## Why release_partition() must explicitly reset them

release_p= artition() is called when moving to a new partition and must
reset per-p= artition state. Unlike ExecInitWindowAgg() which creates a
fresh structu= re, release_partition() reuses an existing structure that
contains value= s from the previous partition.

The root cause of the reset requireme= nt is that release_partition()
calls MemoryContextReset(winstate->par= tcontext), which frees all
partition-local memory. This includes:
=C2= =A0 - All NFA context structures pointed to by nfaContext
=C2=A0 - All N= FA state nodes in the free lists (nfaContextFree, nfaStateFree)
=C2=A0 -= All other partition-specific data

As a consequence of this memory r= eset:
=C2=A0 1. The NFA pointers (nfaContext, nfaContextFree, etc.) must= be set to
=C2=A0 =C2=A0 =C2=A0NULL to avoid dangling pointers
=C2=A0= 2. The active resource counters (nfaStatesActive, nfaContextsActive)
= =C2=A0 =C2=A0 =C2=A0must be reset to 0 since all the resources they were co= unting have
=C2=A0 =C2=A0 =C2=A0been freed

Example scenario:
= =C2=A0 Partition 1 processing:
=C2=A0 =C2=A0 - nfaStatesActive increment= s one-by-one as states are allocated,
=C2=A0 =C2=A0 =C2=A0 decrements as= they are freed, fluctuates during execution,
=C2=A0 =C2=A0 =C2=A0 ends = at some non-zero value (e.g., 3)
=C2=A0 =C2=A0 - nfaContextsActive simil= arly fluctuates, ends at some value (e.g., 2)

=C2=A0 Partition 2 sta= rts =E2=86=92 release_partition() called:
=C2=A0 =C2=A0 - MemoryContextR= eset(partcontext) frees all NFA structures
=C2=A0 =C2=A0 - nfaContext, n= faContextFree, etc. =E2=86=92 must set to NULL
=C2=A0 =C2=A0 - nfaStates= Active: 3 =E2=86=92 must reset to 0
=C2=A0 =C2=A0 - nfaContextsActive: 2= =E2=86=92 must reset to 0

These counters track instantaneous active= resources within a partition,
so they must be reset to 0 when starting = a new partition. In contrast,
cumulative statistics like nfaStatesMax an= d nfaStatesTotalCreated are
NOT reset because they track overall query-w= ide statistics across all
partitions.

## Why only these two count= ers?

You might wonder why I don't propose initializing all the o= ther NFA
statistics fields as well. ExecInitWindowAgg() currently omits = explicit
initialization for many statistics fields:

=C2=A0 Per-pa= rtition internal counters (reset at partition boundaries):
=C2=A0 =C2=A0= - nfaStatesActive =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0(omitted)
=C2=A0 = =C2=A0 - nfaContextsActive =3D 0; =C2=A0 =C2=A0 =C2=A0(omitted)

=C2= =A0 Query-wide cumulative statistics (never reset):
=C2=A0 =C2=A0 - nfaS= tatesMax =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (om= itted)
=C2=A0 =C2=A0 - nfaStatesTotalCreated =3D 0; =C2=A0 =C2=A0 =C2=A0= =C2=A0(omitted)
=C2=A0 =C2=A0 - nfaStatesMerged =3D 0; =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(omitted)
=C2=A0 =C2=A0 - nfaContextsM= ax =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (omitted)
=C2= =A0 =C2=A0 - nfaContextsTotalCreated =3D 0; =C2=A0 =C2=A0 =C2=A0(omitted)=C2=A0 =C2=A0 - nfaContextsAbsorbed =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0(omitted)
=C2=A0 =C2=A0 - nfaContextsSkipped =3D 0; =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (omitted)
=C2=A0 =C2=A0 - nfaContextsPruned =3D 0; = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(omitted)
=C2=A0 =C2=A0 - nfaMa= tchesSucceeded =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(omitted)
=C2=A0= =C2=A0 - nfaMatchesFailed =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (omitted)
=C2=A0 =C2=A0 - nfaMatchLen =3D {0, 0, 0}; =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(omitted)
=C2=A0 =C2=A0 - nfaFailLen =3D {0, 0, 0}; =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (omitted)
=C2=A0 =C2=A0 - nfaAbsorbedLen= =3D {0, 0, 0}; =C2=A0 =C2=A0 =C2=A0 (omitted)
=C2=A0 =C2=A0 - nfaSkippe= dLen =3D {0, 0, 0}; =C2=A0 =C2=A0 =C2=A0 =C2=A0(omitted)

The key dis= tinction is that nfaStatesActive and nfaContextsActive are
the ONLY stat= istics that get reset in release_partition(). All the other
statistics a= re cumulative across the entire query and should never be
reset between = partitions.

For example, nfaStatesMax tracks the peak number of acti= ve states across
ALL partitions, not just within one partition. Similarl= y,
nfaStatesTotalCreated accumulates the total count across all partitio= ns.
These cumulative statistics start at 0 (via palloc0) and only increa= se,
never getting reset.

Therefore, I believe it only makes sense= to add explicit initialization
for nfaStatesActive and nfaContextsActiv= e, since these are the only two
that release_partition() also explicitly= resets. Adding explicit
initialization for all the cumulative statistic= s would be misleading,
as it might suggest they get reset somewhere (whi= ch they don't).

## Proposal for consistency

For consisten= cy with release_partition(), I can add just the two
per-partition counte= r initializations to ExecInitWindowAgg():

=C2=A0 /* Initialize NFA f= ree lists for row pattern matching */
=C2=A0 winstate->nfaContext =3D= NULL;
=C2=A0 winstate->nfaContextTail =3D NULL;
=C2=A0 winstate-&= gt;nfaContextFree =3D NULL;
=C2=A0 winstate->nfaStateFree =3D NULL;=C2=A0 winstate->nfaLastProcessedRow =3D -1;
=C2=A0 winstate->nf= aStatesActive =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0// Add this
=C2=A0 winst= ate->nfaContextsActive =3D 0; =C2=A0 =C2=A0 =C2=A0// Add this

Thi= s would make both ExecInitWindowAgg() and release_partition()
initialize= the same set of per-partition NFA fields, making the code
more uniform = and easier to review. The cumulative statistics fields
remain omitted in= both functions, which correctly reflects that they
are never reset.
=
Functionally, this change makes no difference since palloc0() alreadyzeros these fields, but it improves code consistency and makes the
per= -partition vs. query-wide distinction clearer.

Would you like me to = include this change in the next patch?

Best regards,
Henson
--000000000000b20b300649fbb46f--