From: Richard Guo <guofenglinux@gmail.com>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: Bruce Momjian <bruce@momjian.us>
Cc: David Rowley <dgrowleyml@gmail.com>
Cc: Ronald Cruz <cruz@rentec.com>
Cc: pgsql-bugs@lists.postgresql.org, Peter Ford <pford@rentec.com>
Cc: Aaron J. Garcia <agarcia@rentec.com>
Subject: Re: Query result differences between PostgreSQL 17 vs 16
Date: Mon, 3 Mar 2025 15:40:47 +0900
Message-ID: <CAMbWs4_4HBfqs+AjrtNOeqZYwKTJps2jANzdCbAfQSCd-CdeGA@mail.gmail.com> (raw)
In-Reply-To: <2748914.1740757698@sss.pgh.pa.us>
References: <f5320d3d-77af-4ce8-b9c3-4715ff33f213@rentec.com>
<Z7kGplh70wbeX9su@momjian.us>
<3736132.1740181858@sss.pgh.pa.us>
<CAMbWs4_A=DFhTHQvbtCXpzs7OBGb0HcNX-yDsf01chVP60D9EQ@mail.gmail.com>
<3818495.1740191559@sss.pgh.pa.us>
<CAMbWs4_BCC8+4PqJi2NcO5WTu5vsJPMh7iAe7e=nXNVTZNp+LQ@mail.gmail.com>
<CAMbWs49rShAwK0sMz+-6d9hGd1RsRQd0tBuVUGvh88pNu9hG1w@mail.gmail.com>
<1716556.1740551169@sss.pgh.pa.us>
<CAMbWs4_SqFDZ1Mnp0Kmy-H2s7_-PdeuXva+kBG-jKSampoDHnw@mail.gmail.com>
<CAMbWs48-_meMqqbkFQoVEEKBYYsanMvRk3zCqmVr23gyxkNhag@mail.gmail.com>
<2337383.1740630494@sss.pgh.pa.us>
<CAMbWs4-ATTw82Pc3B+64im26JQEWHemC-6VcGzqqqo_mjCEqpw@mail.gmail.com>
<2748914.1740757698@sss.pgh.pa.us>
On Sat, Mar 1, 2025 at 12:48 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Richard Guo <guofenglinux@gmail.com> writes:
> > Now I'm inclined to agree with you. It seems we've been lucky so far
> > not to encounter issues with IS NULL deductions on clone clauses, but
> > this feels like a problem waiting to happen in the future.
>
> Yes, I'm on board with that too. I think the comments need more work
> than you've done though. I think they should say something about
> "nullingrel bits in clone clauses may not reflect reality, so we dare
> not draw conclusions from clones about whether Vars are guaranteed
> not-null". Also, I'm not convinced any more that this has anything to
> do with missing clone members, so we should remove that claim.
Agreed. Thanks for the suggestion.
> > The no-clone-quals limitation in restriction_is_always_false makes the
> > fix in f00ab1fd1 unnecessary. I think we should revert those changes.
>
> Hmm, I'm less on board with that. The saving-and-restoring of
> last_rinfo_serial looks correct to me, even though this fix might
> cause the test case you found before to not tickle that bug.
Fair point.
> > Attached is the updated patch.
>
> I'm confused by the changes to existing test cases in this? It looks
> like you're undoing some test changes that are not from f00ab1fd1, so
> I don't understand why. My inclination here would be to add a new
> test that exposes the current bug, but leave the rest alone, even
> though they may no longer be testing exactly what they were originally
> meant to do.
Yeah, the patch modifies some existing test cases that are intended to
test a join clause that is IS_NOT_NULL/IS_NULL qual can or cannot be
reduced depending on whether its Var is nullable by any outer joins.
And it happens that the join clauses in these test cases are clone
clauses, which are excluded from reduction by the fix here. As a
result, they are no longer testing what they are intended to. This
patch modifies them to ensure that those join clauses are not clone
clauses.
This patch also adds a new test that exposes the current bug, and
tests that clone clauses are not reduced to constant true/false.
Here is an updated patch, which also includes the test case you found
proving the no-clone-quals limitation in restriction_is_always_false
is also needed.
Thanks
Richard
Attachments:v3-0001-Avoid-NullTest-deduction-for-clone-clauses.patch (application/octet-stream, 16.7K) download
From 239a8aa690950306eb60d842da4dc40675862a75 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Wed, 26 Feb 2025 10:39:14 +0900
Subject: [PATCH v3] Avoid NullTest deduction for clone clauses
In commit b262ad440, we introduced an optimization that reduces an IS
NOT NULL qual on a column defined as NOT NULL to constant true, and an
IS NULL qual on a NOT NULL column to constant false, provided we can
prove that the input expression of the NullTest is not nullable by any
outer join. This deduction happens after we have generated multiple
clones of the same qual condition to cope with commuted-left-join
cases.
However, performing the NullTest deduction for clone clauses can be
unsafe, because we don't have a reliable way to determine if the input
expression of a NullTest is non-nullable: nullingrel bits in clone
clauses may not reflect reality, so we dare not draw conclusions from
clones about whether Vars are guaranteed not-null.
To fix, we check whether the given RestrictInfo is a clone clause in
restriction_is_always_true and restriction_is_always_false, and avoid
performing any reduction if it is.
There are several ensuing plan changes in predicate.out, and we have
to modify the tests to ensure that they continue to test what they are
intended to. Additionally, this fix causes the test case added in
f00ab1fd1 to no longer trigger the bug that commit fixed, so we also
remove that test case.
Back-patch to v17 where this bug crept in.
Reported-by: Ronald Cruz <cruz@rentec.com>
Diagnosed-by: Tom Lane <tgl@sss.pgh.pa.us>
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/f5320d3d-77af-4ce8-b9c3-4715ff33f213@rentec.com
Backpatch-through: 17
---
src/backend/optimizer/plan/initsplan.c | 18 +++
src/test/regress/expected/predicate.out | 191 +++++++++++++++---------
src/test/regress/sql/predicate.sql | 59 +++++---
3 files changed, 175 insertions(+), 93 deletions(-)
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.cindex 2cb0ae6d659..1d1aa27d450 100644--- a/src/backend/optimizer/plan/initsplan.c+++ b/src/backend/optimizer/plan/initsplan.c@@ -3091,6 +3091,15 @@ bool
restriction_is_always_true(PlannerInfo *root,
RestrictInfo *restrictinfo)
{
+ /*+ * For a clone clause, we don't have a reliable way to determine if the+ * input expression of a NullTest is non-nullable: nullingrel bits in+ * clone clauses may not reflect reality, so we dare not draw conclusions+ * from clones about whether Vars are guaranteed not-null.+ */+ if (restrictinfo->has_clone || restrictinfo->is_clone)+ return false;+
/* Check for NullTest qual */
if (IsA(restrictinfo->clause, NullTest))
{
@@ -3140,6 +3149,15 @@ bool
restriction_is_always_false(PlannerInfo *root,
RestrictInfo *restrictinfo)
{
+ /*+ * For a clone clause, we don't have a reliable way to determine if the+ * input expression of a NullTest is non-nullable: nullingrel bits in+ * clone clauses may not reflect reality, so we dare not draw conclusions+ * from clones about whether Vars are guaranteed not-null.+ */+ if (restrictinfo->has_clone || restrictinfo->is_clone)+ return false;+
/* Check for NullTest qual */
if (IsA(restrictinfo->clause, NullTest))
{
diff --git a/src/test/regress/expected/predicate.out b/src/test/regress/expected/predicate.outindex 965a3a76161..b79037748b7 100644--- a/src/test/regress/expected/predicate.out+++ b/src/test/regress/expected/predicate.out@@ -97,55 +97,50 @@ SELECT * FROM pred_tab t WHERE t.b IS NULL OR t.c IS NULL;
-- and b) its Var is not nullable by any outer joins
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL;- QUERY PLAN --------------------------------------------------+ LEFT JOIN pred_tab t2 ON t1.a IS NOT NULL;+ QUERY PLAN +-------------------------------------
Nested Loop Left Join
-> Seq Scan on pred_tab t1
-> Materialize
- -> Nested Loop Left Join- -> Seq Scan on pred_tab t2- -> Materialize- -> Seq Scan on pred_tab t3-(7 rows)+ -> Seq Scan on pred_tab t2+(4 rows)
-- Ensure the IS_NOT_NULL qual is not ignored when columns are made nullable
-- by an outer join
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON t1.a = 1+ FULL JOIN pred_tab t2 ON t1.a = t2.a
LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL;
QUERY PLAN
-------------------------------------------
Nested Loop Left Join
Join Filter: (t2.a IS NOT NULL)
- -> Nested Loop Left Join- Join Filter: (t1.a = 1)- -> Seq Scan on pred_tab t1- -> Materialize+ -> Merge Full Join+ Merge Cond: (t1.a = t2.a)+ -> Sort+ Sort Key: t1.a+ -> Seq Scan on pred_tab t1+ -> Sort+ Sort Key: t2.a
-> Seq Scan on pred_tab t2
-> Materialize
-> Seq Scan on pred_tab t3
-(9 rows)+(12 rows)
-- Ensure the IS_NULL qual is reduced to constant-FALSE, since a) it's on a NOT
-- NULL column, and b) its Var is not nullable by any outer joins
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NULL AND t2.b = 1;- QUERY PLAN ----------------------------------------------------+ LEFT JOIN pred_tab t2 ON t1.a IS NULL;+ QUERY PLAN +--------------------------------
Nested Loop Left Join
+ Join Filter: false
-> Seq Scan on pred_tab t1
- -> Materialize- -> Nested Loop Left Join- Join Filter: (false AND (t2.b = 1))- -> Seq Scan on pred_tab t2- -> Result- One-Time Filter: false-(8 rows)+ -> Result+ One-Time Filter: false+(5 rows)
-- Ensure the IS_NULL qual is not reduced to constant-FALSE when the column is
-- nullable by an outer join
@@ -172,55 +167,50 @@ SELECT * FROM pred_tab t1
-- Ensure the OR clause is ignored when an OR branch is provably always true
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL OR t2.b = 1;- QUERY PLAN --------------------------------------------------+ LEFT JOIN pred_tab t2 ON t1.a IS NOT NULL OR t2.b = 1;+ QUERY PLAN +-------------------------------------
Nested Loop Left Join
-> Seq Scan on pred_tab t1
-> Materialize
- -> Nested Loop Left Join- -> Seq Scan on pred_tab t2- -> Materialize- -> Seq Scan on pred_tab t3-(7 rows)+ -> Seq Scan on pred_tab t2+(4 rows)
-- Ensure the NullTest is not ignored when the column is nullable by an outer
-- join
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON t1.a = 1+ FULL JOIN pred_tab t2 ON t1.a = t2.a
LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL OR t2.b = 1;
QUERY PLAN
---------------------------------------------------
Nested Loop Left Join
Join Filter: ((t2.a IS NOT NULL) OR (t2.b = 1))
- -> Nested Loop Left Join- Join Filter: (t1.a = 1)- -> Seq Scan on pred_tab t1- -> Materialize+ -> Merge Full Join+ Merge Cond: (t1.a = t2.a)+ -> Sort+ Sort Key: t1.a+ -> Seq Scan on pred_tab t1+ -> Sort+ Sort Key: t2.a
-> Seq Scan on pred_tab t2
-> Materialize
-> Seq Scan on pred_tab t3
-(9 rows)+(12 rows)
-- Ensure the OR clause is reduced to constant-FALSE when all OR branches are
-- provably false
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON (t2.a IS NULL OR t2.c IS NULL) AND t2.b = 1;- QUERY PLAN ----------------------------------------------------+ LEFT JOIN pred_tab t2 ON (t1.a IS NULL OR t1.c IS NULL);+ QUERY PLAN +--------------------------------
Nested Loop Left Join
+ Join Filter: false
-> Seq Scan on pred_tab t1
- -> Materialize- -> Nested Loop Left Join- Join Filter: (false AND (t2.b = 1))- -> Seq Scan on pred_tab t2- -> Result- One-Time Filter: false-(8 rows)+ -> Result+ One-Time Filter: false+(5 rows)
-- Ensure the OR clause is not reduced to constant-FALSE when a column is
-- made nullable from an outer join
@@ -290,31 +280,84 @@ SELECT * FROM pred_parent WHERE a IS NULL;
(2 rows)
DROP TABLE pred_parent, pred_child;
--- Validate the additional constant-FALSE qual does not cause inconsistent--- RestrictInfo serial numbers-CREATE TABLE pred_tab (a int PRIMARY KEY, b int);-INSERT INTO pred_tab SELECT i, i FROM generate_series(1, 10)i;+-- Validate we do not reduce a clone clause to a constant true or false+CREATE TABLE pred_tab (a int, b int);+CREATE TABLE pred_tab_notnull (a int, b int NOT NULL);+INSERT INTO pred_tab VALUES (1, 1);+INSERT INTO pred_tab VALUES (2, 2);+INSERT INTO pred_tab_notnull VALUES (2, 2);+INSERT INTO pred_tab_notnull VALUES (3, 3);
ANALYZE pred_tab;
+ANALYZE pred_tab_notnull;+-- Ensure the IS_NOT_NULL qual is not reduced to constant true and removed
EXPLAIN (COSTS OFF)
-SELECT 1 FROM pred_tab t1- LEFT JOIN- (pred_tab t2 LEFT JOIN pred_tab t3 ON t2.a = t3.a) ON TRUE- LEFT JOIN pred_tab t4 ON t1.a IS NULL AND t1.b = 1- RIGHT JOIN pred_tab t5 ON t1.b = t5.b;- QUERY PLAN ----------------------------------------------------- Hash Right Join- Hash Cond: (t1.b = t5.b)- -> Nested Loop Left Join+SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NOT NULL;+ QUERY PLAN +---------------------------------------------------------------+ Nested Loop Left Join+ -> Seq Scan on pred_tab t1+ -> Materialize
-> Nested Loop Left Join
- Join Filter: (false AND (t1.b = 1))- -> Seq Scan on pred_tab t1- -> Result- One-Time Filter: false- -> Materialize- -> Seq Scan on pred_tab t2- -> Hash- -> Seq Scan on pred_tab t5+ Join Filter: (t3.b IS NOT NULL)+ -> Nested Loop Left Join+ Join Filter: (t2.a = t3.a)+ -> Seq Scan on pred_tab t2+ -> Materialize+ -> Seq Scan on pred_tab_notnull t3+ -> Materialize+ -> Seq Scan on pred_tab t4
(12 rows)
+SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NOT NULL;+ a | b | a | b | a | b | a | b +---+---+---+---+---+---+---+---+ 1 | 1 | 1 | 1 | | | | + 1 | 1 | 2 | 2 | 2 | 2 | 1 | 1+ 1 | 1 | 2 | 2 | 2 | 2 | 2 | 2+ 2 | 2 | 1 | 1 | | | | + 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1+ 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2+(6 rows)++-- Ensure the IS_NULL qual is not reduced to constant false+EXPLAIN (COSTS OFF)+SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NULL AND t3.a IS NOT NULL;+ QUERY PLAN +--------------------------------------------------------------------+ Nested Loop Left Join+ -> Seq Scan on pred_tab t1+ -> Materialize+ -> Nested Loop Left Join+ Join Filter: ((t3.b IS NULL) AND (t3.a IS NOT NULL))+ -> Nested Loop Left Join+ Join Filter: (t2.a = t3.a)+ -> Seq Scan on pred_tab t2+ -> Materialize+ -> Seq Scan on pred_tab_notnull t3+ -> Materialize+ -> Seq Scan on pred_tab t4+(12 rows)++SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NULL AND t3.a IS NOT NULL;+ a | b | a | b | a | b | a | b +---+---+---+---+---+---+---+---+ 1 | 1 | 1 | 1 | | | | + 1 | 1 | 2 | 2 | 2 | 2 | | + 2 | 2 | 1 | 1 | | | | + 2 | 2 | 2 | 2 | 2 | 2 | | +(4 rows)+
DROP TABLE pred_tab;
+DROP TABLE pred_tab_notnull;diff --git a/src/test/regress/sql/predicate.sql b/src/test/regress/sql/predicate.sqlindex 661013ff7e4..9dcb81b1bc5 100644--- a/src/test/regress/sql/predicate.sql+++ b/src/test/regress/sql/predicate.sql@@ -64,22 +64,20 @@ SELECT * FROM pred_tab t WHERE t.b IS NULL OR t.c IS NULL;
-- and b) its Var is not nullable by any outer joins
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL;+ LEFT JOIN pred_tab t2 ON t1.a IS NOT NULL;
-- Ensure the IS_NOT_NULL qual is not ignored when columns are made nullable
-- by an outer join
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON t1.a = 1+ FULL JOIN pred_tab t2 ON t1.a = t2.a
LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL;
-- Ensure the IS_NULL qual is reduced to constant-FALSE, since a) it's on a NOT
-- NULL column, and b) its Var is not nullable by any outer joins
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NULL AND t2.b = 1;+ LEFT JOIN pred_tab t2 ON t1.a IS NULL;
-- Ensure the IS_NULL qual is not reduced to constant-FALSE when the column is
-- nullable by an outer join
@@ -95,22 +93,20 @@ SELECT * FROM pred_tab t1
-- Ensure the OR clause is ignored when an OR branch is provably always true
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL OR t2.b = 1;+ LEFT JOIN pred_tab t2 ON t1.a IS NOT NULL OR t2.b = 1;
-- Ensure the NullTest is not ignored when the column is nullable by an outer
-- join
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON t1.a = 1+ FULL JOIN pred_tab t2 ON t1.a = t2.a
LEFT JOIN pred_tab t3 ON t2.a IS NOT NULL OR t2.b = 1;
-- Ensure the OR clause is reduced to constant-FALSE when all OR branches are
-- provably false
EXPLAIN (COSTS OFF)
SELECT * FROM pred_tab t1
- LEFT JOIN pred_tab t2 ON TRUE- LEFT JOIN pred_tab t3 ON (t2.a IS NULL OR t2.c IS NULL) AND t2.b = 1;+ LEFT JOIN pred_tab t2 ON (t1.a IS NULL OR t1.c IS NULL);
-- Ensure the OR clause is not reduced to constant-FALSE when a column is
-- made nullable from an outer join
@@ -148,17 +144,42 @@ SELECT * FROM pred_parent WHERE a IS NULL;
DROP TABLE pred_parent, pred_child;
--- Validate the additional constant-FALSE qual does not cause inconsistent--- RestrictInfo serial numbers-CREATE TABLE pred_tab (a int PRIMARY KEY, b int);-INSERT INTO pred_tab SELECT i, i FROM generate_series(1, 10)i;+-- Validate we do not reduce a clone clause to a constant true or false+CREATE TABLE pred_tab (a int, b int);+CREATE TABLE pred_tab_notnull (a int, b int NOT NULL);++INSERT INTO pred_tab VALUES (1, 1);+INSERT INTO pred_tab VALUES (2, 2);++INSERT INTO pred_tab_notnull VALUES (2, 2);+INSERT INTO pred_tab_notnull VALUES (3, 3);+
ANALYZE pred_tab;
+ANALYZE pred_tab_notnull;+-- Ensure the IS_NOT_NULL qual is not reduced to constant true and removed
EXPLAIN (COSTS OFF)
-SELECT 1 FROM pred_tab t1- LEFT JOIN- (pred_tab t2 LEFT JOIN pred_tab t3 ON t2.a = t3.a) ON TRUE- LEFT JOIN pred_tab t4 ON t1.a IS NULL AND t1.b = 1- RIGHT JOIN pred_tab t5 ON t1.b = t5.b;+SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NOT NULL;++SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NOT NULL;++-- Ensure the IS_NULL qual is not reduced to constant false+EXPLAIN (COSTS OFF)+SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NULL AND t3.a IS NOT NULL;++SELECT * FROM pred_tab t1+ LEFT JOIN pred_tab t2 ON TRUE+ LEFT JOIN pred_tab_notnull t3 ON t2.a = t3.a+ LEFT JOIN pred_tab t4 ON t3.b IS NULL AND t3.a IS NOT NULL;
DROP TABLE pred_tab;
+DROP TABLE pred_tab_notnull;--
2.43.0
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-bugs@postgresql.org
Cc: guofenglinux@gmail.com, tgl@sss.pgh.pa.us, bruce@momjian.us, dgrowleyml@gmail.com, cruz@rentec.com, pford@rentec.com, agarcia@rentec.com
Subject: Re: Query result differences between PostgreSQL 17 vs 16
In-Reply-To: <CAMbWs4_4HBfqs+AjrtNOeqZYwKTJps2jANzdCbAfQSCd-CdeGA@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox