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 1waV2z-001qa4-0U for pgsql-hackers@arkaria.postgresql.org; Fri, 19 Jun 2026 08:57:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1waV2x-00FZnz-0H for pgsql-hackers@arkaria.postgresql.org; Fri, 19 Jun 2026 08:57:55 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1waV2w-00FZnq-26 for pgsql-hackers@lists.postgresql.org; Fri, 19 Jun 2026 08:57:54 +0000 Received: from meldrar.postgresql.org ([2a02:c0:301:0:ffff::31]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1waV2u-00000001F9H-0Fj1 for pgsql-hackers@postgresql.org; Fri, 19 Jun 2026 08:57:54 +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=ma5G1wOyw91f3sLEBsq/6mjw66cPh2YaMCkPMDhHRdQ=; b=jX2UWPUUXJFN+nskZPUMOFKUp4 AoY1axRz2anO/3Xr2tFlXVqvDMjNEj/NSfyKyMS9fBAT9kKSsusIV6Llu8vfcnBb4jltDZBCuKeBG /0RsK3M/DIo1YQZKLCEev9cl1kmqvlz6GLQvWx8eaCApdOIq7Ion/EgZLzZxdMcchpwrHeyegbHdt yfrHEW+jLBT/6nu3R7soQxbEZcH9v5S9xCTCvPjQWzAjMeyVC11Ukqy22XedN3JKqEGJZy10Tf18L gVxD889bVbCUQd1Y9xiVn6r4bP6j38K8R7EYaqFC7pqz3/SsQE4Dix8ucaxz5xAVtz9sXcCg6b5va dHUTjLjg==; Received: from [2409:11:4120:300:758f:c2ab:d7c1:e3d] (helo=localhost) by meldrar.postgresql.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1waV2m-003Bw8-2K; Fri, 19 Jun 2026 08:57:46 +0000 Date: Fri, 19 Jun 2026 17:57:28 +0900 (JST) Message-Id: <20260619.175728.667662038194755204.ishii@postgresql.org> To: assam258@gmail.com Cc: jian.universality@gmail.com, 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:758f:c2ab:d7c1:e3d (failed) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi Henson, > 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. I think we should follow (a).