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 1wU8ul-000yNu-0v for pgsql-hackers@arkaria.postgresql.org; Mon, 01 Jun 2026 20:07: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 1wU8uk-00B5W0-0h for pgsql-hackers@arkaria.postgresql.org; Mon, 01 Jun 2026 20:07: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 1wU8uj-00B5Vj-2C for pgsql-hackers@lists.postgresql.org; Mon, 01 Jun 2026 20:07:09 +0000 Received: from fout-b2-smtp.messagingengine.com ([202.12.124.145]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wU8uh-00000000d7E-3AKY for pgsql-hackers@postgresql.org; Mon, 01 Jun 2026 20:07:08 +0000 Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 422951D000B1; Mon, 1 Jun 2026 16:07:06 -0400 (EDT) Received: from phl-imap-08 ([10.202.2.84]) by phl-compute-05.internal (MEProxy); Mon, 01 Jun 2026 16:07:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=compiler.org; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm1; t=1780344425; x=1780430825; bh=AMEY/UDfwRPRCkBVENIKO+GZw0WLCeTP5o/JVwIucfM=; b= 6I9pJObmmkYOZ3AFgNAUfnn0YtpK7/gNUFWcH0Fhy+E5y2VOyaMmJSyL1PImJnD+ jqWNevDSXBp11/RimN/iAzoW8mBfEGb+C/RsaPqyVdOWK/gxz7z9lwHlk0ioEiPS HG+DqcJ/CEuXgNZJjGIZT44PJ0/snkGQyKc5MN2j96jpZLQtNdkGdcehCVq7UiH3 TuaKU/jqWnK2Tm7/4yRG5eKmH0m9V3yL/QO05rIM3KuvsQanmtYi9Vs0zd0rd9z8 5Duey5K/o71GoM+8CGrChxCDI3bLFwFVT6YalO+vdlnkFvAQbpo1jx8cfyvmrMZQ LUGAtXe8sfe1jYUwRTSDqg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1780344425; x= 1780430825; bh=AMEY/UDfwRPRCkBVENIKO+GZw0WLCeTP5o/JVwIucfM=; b=G NsjVm8DkciCWOyP9Ik7/9lt6gp2DtzHKT9MlIU9fjm3KXK3yXQVYgSMaoKu7s+Zb ltSX+jpBLHE51zHouWS4VPYMs2U7soQk99eWfz4Cd+70rzVzWxFTj3/P+Xps+vUe tHwgctxqeAzMIHP0DN0bmK8P3jlJM35mJzrAsN2OfDCz/eraBtzyjydbQkNXGxPO PuHxMhj0B7RTICV81D84xgHkqlKa4M+Mdp0dEiJ6xYRyENRfPkPMZfjRoZps2EZQ uDC/ymC3uk6c1wyOIGegyLvvIN4ICAjlm0otIDj43LbjbjETluSTl1wPVEMY/Nkn xIcruSRr9YlOQu/014GNg== X-ME-Sender: X-ME-Proxy-Cause: dmFkZTGbPwJ+WKa4jX13oX8/YYxr7z3EVkgR0RJqSaGzAgj/C0bgiwJ1+0KwA1mcJFpsHP 0HHFfYX3qKGx3/9RU4daylHyUytGEcSsXrGCwRQCPXO2ehr856jG8chj9y02EuwJYCAMMT 45ewSVlA2J+2uSiewDQcTYAqW8/P2+4BNUjlwG0EaUd4gutHHwt1xwsZVNt+4eKPoeNTQR /fcih4OPPJXTA9JeyqxWc7FmXs877rJPNdPyUliJn1stF3tFgHVDkBZ9b3InptuYoH0Qq2 NjQqU72I54C/I5/Ahcv8CbWaaYYmvvt1dTXmPBTsjsa6t166207X/DIUozV28O4QIoK/Di ZAjEmqfkxcOMQI/tLFptEhSSpSUcMrAAts4yEWRtllvSwKsLiqpQ7KXdQZYNBfRaSaRfrH mHsO9TLcy1KUVCh2hQ4h/SqDHSgT4rDNZm6DSPSEoNylucHZkSt3/aYXbQprz4txgs0yOY krN73uwqagFlUmVZMcJQF78Oe4BHoL3vb9BWgWbETnQDO749SCh0FW1RDHior9jmo/wrtq 0bjIJVpDuyj5XtszHAvJKhIW6SC1B3Kh6z1ia/YF8GS2mk5AKMRRXW+3SD/FQv4Rr3seBx 8g6THEAfDiN8C8R05ae5hlK/1oWej4e8r/tmG4miHbUzkWsHBJXMEzdi3qrw X-ME-Proxy: Feedback-ID: ic6394509:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 1822B2CE1D5B; Mon, 1 Jun 2026 16:07:05 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface MIME-Version: 1.0 X-ThreadId: AN_Vy_h1VtK3 Date: Mon, 01 Jun 2026 22:06:44 +0200 From: "Joel Jacobson" To: "Laurenz Albe" , pgsql-hackers Cc: "Arne Roland" , "Anders Granlund" , "Andreas Karlsson" , "Vik Fearing" Message-Id: <9ac96604-8112-4750-b0ca-a6ab41d51d31@app.fastmail.com> In-Reply-To: <4a34b3e4-fa4c-446d-beb6-45ccac536086@app.fastmail.com> References: <00c30670-64e1-4c30-a349-784426d333df@app.fastmail.com> <264e69aed5a2fdd93ad555dff96daeabc5c35724.camel@cybertec.at> <2ac20bea-4130-4cf3-8e13-ea7c6d062296@app.fastmail.com> <348b4bd1d4215d475952b7f5527a092a1491a2c1.camel@cybertec.at> <4a34b3e4-fa4c-446d-beb6-45ccac536086@app.fastmail.com> Subject: Re: Key joins Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Sun, May 31, 2026, at 16:40, Joel Jacobson wrote: > On Sun, May 31, 2026, at 10:05, Joel Jacobson wrote: >> On Fri, May 29, 2026, at 18:20, Laurenz Albe wrote: >>> On Fri, 2026-05-29 at 15:21 +0200, Joel Jacobson wrote: >>>> We actually originally considered TO and FROM as keywords for indic= ating >>>> direction, but FROM in a join clause causes confusion with the FROM >>>> clause itself.=C2=A0 Our user discussions over the last three years= indicates >>>> that arrows are clearer and less ambiguous. >>>>=20 >>>> It's also worth to mention that SQL/PGQ also uses ASCII arrows to >>>> indicate direction for its graph pattern syntax. >>> >>> I understand the problem with FROM, and I have no objection to the >>> arrows. >> >> Thanks for reviewing. >> >> v7 updates 0002 to match the revised Change Proposal wording for >> GROUPING SETS/ROLLUP/CUBE: > > v8 fixes another nondeterministic isolation-test ordering issue seen by > cfbot on the FreeBSD machine. > > 0001 and 0003 are unchanged from v7. I noted a small error in 7.4.13 in the paper. The examples incorrectly used "LEFT JOIN" instead of "JOIN", which made the claim "Both queries, if accepted, would produce the same result rows" to not hold true. Fixed subsection below: =3D=3D=3D 7.4.13 Filtered Views and the PK Side A key join through a filtered view on the PK side is rejected unless the FK side supplies matching direct key-equality filter evidence; see Section 7.3.2. This differs from a query that filters the base table with a WHERE clause after the join: For the examples below, assume orders has a NOT NULL customer_id that references customers (id). -- Accepted: join the full base table, then filter the result. SELECT * FROM orders AS o JOIN customers AS c FOR KEY (id) <- o (customer_id) WHERE c.active; CREATE VIEW active_customers AS SELECT * FROM customers WHERE active; -- Rejected: the view is the PK side and lacks row coverage. SELECT * FROM orders AS o JOIN active_customers AS ac FOR KEY (id) <- o (customer_id); ERROR: key join from referencing relation o to referenced relation ac c= annot be proven ERROR: key join from referencing relation o to referenced relation ac c= annot be proven LINE 3: JOIN active_customers AS ac FOR KEY (id) <- o (customer_id); ^ DETAIL: Not every o (customer_id) value can be proven to have a matchin= g ac row. Referenced relation ac is filtered before this key join. The r= elevant operation occurs inside view public.active_customers. Both queries, if accepted, would produce the same result rows, but would differ from the key join's perspective. In the first query, the join is against the full customers table: every order is guaranteed to find its matching customer, and the WHERE clause filters the result after the join has been evaluated. In the second query, active_customers is the PK side, and it is missing inactive customers. An order that references an inactive customer will not find a match. This asymmetry is inherent in row coverage. A key join guarantees that the join will behave as a proper foreign key traversal, producing exactly one match for each FK row. A filtered PK side breaks this guarantee unless the missing PK values are matched by filters that remove the corresponding FK rows before the join. =3D=3D=3D /Joel