@@ -1459,6 +1459,10 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1459
1459
int varno ;
1460
1460
Relids clause_varnos ;
1461
1461
Relids upper_varnos ;
1462
+ ListCell * lc ;
1463
+ List * newWhere = NIL ;
1464
+ List * all_clauses = NIL ;
1465
+ bool upper_reference_exists = false;
1462
1466
1463
1467
Assert (sublink -> subLinkType == EXISTS_SUBLINK );
1464
1468
@@ -1488,32 +1492,71 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1488
1492
if (!simplify_EXISTS_query (root , subselect ))
1489
1493
return NULL ;
1490
1494
1491
- /*
1492
- * Separate out the WHERE clause. (We could theoretically also remove
1493
- * top-level plain JOIN/ON clauses, but it's probably not worth the
1494
- * trouble.)
1495
- */
1496
- whereClause = subselect -> jointree -> quals ;
1495
+ if (subselect -> jointree -> quals )
1496
+ all_clauses = lappend (all_clauses , subselect -> jointree -> quals );
1497
+
1497
1498
subselect -> jointree -> quals = NULL ;
1498
1499
1499
- /*
1500
- * The rest of the sub-select must not refer to any Vars of the parent
1501
- * query. (Vars of higher levels should be okay, though.)
1502
- */
1503
- if (contain_vars_of_level ((Node * ) subselect , 1 ))
1504
- return NULL ;
1500
+ /* Gather all clauses in main list for the further consideration */
1501
+ all_clauses = list_concat (all_clauses , subselect -> jointree -> fromlist );
1505
1502
1506
1503
/*
1507
- * On the other hand, the WHERE clause must contain some Vars of the
1508
- * parent query, else it's not gonna be a join.
1504
+ * We will able to remove top-level plain JOIN/ON clauses if they are not outer join.
1509
1505
*/
1510
- if (!contain_vars_of_level (whereClause , 1 ))
1511
- return NULL ;
1506
+ foreach (lc , all_clauses )
1507
+ {
1508
+ Node * je = ((Node * ) lfirst (lc ));
1509
+
1510
+ whereClause = copyObject (je );
1511
+
1512
+ if (IsA (whereClause , RangeTblRef ))
1513
+ continue ;
1514
+
1515
+ if (IsA (whereClause , JoinExpr ))
1516
+ {
1517
+ if (((JoinExpr * ) whereClause )-> jointype != JOIN_INNER )
1518
+ {
1519
+ /*
1520
+ * Clauses must not refer to any Vars of the parent
1521
+ * query. (Vars of higher levels should be okay, though.)
1522
+ */
1523
+ if (contain_vars_of_level (whereClause , 1 ))
1524
+ return NULL ;
1525
+ else
1526
+ continue ;
1527
+ }
1528
+ else if (((JoinExpr * ) whereClause )-> quals != NULL )
1529
+ whereClause = ((JoinExpr * ) whereClause )-> quals ;
1530
+ }
1531
+
1532
+ /*
1533
+ * We don't risk optimizing if the WHERE clause is volatile, either.
1534
+ */
1535
+ if (contain_volatile_functions (whereClause ))
1536
+ return NULL ;
1537
+
1538
+ /*
1539
+ * Clean up the WHERE clause by doing const-simplification etc on it.
1540
+ */
1541
+ whereClause = eval_const_expressions (root , whereClause );
1542
+ whereClause = (Node * ) canonicalize_qual ((Expr * ) whereClause , false);
1543
+
1544
+ if (!IsA (whereClause , JoinExpr ))
1545
+ newWhere = lappend (newWhere , whereClause );
1546
+ else
1547
+ return NULL ;
1548
+
1549
+ if (contain_vars_of_level ((Node * ) whereClause , 1 ))
1550
+ upper_reference_exists = true;
1551
+ }
1552
+
1553
+ list_free (all_clauses );
1512
1554
1513
1555
/*
1514
- * We don't risk optimizing if the WHERE clause is volatile, either.
1556
+ * There are no WHERE clause containing some Vars of the
1557
+ * parent query, so it's not gonna be a join.
1515
1558
*/
1516
- if ( contain_volatile_functions ( whereClause ) )
1559
+ if (! upper_reference_exists )
1517
1560
return NULL ;
1518
1561
1519
1562
/*
@@ -1567,23 +1610,24 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1567
1610
*/
1568
1611
rtoffset = list_length (parse -> rtable );
1569
1612
OffsetVarNodes ((Node * ) subselect , rtoffset , 0 );
1570
- OffsetVarNodes (whereClause , rtoffset , 0 );
1571
1613
1572
1614
/*
1573
1615
* Upper-level vars in subquery will now be one level closer to their
1574
1616
* parent than before; in particular, anything that had been level 1
1575
1617
* becomes level zero.
1576
1618
*/
1577
1619
IncrementVarSublevelsUp ((Node * ) subselect , -1 , 1 );
1578
- IncrementVarSublevelsUp (whereClause , -1 , 1 );
1620
+
1621
+ OffsetVarNodes ((Node * ) newWhere , rtoffset , 0 );
1622
+ IncrementVarSublevelsUp ((Node * ) newWhere , -1 , 1 );
1579
1623
1580
1624
/*
1581
1625
* Now that the WHERE clause is adjusted to match the parent query
1582
1626
* environment, we can easily identify all the level-zero rels it uses.
1583
1627
* The ones <= rtoffset belong to the upper query; the ones > rtoffset do
1584
1628
* not.
1585
1629
*/
1586
- clause_varnos = pull_varnos (root , whereClause );
1630
+ clause_varnos = pull_varnos (root , ( Node * ) newWhere );
1587
1631
upper_varnos = NULL ;
1588
1632
varno = -1 ;
1589
1633
while ((varno = bms_next_member (clause_varnos , varno )) >= 0 )
@@ -1601,6 +1645,31 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1601
1645
if (!bms_is_subset (upper_varnos , available_rels ))
1602
1646
return NULL ;
1603
1647
1648
+ /*
1649
+ * In case of a successful attempt, replaces it with the correct condition.
1650
+ * We were sure that inner relations are independent, so we confidently
1651
+ * can replace their join condition on true.
1652
+ */
1653
+ foreach (lc , subselect -> jointree -> fromlist )
1654
+ {
1655
+ Node * node = lfirst (lc );
1656
+
1657
+ if (IsA (node , RangeTblRef ))
1658
+ continue ;
1659
+
1660
+ if ((IsA (node , JoinExpr ) && ((JoinExpr * )node )-> jointype != JOIN_INNER ))
1661
+ continue ;
1662
+
1663
+ if (IsA (node , JoinExpr ) && ((JoinExpr * ) node )-> quals != NULL )
1664
+ ((JoinExpr * ) node )-> quals = (Node * ) makeConst (BOOLOID ,
1665
+ -1 ,
1666
+ InvalidOid ,
1667
+ sizeof (bool ),
1668
+ (Datum ) 1 ,
1669
+ false,
1670
+ true);
1671
+ }
1672
+
1604
1673
/*
1605
1674
* Now we can attach the modified subquery rtable to the parent. This also
1606
1675
* adds subquery's RTEPermissionInfos into the upper query.
@@ -1622,7 +1691,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1622
1691
result -> rarg = (Node * ) subselect -> jointree ;
1623
1692
result -> usingClause = NIL ;
1624
1693
result -> join_using_alias = NULL ;
1625
- result -> quals = whereClause ;
1694
+ result -> quals = ( Node * ) make_ands_explicit ( newWhere ) ;
1626
1695
result -> alias = NULL ;
1627
1696
result -> rtindex = 0 ; /* we don't need an RTE for it */
1628
1697
0 commit comments