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 1waSRb-001ofT-0W for pgsql-hackers@arkaria.postgresql.org; Fri, 19 Jun 2026 06:11:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1waSRa-00F7e6-0D for pgsql-hackers@arkaria.postgresql.org; Fri, 19 Jun 2026 06:11:10 +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 1waSRZ-00F7dy-29 for pgsql-hackers@lists.postgresql.org; Fri, 19 Jun 2026 06:11:09 +0000 Received: from mail-ed1-x52e.google.com ([2a00:1450:4864:20::52e]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1waSRY-0000000164b-1Dvv for pgsql-hackers@postgresql.org; Fri, 19 Jun 2026 06:11:08 +0000 Received: by mail-ed1-x52e.google.com with SMTP id 4fb4d7f45d1cf-68c76fb8009so2661342a12.0 for ; Thu, 18 Jun 2026 23:11:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1781849466; cv=none; d=google.com; s=arc-20240605; b=WVX0gr7v+ZWF6z17A+XO24mEm4pTAvG3g2z0M5XL0PioKDfBAThZMCTj6xIFGUzi53 G6ytnfGvpfx0VSsaYLIyZ22t0xLCzMP3L79MWClp+v9nddAxP4uE0pP1hTgduJcs3jF+ p+YWp0peQ9fcPMk+gUXoH9aHG648cX31628mjRXkX2d95ygihk1bLZrwQsGLSFLau3lW +Z0KQVKBTncIuYERMMX2FNkfOKjA+xfUAePx57oOwdxiBdHVag+HG5LbTIFZhUr7vbHR pCD77oFwDmv8jIVv686fWu/jMgig5REvc8eJwAV6BpviQzYbS0Rj8Gj6jfmltDQ5asWo 4lTA== 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=it2rlfqDApLCrCFBPzZTIPn1QiGU72jSxbYbgiF5lTQ=; fh=rm6iyRQPq6PUpxxY+lbTyPh+1V9qrjMEGSjYvbaXPTY=; b=Hosc2/TtjnaYP0dcX+GUlZSBcyDa1tpV/aPdWKFU0Ecj6bLdwsv365bgI1fjZxcjjw rpW6mMtqhpyrc+j0TKUaiXdHIITRFOKmBuMKHstKdOTEr+wYMECcfLyHbreezGMDWr36 AgHYF5CYSRgUxw7vzYn4r77lkzkM5a0taZ9c/fNz5HkjowxZFy4/FdH8478uuXBwFWZt N1Y51+UHMG5LntZYgZWy95M7PxZUI/5X0z6JYhcw+xvVYom7OEmblPBErtpCiXA9YOg/ R4icJuewwc1V5Njzb5L8azvI03/ZYOZJqmJrsWlAa9K+JM+8PkFocG8OfHM4Zh2xpejD 0Pyg==; 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=20251104; t=1781849466; x=1782454266; 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=it2rlfqDApLCrCFBPzZTIPn1QiGU72jSxbYbgiF5lTQ=; b=nASZRReRBZHN5ex9XpL5LPw4JkQpTE3N85YIiYx4mJTggA9JW0AW3EpJxcWSxs+sXJ fPpQgXIr9hXQGOU5jPFvcMwlujfBGBilVr9nhSYwkz/S3sStzr/qGqlEUmpKPHLsESbe pz0XGCAOkvvCtTuqSIbgjlA5v+rh316lSLAlHd+INI48T5XPyTalKZbeI58h5scsB850 tnOGJmcVx1Lsm2dg51NRDTiY8Ty4ICn/VADT587awUnSiThLjC2w8cSRBOZldGY93I2H VnnO5FrCQ6cIFLHe6nbnPdo/Hs0vhJ/eZOPhWxzbOyO6KdI15MCJOxceWzLiuh4wmvUN 0pRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781849466; x=1782454266; 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=it2rlfqDApLCrCFBPzZTIPn1QiGU72jSxbYbgiF5lTQ=; b=iUwGU6od7sEWuBhvuzhSebT7houq4xKdbSCUHDcuhVsOq2iJBNDBkZeAQ/bpU0FjBR uF+mGQ4PGkf35N9CCm/0iwvUsVb287lBeCRpPSmxblhZd9lgh77RyJ7Wm7T1XbgvfzCZ fxiIDAtZp5M0++jo7nZ50+DzZKd3zkID8v0yk4f8rZX3KuM/q+yrTHrLDQbTPIZun/mG fg4SX9tnY1s5iTQJGozRx/Azp6d+WIs5teVSMKGenJOTRBKj5mIHJ2ls6HzCgPWDrELH mY8R51UnJEjcdOeVoO3eXw4UVrIS2vAq8/NIpvm7FLRMMX1FQsZZr6wOFxH2eyDvCguh Sp5A== X-Forwarded-Encrypted: i=1; AFNElJ+QnCM2nuG4kbu8L2eNY4ztZbXwIGJUQ0HlyMyMpq88Ky9pLfw9dB1bjst4/G32VebRjMtzxkJXKYSltk40@postgresql.org X-Gm-Message-State: AOJu0YziWTnX79ZBytx0fZhM3lMugiImRYWaDhGfpBV1lAZk4ku9n445 m6WGMFjPwTfmnf0q0XFFc7GmqjpGInrFI2EQnZOCQ/f8Z8zltuFsKIWpnkYvReYy2DQcR7rLyY9 ngqOiP58Tf82fFJOg5BxQJB/r5eHIF+qXYxwycEc= X-Gm-Gg: AfdE7cmQS1McHGitpW6apqsDmB2IIPt+MPS2B1y4lcL82tXf3n3YfwnOn4ouF/ElLL0 EcvAUE09pxwqXGl/E4lpDa1GjvTLbdQH8ta8JlewclKeiMvnPd8u24Nllc5Nc8cP5YIXHgriuxJ hcfVVoaJ2VTUxnceM6wOrJ63VEhvNrOyobqqxMVNPPRjGHo5NzaKTNSxXuT+9+a+2k7DM7AJ2qs NTpWo8IgsufduuqpWNMhdK13d0VVEiv449uJaGcuneoVY7ce22y3UH/9508+gBj5xsZ4uQJFKfa lgZNLiDNSdOonlqtJUSuzra22h9XNGGM/ujylhkyz16Qjf2beyF/MR2MsSn0dO2IqQ6MHzF+o3X hcesP2gT+6Q== X-Received: by 2002:a17:906:4785:b0:c07:3e6f:5656 with SMTP id a640c23a62f3a-c0b743b1100mr47184766b.33.1781849466044; Thu, 18 Jun 2026 23:11:06 -0700 (PDT) MIME-Version: 1.0 References: <20260618.185007.1430819167281911424.ishii@postgresql.org> In-Reply-To: Reply-To: assam258@gmail.com From: Henson Choi Date: Fri, 19 Jun 2026 15:10:54 +0900 X-Gm-Features: AVVi8Cf4y-BjEd5fyX-SGFTiZ2moiBDNR4gK2BO3czX1tbvjkEuZanjc3D0XKO0 Message-ID: Subject: Re: Row pattern recognition To: Tatsuo Ishii , jian he 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 Content-Type: multipart/alternative; boundary="00000000000077835f06549528fd" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --00000000000077835f06549528fd Content-Type: text/plain; charset="UTF-8" Hi hackers, When a WINDOW clause is not referenced by any window function, the pattern is never matched and the DEFINE expressions are never evaluated. One consequence is that a DEFINE which would raise a run-time error raises nothing when the window is unused. The same window definition behaves differently depending only on whether a window function consumes it: CREATE TABLE t (id int, v int); INSERT INTO t VALUES (1, 10), (2, 20), (3, 15); -- (1) the window IS used (count(*) OVER w): the DEFINE is evaluated SELECT count(*) OVER w AS cnt FROM t WINDOW w AS ( ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING INITIAL PATTERN (A+) DEFINE A AS (1 / (v - v)) > 0 ); -- ERROR: division by zero -- (2) the window is NOT used (no window function): same definition SELECT v FROM t WINDOW w AS ( ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING INITIAL PATTERN (A+) DEFINE A AS (1 / (v - v)) > 0 ); -- v -- ---- -- 10 -- 20 -- 15 -- (no error) EXPLAIN (VERBOSE, COSTS OFF) of (2) confirms the window, and with it the DEFINE expression, are gone entirely: Seq Scan on public.t Output: v, id (A column-dependent division by zero is used so that the expression does not constant-fold and can only error at run time.) This follows from existing, general planner behavior. A window definition that no window function references is removed from the plan by select_active_windows(); the planner does this for every window, because a window with no consumer produces no output, so sorting or partitioning it would be wasted work. Before RPR that reasoning was complete: an ordinary window has nothing but its output, so dropping an unused one changes nothing observable. RPR is what turns this into a question. A DEFINE clause is a per-row predicate that can have a run-time effect of its own -- here, raising an error -- independent of any output the window produces. So the assumption behind the optimization, that an unused window has no observable behavior, no longer holds automatically once a window carries a DEFINE. Whether the existing "drop it" optimization should still extend to an RPR window is a decision RPR's addition forces, not something the prior behavior settles. The question is whether the current behavior is what we want: (a) Keep it. Skipping the pattern matching for a window that produces nothing is the natural optimization, and an expression that is never evaluated raising no error is normal behavior. (b) Run the matching anyway, even though there is no output to produce, so that DEFINE errors are raised regardless of whether a window function consumes the window. Option (a) is cheaper and consistent with how unevaluated expressions behave, but I lean towards (b): a faulty DEFINE should fail consistently rather than pass silently just because no window function happens to consume the window. I would like to hear what you think. Regards, Henson --00000000000077835f06549528fd Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi hackers,

When a WINDOW clause is not referenced = by any window function, the pattern
is never matched and the DEFINE expr= essions are never evaluated.

One consequence is that a DEFINE which = would raise a run-time error raises
nothing when the window is unused.= =C2=A0 The same window definition behaves
differently depending only on = whether a window function consumes it:

=C2=A0 CREATE TABLE t (id int= , v int);
=C2=A0 INSERT INTO t VALUES (1, 10), (2, 20), (3, 15);

= -- (1) the window IS used (count(*) OVER w): the DEFINE is evaluated
=C2=A0 SELECT count(*) OVER w AS cnt
=C2=A0 FROM t
=C2=A0 WINDOW w A= S (
=C2=A0 =C2=A0 =C2=A0 ORDER BY id
=C2=A0 =C2=A0 =C2=A0 ROWS BETWEE= N CURRENT ROW AND UNBOUNDED FOLLOWING
=C2=A0 =C2=A0 =C2=A0 INITIAL
= =C2=A0 =C2=A0 =C2=A0 PATTERN (A+)
=C2=A0 =C2=A0 =C2=A0 DEFINE A AS (1 / = (v - v)) > 0
=C2=A0 );
=C2=A0 -- ERROR: =C2=A0division by zero
=
-- (2) the window is NOT used (no window function): same definition
=
=C2=A0 SELECT v
=C2=A0 FROM t
=C2=A0 WINDOW w AS (
=C2=A0 =C2= =A0 =C2=A0 ORDER BY id
=C2=A0 =C2=A0 =C2=A0 ROWS BETWEEN CURRENT ROW AND= UNBOUNDED FOLLOWING
=C2=A0 =C2=A0 =C2=A0 INITIAL
=C2=A0 =C2=A0 =C2= =A0 PATTERN (A+)
=C2=A0 =C2=A0 =C2=A0 DEFINE A AS (1 / (v - v)) > 0=C2=A0 );
=C2=A0 -- =C2=A0v
=C2=A0 -- ----
=C2=A0 -- =C2=A010=C2=A0 -- =C2=A020
=C2=A0 -- =C2=A015
=C2=A0 -- (no error)

EX= PLAIN (VERBOSE, COSTS OFF) of (2) confirms the window, and with it the
D= EFINE expression, are gone entirely:

=C2=A0 =C2=A0 =C2=A0 Seq Scan o= n public.t
=C2=A0 =C2=A0 =C2=A0 =C2=A0 Output: v, id

(A column-de= pendent division by zero is used so that the expression does not
constan= t-fold and can only error at run time.)

This follows from existing, = general planner behavior.=C2=A0 A window definition
that no window funct= ion references is removed from the plan by
select_active_windows(); the = planner does this for every window, because a
window with no consumer pr= oduces no output, so sorting or partitioning it
would be wasted work.=C2= =A0 Before RPR that reasoning was complete: an ordinary
window has nothi= ng but its output, so dropping an unused one changes nothing
observable.=

RPR is what turns this into a question.=C2=A0 A DEFINE clause is a = per-row
predicate that can have a run-time effect of its own -- here, ra= ising an
error -- independent of any output the window produces.=C2=A0 S= o the assumption
behind the optimization, that an unused window has no o= bservable behavior, no
longer holds automatically once a window carries = a DEFINE.=C2=A0 Whether the
existing "drop it" optimization sh= ould still extend to an RPR window is a
decision RPR's addition forc= es, not something the prior behavior settles.

The question is whethe= r the current behavior is what we want:

=C2=A0 (a) Keep it.=C2=A0 Sk= ipping the pattern matching for a window that produces
=C2=A0 =C2=A0 =C2= =A0 nothing is the natural optimization, and an expression that is never=C2=A0 =C2=A0 =C2=A0 evaluated raising no error is normal behavior.
=C2=A0 (b) Run the matching anyway, even though there is no output to prod= uce, so
=C2=A0 =C2=A0 =C2=A0 that DEFINE errors are raised regardless of= whether a window function
=C2=A0 =C2=A0 =C2=A0 consumes the window.
=
Option (a) is cheaper and consistent with how unevaluated expressionsbehave, but I lean towards (b): a faulty DEFINE should fail consistently<= br>rather than pass silently just because no window function happens to con= sume
the window.=C2=A0 I would like to hear what you think.

Regar= ds,
Henson
--00000000000077835f06549528fd--