From a77855103cc40b4f5d1669006c8633fda53c37db Mon Sep 17 00:00:00 2001
From: Alexander Pyhalov
Date: Tue, 26 Dec 2023 10:07:13 +0300
Subject: [PATCH 4/6] Compare converted whole row vars in
search_indexed_tlist_for_non_var() correctly and fix test results
---
src/backend/nodes/nodeFuncs.c | 49 +++++++++++++
src/backend/optimizer/plan/setrefs.c | 2 +-
src/backend/optimizer/util/tlist.c | 23 ++++++
src/include/nodes/nodeFuncs.h | 1 +
src/include/optimizer/tlist.h | 1 +
.../regress/expected/partition_aggregate.out | 39 ++++++----
src/test/regress/expected/partition_join.out | 72 +++++++++++--------
src/test/regress/sql/partition_aggregate.sql | 2 +-
src/test/regress/sql/partition_join.sql | 3 +-
9 files changed, 144 insertions(+), 48 deletions(-)
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 4ce0230aad5..41e2acaf1bf 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -4825,3 +4825,52 @@ is_converted_whole_row_reference(Node *node)
return false;
}
+
+/*
+ * is_equal_converted_whole_row_references
+ * Determine if both nodes are equivalent ConvertRowtypeExprs
+ * over the same var.
+ * It differs from equal(), because we ignore varnullingrels.
+ */
+bool
+is_equal_converted_whole_row_references(Node *node1, Node *node2)
+{
+ ConvertRowtypeExpr *convexpr1;
+ ConvertRowtypeExpr *convexpr2;
+
+ if (!node1 || !IsA(node1, ConvertRowtypeExpr))
+ return false;
+
+ if (!node2 || !IsA(node2, ConvertRowtypeExpr))
+ return false;
+
+ convexpr1 = castNode(ConvertRowtypeExpr, node1);
+ convexpr2 = castNode(ConvertRowtypeExpr, node2);
+
+ while (convexpr1->convertformat == COERCE_IMPLICIT_CAST &&
+ convexpr2->convertformat == COERCE_IMPLICIT_CAST &&
+ convexpr1->resulttype == convexpr2->resulttype &&
+ IsA(convexpr1->arg, ConvertRowtypeExpr) &&
+ IsA(convexpr2->arg, ConvertRowtypeExpr))
+ {
+ convexpr1 = castNode(ConvertRowtypeExpr, convexpr1->arg);
+ convexpr2 = castNode(ConvertRowtypeExpr, convexpr2->arg);
+ }
+
+ if (IsA(convexpr1->arg, Var) && IsA(convexpr2->arg, Var))
+ {
+ Var *var1 = castNode(Var, convexpr1->arg);
+ Var *var2 = castNode(Var, convexpr2->arg);
+
+ if ((var1->varno == var2->varno) &&
+ (var1->varattno == var2->varattno) &&
+ (var1->varlevelsup == var2->varlevelsup) &&
+ (var1->vartype == var2->vartype))
+ {
+ /* TODO: Can we state that both varattnos is 0? */
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 09314fac672..82e8872b4a9 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -2924,7 +2924,7 @@ search_indexed_tlist_for_non_var(Expr *node,
if (IsA(node, Const))
return NULL;
- tle = tlist_member(node, itlist->tlist);
+ tle = tlist_member_match_converted_whole_row(node, itlist->tlist);
if (tle)
{
/* Found a matching subplan output expression */
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 7ef7f34d8b5..f3157f0f649 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -119,6 +119,29 @@ tlist_member_match_var(Var *var, List *targetlist)
return NULL;
}
+/*
+ * tlist_member_match_converted_whole_row
+ * tlist_member() variant, which compares whole var references
+ * based on their varno/varattno
+ */
+TargetEntry *
+tlist_member_match_converted_whole_row(Expr *node, List *targetlist)
+{
+ ListCell *temp;
+
+ foreach(temp, targetlist)
+ {
+ TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
+
+ if (equal(node, tlentry->expr))
+ return tlentry;
+
+ if (is_equal_converted_whole_row_references((Node *)node, (Node *)tlentry->expr))
+ return tlentry;
+ }
+ return NULL;
+}
+
/*
* add_to_flat_tlist
* Add more items to a flattened tlist (if they're not already in it)
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index 8d30d6cbac5..cda3fff315d 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -220,4 +220,5 @@ extern bool planstate_tree_walker_impl(struct PlanState *planstate,
void *context);
extern bool is_converted_whole_row_reference(Node *node);
+extern bool is_equal_converted_whole_row_references(Node *node1, Node *node2);
#endif /* NODEFUNCS_H */
diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h
index 15f8f4a4b00..9ab6adc01b8 100644
--- a/src/include/optimizer/tlist.h
+++ b/src/include/optimizer/tlist.h
@@ -18,6 +18,7 @@
extern TargetEntry *tlist_member(Expr *node, List *targetlist);
+extern TargetEntry *tlist_member_match_converted_whole_row(Expr *node, List *targetlist);
extern List *add_to_flat_tlist(List *tlist, List *exprs);
diff --git a/src/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out
index 5f2c0cf5786..ba9245e4011 100644
--- a/src/test/regress/expected/partition_aggregate.out
+++ b/src/test/regress/expected/partition_aggregate.out
@@ -453,27 +453,36 @@ SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2
24 | 900 | 100
(5 rows)
--- Check with whole-row reference; partitionwise aggregation does not apply
+-- Check with whole-row reference
EXPLAIN (COSTS OFF)
SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
QUERY PLAN
-------------------------------------------------------------
Sort
Sort Key: t1.x, (sum(t1.y)), (count(((t1.*)::pagg_tab1)))
- -> HashAggregate
- Group Key: t1.x
- -> Hash Join
- Hash Cond: (t1.x = t2.y)
- -> Append
- -> Seq Scan on pagg_tab1_p1 t1_1
- -> Seq Scan on pagg_tab1_p2 t1_2
- -> Seq Scan on pagg_tab1_p3 t1_3
- -> Hash
- -> Append
- -> Seq Scan on pagg_tab2_p1 t2_1
- -> Seq Scan on pagg_tab2_p2 t2_2
- -> Seq Scan on pagg_tab2_p3 t2_3
-(15 rows)
+ -> Append
+ -> HashAggregate
+ Group Key: t1.x
+ -> Hash Join
+ Hash Cond: (t1.x = t2.y)
+ -> Seq Scan on pagg_tab1_p1 t1
+ -> Hash
+ -> Seq Scan on pagg_tab2_p1 t2
+ -> HashAggregate
+ Group Key: t1_1.x
+ -> Hash Join
+ Hash Cond: (t1_1.x = t2_1.y)
+ -> Seq Scan on pagg_tab1_p2 t1_1
+ -> Hash
+ -> Seq Scan on pagg_tab2_p2 t2_1
+ -> HashAggregate
+ Group Key: t1_2.x
+ -> Hash Join
+ Hash Cond: (t2_2.y = t1_2.x)
+ -> Seq Scan on pagg_tab2_p3 t2_2
+ -> Hash
+ -> Seq Scan on pagg_tab1_p3 t1_2
+(24 rows)
SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
x | sum | count
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 53591a4f2d5..c4500290694 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -108,28 +108,33 @@ SELECT COUNT(*) FROM prt1 t1
300
(1 row)
--- left outer join, with whole-row reference; partitionwise join does not apply
+-- left outer join, with whole-row reference
EXPLAIN (COSTS OFF)
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
--------------------------------------------------
Sort
Sort Key: t1.a, t2.b
- -> Hash Right Join
- Hash Cond: (t2.b = t1.a)
- -> Append
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p1 t2_1
- -> Seq Scan on prt2_p2 t2_2
- -> Seq Scan on prt2_p3 t2_3
- -> Hash
- -> Append
+ -> Hash
-> Seq Scan on prt1_p1 t1_1
Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_p2 t2_2
+ -> Hash
-> Seq Scan on prt1_p2 t1_2
Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
-> Seq Scan on prt1_p3 t1_3
Filter: (b = 0)
-(16 rows)
+(21 rows)
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
t1 | t2
@@ -1347,28 +1352,37 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
(9 rows)
-- merge join when expression with whole-row reference needs to be sorted;
--- partitionwise join does not apply
EXPLAIN (COSTS OFF)
SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
- QUERY PLAN
------------------------------------------------------------------------------------------
- Merge Join
- Merge Cond: ((t1.a = t2.b) AND (((((t1.*)::prt1))::text) = ((((t2.*)::prt2))::text)))
- -> Sort
- Sort Key: t1.a, ((((t1.*)::prt1))::text)
- -> Result
- -> Append
- -> Seq Scan on prt1_p1 t1_1
- -> Seq Scan on prt1_p2 t1_2
- -> Seq Scan on prt1_p3 t1_3
- -> Sort
- Sort Key: t2.b, ((((t2.*)::prt2))::text)
- -> Result
- -> Append
- -> Seq Scan on prt2_p1 t2_1
- -> Seq Scan on prt2_p2 t2_2
- -> Seq Scan on prt2_p3 t2_3
-(16 rows)
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Merge Append
+ Sort Key: t1.a
+ -> Merge Join
+ Merge Cond: ((t1_1.a = t2_1.b) AND (((t1_1.*)::text) = ((t2_1.*)::text)))
+ -> Sort
+ Sort Key: t1_1.a, ((t1_1.*)::text)
+ -> Seq Scan on prt1_p1 t1_1
+ -> Sort
+ Sort Key: t2_1.b, ((t2_1.*)::text)
+ -> Seq Scan on prt2_p1 t2_1
+ -> Merge Join
+ Merge Cond: ((t1_2.a = t2_2.b) AND (((t1_2.*)::text) = ((t2_2.*)::text)))
+ -> Sort
+ Sort Key: t1_2.a, ((t1_2.*)::text)
+ -> Seq Scan on prt1_p2 t1_2
+ -> Sort
+ Sort Key: t2_2.b, ((t2_2.*)::text)
+ -> Seq Scan on prt2_p2 t2_2
+ -> Merge Join
+ Merge Cond: ((t1_3.a = t2_3.b) AND (((t1_3.*)::text) = ((t2_3.*)::text)))
+ -> Sort
+ Sort Key: t1_3.a, ((t1_3.*)::text)
+ -> Seq Scan on prt1_p3 t1_3
+ -> Sort
+ Sort Key: t2_3.b, ((t2_3.*)::text)
+ -> Seq Scan on prt2_p3 t2_3
+(26 rows)
SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
a | b
diff --git a/src/test/regress/sql/partition_aggregate.sql b/src/test/regress/sql/partition_aggregate.sql
index ab070fee244..a763228e6c0 100644
--- a/src/test/regress/sql/partition_aggregate.sql
+++ b/src/test/regress/sql/partition_aggregate.sql
@@ -116,7 +116,7 @@ EXPLAIN (COSTS OFF)
SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
--- Check with whole-row reference; partitionwise aggregation does not apply
+-- Check with whole-row reference
EXPLAIN (COSTS OFF)
SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3;
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index 128ce8376e6..87135dc84d8 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -43,7 +43,7 @@ SELECT COUNT(*) FROM prt1 t1
LEFT JOIN prt1 t2 ON t1.a = t2.a
LEFT JOIN prt1 t3 ON t2.a = t3.a;
--- left outer join, with whole-row reference; partitionwise join does not apply
+-- left outer join, with whole-row reference
EXPLAIN (COSTS OFF)
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
@@ -229,7 +229,6 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
-- merge join when expression with whole-row reference needs to be sorted;
--- partitionwise join does not apply
EXPLAIN (COSTS OFF)
SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
--
2.34.1