summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorRichard Guo <rguo@postgresql.org>2025-12-29 11:40:45 +0900
committerRichard Guo <rguo@postgresql.org>2025-12-29 11:40:45 +0900
commit559f9e90dbbd5d72b1da802703317913280c5080 (patch)
tree91c17573fd6caed9e11011b9773fba7d21bb8829 /src/test
parentad66f705fa6796b40311a8210e9f37144df02ef5 (diff)
Ignore PlaceHolderVars when looking up statistics
When looking up statistical data about an expression, we failed to look through PlaceHolderVar nodes, treating them as opaque. This could prevent us from matching an expression to base columns, index expressions, or extended statistics, as examine_variable() relies on strict structural matching. As a result, queries involving PlaceHolderVar nodes often fell back to default selectivity estimates, potentially leading to poor plan choices. This patch updates examine_variable() to strip PlaceHolderVars before analysis. This is safe during estimation because PlaceHolderVars are transparent for the purpose of statistics lookup: they do not alter the value distribution of the underlying expression. To minimize performance overhead on this hot path, a lightweight walker first checks for the presence of PlaceHolderVars. The more expensive mutator is invoked only when necessary. There is one ensuing plan change in the regression tests, which is expected and demonstrates the fix: the rowcount estimate becomes much more accurate with this patch. Back-patch to v18. Although this issue exists before that, changes in this version made it common enough to notice. Given the lack of field reports for older versions, I am not back-patching further. Reported-by: Haowu Ge <gehaowu@bitmoe.com> Author: Richard Guo <guofenglinux@gmail.com> Discussion: https://postgr.es/m/62af586c-c270-44f3-9c5e-02c81d537e3d.gehaowu@bitmoe.com Backpatch-through: 18
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/join.out27
-rw-r--r--src/test/regress/sql/join.sql10
2 files changed, 35 insertions, 2 deletions
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index edde9e99893..1416f2943bd 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -6877,10 +6877,10 @@ where ss.a = ss.phv and f1 = 0;
QUERY PLAN
------------------------------------
Nested Loop
- -> Seq Scan on int4_tbl
- Filter: (f1 = 0)
-> Seq Scan on parttbl1 parttbl
Filter: (a = 12)
+ -> Seq Scan on int4_tbl
+ Filter: (f1 = 0)
(5 rows)
select * from
@@ -9879,6 +9879,29 @@ GROUP BY s.c1, s.c2;
(7 rows)
DROP TABLE group_tbl;
+-- Test that we ignore PlaceHolderVars when looking up statistics
+EXPLAIN (COSTS OFF)
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+ QUERY PLAN
+--------------------------------------------------
+ Nested Loop
+ -> Seq Scan on tenk1 t2
+ Filter: (unique1 = 42)
+ -> Index Scan using tenk1_unique2 on tenk1 t1
+ Index Cond: (unique2 = t2.unique2)
+ Filter: (unique1 < 100)
+(6 rows)
+
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+ unique1
+---------
+ 42
+(1 row)
+
--
-- Test for a nested loop join involving index scan, transforming OR-clauses
-- to SAOP.
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 7ec84f3b143..b91fb7574df 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -3764,6 +3764,16 @@ GROUP BY s.c1, s.c2;
DROP TABLE group_tbl;
+-- Test that we ignore PlaceHolderVars when looking up statistics
+EXPLAIN (COSTS OFF)
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+
--
-- Test for a nested loop join involving index scan, transforming OR-clauses
-- to SAOP.