@@ -180,11 +180,15 @@ static void appendConditions(List *exprs, deparse_expr_cxt *context);
180
180
static void deparseFromExprForRel (StringInfo buf , PlannerInfo * root ,
181
181
RelOptInfo * foreignrel , bool use_alias ,
182
182
Index ignore_rel , List * * ignore_conds ,
183
+ List * * additional_conds ,
183
184
List * * params_list );
185
+ static void appendWhereClause (List * exprs , List * additional_conds ,
186
+ deparse_expr_cxt * context );
184
187
static void deparseFromExpr (List * quals , deparse_expr_cxt * context );
185
188
static void deparseRangeTblRef (StringInfo buf , PlannerInfo * root ,
186
189
RelOptInfo * foreignrel , bool make_subquery ,
187
- Index ignore_rel , List * * ignore_conds , List * * params_list );
190
+ Index ignore_rel , List * * ignore_conds ,
191
+ List * * additional_conds , List * * params_list );
188
192
static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
189
193
static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
190
194
static void appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
@@ -1370,6 +1374,7 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context)
1370
1374
{
1371
1375
StringInfo buf = context -> buf ;
1372
1376
RelOptInfo * scanrel = context -> scanrel ;
1377
+ List * additional_conds = NIL ;
1373
1378
1374
1379
/* For upper relations, scanrel must be either a joinrel or a baserel */
1375
1380
Assert (!IS_UPPER_REL (context -> foreignrel ) ||
@@ -1379,14 +1384,11 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context)
1379
1384
appendStringInfoString (buf , " FROM " );
1380
1385
deparseFromExprForRel (buf , context -> root , scanrel ,
1381
1386
(bms_membership (scanrel -> relids ) == BMS_MULTIPLE ),
1382
- (Index ) 0 , NULL , context -> params_list );
1383
-
1384
- /* Construct WHERE clause */
1385
- if (quals != NIL )
1386
- {
1387
- appendStringInfoString (buf , " WHERE " );
1388
- appendConditions (quals , context );
1389
- }
1387
+ (Index ) 0 , NULL , & additional_conds ,
1388
+ context -> params_list );
1389
+ appendWhereClause (quals , additional_conds , context );
1390
+ if (additional_conds != NIL )
1391
+ list_free_deep (additional_conds );
1390
1392
}
1391
1393
1392
1394
/*
@@ -1598,6 +1600,42 @@ appendConditions(List *exprs, deparse_expr_cxt *context)
1598
1600
reset_transmission_modes (nestlevel );
1599
1601
}
1600
1602
1603
+ /*
1604
+ * Append WHERE clause, containing conditions from exprs and additional_conds,
1605
+ * to context->buf.
1606
+ */
1607
+ static void
1608
+ appendWhereClause (List * exprs , List * additional_conds , deparse_expr_cxt * context )
1609
+ {
1610
+ StringInfo buf = context -> buf ;
1611
+ bool need_and = false;
1612
+ ListCell * lc ;
1613
+
1614
+ if (exprs != NIL || additional_conds != NIL )
1615
+ appendStringInfoString (buf , " WHERE " );
1616
+
1617
+ /*
1618
+ * If there are some filters, append them.
1619
+ */
1620
+ if (exprs != NIL )
1621
+ {
1622
+ appendConditions (exprs , context );
1623
+ need_and = true;
1624
+ }
1625
+
1626
+ /*
1627
+ * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1628
+ * them.
1629
+ */
1630
+ foreach (lc , additional_conds )
1631
+ {
1632
+ if (need_and )
1633
+ appendStringInfoString (buf , " AND " );
1634
+ appendStringInfoString (buf , (char * ) lfirst (lc ));
1635
+ need_and = true;
1636
+ }
1637
+ }
1638
+
1601
1639
/* Output join name for given join type */
1602
1640
const char *
1603
1641
get_jointype_name (JoinType jointype )
@@ -1616,6 +1654,9 @@ get_jointype_name(JoinType jointype)
1616
1654
case JOIN_FULL :
1617
1655
return "FULL" ;
1618
1656
1657
+ case JOIN_SEMI :
1658
+ return "SEMI" ;
1659
+
1619
1660
default :
1620
1661
/* Shouldn't come here, but protect from buggy code. */
1621
1662
elog (ERROR , "unsupported join type %d" , jointype );
@@ -1712,11 +1753,14 @@ deparseSubqueryTargetList(deparse_expr_cxt *context)
1712
1753
* of DELETE; it deparses the join relation as if the relation never contained
1713
1754
* the target relation, and creates a List of conditions to be deparsed into
1714
1755
* the top-level WHERE clause, which is returned to *ignore_conds.
1756
+ *
1757
+ * 'additional_conds' is a pointer to a list of strings to be appended to
1758
+ * the WHERE clause, coming from lower-level SEMI-JOINs.
1715
1759
*/
1716
1760
static void
1717
1761
deparseFromExprForRel (StringInfo buf , PlannerInfo * root , RelOptInfo * foreignrel ,
1718
1762
bool use_alias , Index ignore_rel , List * * ignore_conds ,
1719
- List * * params_list )
1763
+ List * * additional_conds , List * * params_list )
1720
1764
{
1721
1765
PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) foreignrel -> fdw_private ;
1722
1766
@@ -1728,6 +1772,8 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1728
1772
RelOptInfo * innerrel = fpinfo -> innerrel ;
1729
1773
bool outerrel_is_target = false;
1730
1774
bool innerrel_is_target = false;
1775
+ List * additional_conds_i = NIL ;
1776
+ List * additional_conds_o = NIL ;
1731
1777
1732
1778
if (ignore_rel > 0 && bms_is_member (ignore_rel , foreignrel -> relids ))
1733
1779
{
@@ -1764,7 +1810,8 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1764
1810
initStringInfo (& join_sql_o );
1765
1811
deparseRangeTblRef (& join_sql_o , root , outerrel ,
1766
1812
fpinfo -> make_outerrel_subquery ,
1767
- ignore_rel , ignore_conds , params_list );
1813
+ ignore_rel , ignore_conds , & additional_conds_o ,
1814
+ params_list );
1768
1815
1769
1816
/*
1770
1817
* If inner relation is the target relation, skip deparsing it.
@@ -1780,6 +1827,12 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1780
1827
Assert (fpinfo -> jointype == JOIN_INNER );
1781
1828
Assert (fpinfo -> joinclauses == NIL );
1782
1829
appendBinaryStringInfo (buf , join_sql_o .data , join_sql_o .len );
1830
+ /* Pass EXISTS conditions to upper level */
1831
+ if (additional_conds_o != NIL )
1832
+ {
1833
+ Assert (* additional_conds == NIL );
1834
+ * additional_conds = additional_conds_o ;
1835
+ }
1783
1836
return ;
1784
1837
}
1785
1838
}
@@ -1790,7 +1843,54 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1790
1843
initStringInfo (& join_sql_i );
1791
1844
deparseRangeTblRef (& join_sql_i , root , innerrel ,
1792
1845
fpinfo -> make_innerrel_subquery ,
1793
- ignore_rel , ignore_conds , params_list );
1846
+ ignore_rel , ignore_conds , & additional_conds_i ,
1847
+ params_list );
1848
+
1849
+ /*
1850
+ * SEMI-JOIN is deparsed as the EXISTS subquery. It references
1851
+ * outer and inner relations, so it should be evaluated as the
1852
+ * condition in the upper-level WHERE clause. We deparse the
1853
+ * condition and pass it to upper level callers as an
1854
+ * additional_conds list. Upper level callers are responsible for
1855
+ * inserting conditions from the list where appropriate.
1856
+ */
1857
+ if (fpinfo -> jointype == JOIN_SEMI )
1858
+ {
1859
+ deparse_expr_cxt context ;
1860
+ StringInfoData str ;
1861
+
1862
+ /* Construct deparsed condition from this SEMI-JOIN */
1863
+ initStringInfo (& str );
1864
+ appendStringInfo (& str , "EXISTS (SELECT NULL FROM %s" ,
1865
+ join_sql_i .data );
1866
+
1867
+ context .buf = & str ;
1868
+ context .foreignrel = foreignrel ;
1869
+ context .scanrel = foreignrel ;
1870
+ context .root = root ;
1871
+ context .params_list = params_list ;
1872
+
1873
+ /*
1874
+ * Append SEMI-JOIN clauses and EXISTS conditions from lower
1875
+ * levels to the current EXISTS subquery
1876
+ */
1877
+ appendWhereClause (fpinfo -> joinclauses , additional_conds_i , & context );
1878
+
1879
+ /*
1880
+ * EXISTS conditions, coming from lower join levels, have just
1881
+ * been processed.
1882
+ */
1883
+ if (additional_conds_i != NIL )
1884
+ {
1885
+ list_free_deep (additional_conds_i );
1886
+ additional_conds_i = NIL ;
1887
+ }
1888
+
1889
+ /* Close parentheses for EXISTS subquery */
1890
+ appendStringInfo (& str , ")" );
1891
+
1892
+ * additional_conds = lappend (* additional_conds , str .data );
1893
+ }
1794
1894
1795
1895
/*
1796
1896
* If outer relation is the target relation, skip deparsing it.
@@ -1801,6 +1901,12 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1801
1901
Assert (fpinfo -> jointype == JOIN_INNER );
1802
1902
Assert (fpinfo -> joinclauses == NIL );
1803
1903
appendBinaryStringInfo (buf , join_sql_i .data , join_sql_i .len );
1904
+ /* Pass EXISTS conditions to the upper call */
1905
+ if (additional_conds_i != NIL )
1906
+ {
1907
+ Assert (* additional_conds == NIL );
1908
+ * additional_conds = additional_conds_i ;
1909
+ }
1804
1910
return ;
1805
1911
}
1806
1912
}
@@ -1809,33 +1915,65 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1809
1915
Assert (!outerrel_is_target && !innerrel_is_target );
1810
1916
1811
1917
/*
1812
- * For a join relation FROM clause entry is deparsed as
1813
- *
1814
- * ((outer relation) <join type> (inner relation) ON (joinclauses))
1918
+ * For semijoin FROM clause is deparsed as an outer relation. An inner
1919
+ * relation and join clauses are converted to EXISTS condition and
1920
+ * passed to the upper level.
1815
1921
*/
1816
- appendStringInfo (buf , "(%s %s JOIN %s ON " , join_sql_o .data ,
1817
- get_jointype_name (fpinfo -> jointype ), join_sql_i .data );
1818
-
1819
- /* Append join clause; (TRUE) if no join clause */
1820
- if (fpinfo -> joinclauses )
1922
+ if (fpinfo -> jointype == JOIN_SEMI )
1821
1923
{
1822
- deparse_expr_cxt context ;
1924
+ appendStringInfo (buf , "%s" , join_sql_o .data );
1925
+ }
1926
+ else
1927
+ {
1928
+ /*
1929
+ * For a join relation FROM clause, entry is deparsed as
1930
+ *
1931
+ * ((outer relation) <join type> (inner relation) ON
1932
+ * (joinclauses))
1933
+ */
1934
+ appendStringInfo (buf , "(%s %s JOIN %s ON " , join_sql_o .data ,
1935
+ get_jointype_name (fpinfo -> jointype ), join_sql_i .data );
1823
1936
1824
- context .buf = buf ;
1825
- context .foreignrel = foreignrel ;
1826
- context .scanrel = foreignrel ;
1827
- context .root = root ;
1828
- context .params_list = params_list ;
1937
+ /* Append join clause; (TRUE) if no join clause */
1938
+ if (fpinfo -> joinclauses )
1939
+ {
1940
+ deparse_expr_cxt context ;
1829
1941
1830
- appendStringInfoChar (buf , '(' );
1831
- appendConditions (fpinfo -> joinclauses , & context );
1942
+ context .buf = buf ;
1943
+ context .foreignrel = foreignrel ;
1944
+ context .scanrel = foreignrel ;
1945
+ context .root = root ;
1946
+ context .params_list = params_list ;
1947
+
1948
+ appendStringInfoChar (buf , '(' );
1949
+ appendConditions (fpinfo -> joinclauses , & context );
1950
+ appendStringInfoChar (buf , ')' );
1951
+ }
1952
+ else
1953
+ appendStringInfoString (buf , "(TRUE)" );
1954
+
1955
+ /* End the FROM clause entry. */
1832
1956
appendStringInfoChar (buf , ')' );
1833
1957
}
1834
- else
1835
- appendStringInfoString (buf , "(TRUE)" );
1836
1958
1837
- /* End the FROM clause entry. */
1838
- appendStringInfoChar (buf , ')' );
1959
+ /*
1960
+ * Construct additional_conds to be passed to the upper caller from
1961
+ * current level additional_conds and additional_conds, coming from
1962
+ * inner and outer rels.
1963
+ */
1964
+ if (additional_conds_o != NIL )
1965
+ {
1966
+ * additional_conds = list_concat (* additional_conds ,
1967
+ additional_conds_o );
1968
+ list_free (additional_conds_o );
1969
+ }
1970
+
1971
+ if (additional_conds_i != NIL )
1972
+ {
1973
+ * additional_conds = list_concat (* additional_conds ,
1974
+ additional_conds_i );
1975
+ list_free (additional_conds_i );
1976
+ }
1839
1977
}
1840
1978
else
1841
1979
{
@@ -1863,11 +2001,13 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1863
2001
1864
2002
/*
1865
2003
* Append FROM clause entry for the given relation into buf.
2004
+ * Conditions from lower-level SEMI-JOINs are appended to additional_conds
2005
+ * and should be added to upper level WHERE clause.
1866
2006
*/
1867
2007
static void
1868
2008
deparseRangeTblRef (StringInfo buf , PlannerInfo * root , RelOptInfo * foreignrel ,
1869
2009
bool make_subquery , Index ignore_rel , List * * ignore_conds ,
1870
- List * * params_list )
2010
+ List * * additional_conds , List * * params_list )
1871
2011
{
1872
2012
PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) foreignrel -> fdw_private ;
1873
2013
@@ -1925,7 +2065,8 @@ deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1925
2065
}
1926
2066
else
1927
2067
deparseFromExprForRel (buf , root , foreignrel , true, ignore_rel ,
1928
- ignore_conds , params_list );
2068
+ ignore_conds , additional_conds ,
2069
+ params_list );
1929
2070
}
1930
2071
1931
2072
/*
@@ -2148,6 +2289,7 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
2148
2289
RangeTblEntry * rte = planner_rt_fetch (rtindex , root );
2149
2290
ListCell * lc ,
2150
2291
* lc2 ;
2292
+ List * additional_conds = NIL ;
2151
2293
2152
2294
/* Set up context struct for recursion */
2153
2295
context .root = root ;
@@ -2189,17 +2331,17 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
2189
2331
{
2190
2332
List * ignore_conds = NIL ;
2191
2333
2334
+
2192
2335
appendStringInfoString (buf , " FROM " );
2193
2336
deparseFromExprForRel (buf , root , foreignrel , true, rtindex ,
2194
- & ignore_conds , params_list );
2337
+ & ignore_conds , & additional_conds , params_list );
2195
2338
remote_conds = list_concat (remote_conds , ignore_conds );
2196
2339
}
2197
2340
2198
- if (remote_conds )
2199
- {
2200
- appendStringInfoString (buf , " WHERE " );
2201
- appendConditions (remote_conds , & context );
2202
- }
2341
+ appendWhereClause (remote_conds , additional_conds , & context );
2342
+
2343
+ if (additional_conds != NIL )
2344
+ list_free_deep (additional_conds );
2203
2345
2204
2346
if (foreignrel -> reloptkind == RELOPT_JOINREL )
2205
2347
deparseExplicitTargetList (returningList , true, retrieved_attrs ,
@@ -2255,6 +2397,7 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
2255
2397
List * * retrieved_attrs )
2256
2398
{
2257
2399
deparse_expr_cxt context ;
2400
+ List * additional_conds = NIL ;
2258
2401
2259
2402
/* Set up context struct for recursion */
2260
2403
context .root = root ;
@@ -2274,15 +2417,14 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
2274
2417
2275
2418
appendStringInfoString (buf , " USING " );
2276
2419
deparseFromExprForRel (buf , root , foreignrel , true, rtindex ,
2277
- & ignore_conds , params_list );
2420
+ & ignore_conds , & additional_conds , params_list );
2278
2421
remote_conds = list_concat (remote_conds , ignore_conds );
2279
2422
}
2280
2423
2281
- if (remote_conds )
2282
- {
2283
- appendStringInfoString (buf , " WHERE " );
2284
- appendConditions (remote_conds , & context );
2285
- }
2424
+ appendWhereClause (remote_conds , additional_conds , & context );
2425
+
2426
+ if (additional_conds != NIL )
2427
+ list_free_deep (additional_conds );
2286
2428
2287
2429
if (foreignrel -> reloptkind == RELOPT_JOINREL )
2288
2430
deparseExplicitTargetList (returningList , true, retrieved_attrs ,
0 commit comments