@@ -180,11 +180,15 @@ static void appendConditions(List *exprs, deparse_expr_cxt *context);
180180static void deparseFromExprForRel (StringInfo buf , PlannerInfo * root ,
181181 RelOptInfo * foreignrel , bool use_alias ,
182182 Index ignore_rel , List * * ignore_conds ,
183+ List * * additional_conds ,
183184 List * * params_list );
185+ static void appendWhereClause (List * exprs , List * additional_conds ,
186+ deparse_expr_cxt * context );
184187static void deparseFromExpr (List * quals , deparse_expr_cxt * context );
185188static void deparseRangeTblRef (StringInfo buf , PlannerInfo * root ,
186189 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 );
188192static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
189193static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
190194static void appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
@@ -1370,6 +1374,7 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context)
13701374{
13711375 StringInfo buf = context -> buf ;
13721376 RelOptInfo * scanrel = context -> scanrel ;
1377+ List * additional_conds = NIL ;
13731378
13741379 /* For upper relations, scanrel must be either a joinrel or a baserel */
13751380 Assert (!IS_UPPER_REL (context -> foreignrel ) ||
@@ -1379,14 +1384,11 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context)
13791384 appendStringInfoString (buf , " FROM " );
13801385 deparseFromExprForRel (buf , context -> root , scanrel ,
13811386 (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 );
13901392}
13911393
13921394/*
@@ -1598,6 +1600,42 @@ appendConditions(List *exprs, deparse_expr_cxt *context)
15981600 reset_transmission_modes (nestlevel );
15991601}
16001602
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+
16011639/* Output join name for given join type */
16021640const char *
16031641get_jointype_name (JoinType jointype )
@@ -1616,6 +1654,9 @@ get_jointype_name(JoinType jointype)
16161654 case JOIN_FULL :
16171655 return "FULL" ;
16181656
1657+ case JOIN_SEMI :
1658+ return "SEMI" ;
1659+
16191660 default :
16201661 /* Shouldn't come here, but protect from buggy code. */
16211662 elog (ERROR , "unsupported join type %d" , jointype );
@@ -1712,11 +1753,14 @@ deparseSubqueryTargetList(deparse_expr_cxt *context)
17121753 * of DELETE; it deparses the join relation as if the relation never contained
17131754 * the target relation, and creates a List of conditions to be deparsed into
17141755 * 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.
17151759 */
17161760static void
17171761deparseFromExprForRel (StringInfo buf , PlannerInfo * root , RelOptInfo * foreignrel ,
17181762 bool use_alias , Index ignore_rel , List * * ignore_conds ,
1719- List * * params_list )
1763+ List * * additional_conds , List * * params_list )
17201764{
17211765 PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) foreignrel -> fdw_private ;
17221766
@@ -1728,6 +1772,8 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
17281772 RelOptInfo * innerrel = fpinfo -> innerrel ;
17291773 bool outerrel_is_target = false;
17301774 bool innerrel_is_target = false;
1775+ List * additional_conds_i = NIL ;
1776+ List * additional_conds_o = NIL ;
17311777
17321778 if (ignore_rel > 0 && bms_is_member (ignore_rel , foreignrel -> relids ))
17331779 {
@@ -1764,7 +1810,8 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
17641810 initStringInfo (& join_sql_o );
17651811 deparseRangeTblRef (& join_sql_o , root , outerrel ,
17661812 fpinfo -> make_outerrel_subquery ,
1767- ignore_rel , ignore_conds , params_list );
1813+ ignore_rel , ignore_conds , & additional_conds_o ,
1814+ params_list );
17681815
17691816 /*
17701817 * If inner relation is the target relation, skip deparsing it.
@@ -1780,6 +1827,12 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
17801827 Assert (fpinfo -> jointype == JOIN_INNER );
17811828 Assert (fpinfo -> joinclauses == NIL );
17821829 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+ }
17831836 return ;
17841837 }
17851838 }
@@ -1790,7 +1843,54 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
17901843 initStringInfo (& join_sql_i );
17911844 deparseRangeTblRef (& join_sql_i , root , innerrel ,
17921845 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+ }
17941894
17951895 /*
17961896 * If outer relation is the target relation, skip deparsing it.
@@ -1801,6 +1901,12 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
18011901 Assert (fpinfo -> jointype == JOIN_INNER );
18021902 Assert (fpinfo -> joinclauses == NIL );
18031903 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+ }
18041910 return ;
18051911 }
18061912 }
@@ -1809,33 +1915,65 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
18091915 Assert (!outerrel_is_target && !innerrel_is_target );
18101916
18111917 /*
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.
18151921 */
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 )
18211923 {
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 );
18231936
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 ;
18291941
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. */
18321956 appendStringInfoChar (buf , ')' );
18331957 }
1834- else
1835- appendStringInfoString (buf , "(TRUE)" );
18361958
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+ }
18391977 }
18401978 else
18411979 {
@@ -1863,11 +2001,13 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
18632001
18642002/*
18652003 * 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.
18662006 */
18672007static void
18682008deparseRangeTblRef (StringInfo buf , PlannerInfo * root , RelOptInfo * foreignrel ,
18692009 bool make_subquery , Index ignore_rel , List * * ignore_conds ,
1870- List * * params_list )
2010+ List * * additional_conds , List * * params_list )
18712011{
18722012 PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) foreignrel -> fdw_private ;
18732013
@@ -1925,7 +2065,8 @@ deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
19252065 }
19262066 else
19272067 deparseFromExprForRel (buf , root , foreignrel , true, ignore_rel ,
1928- ignore_conds , params_list );
2068+ ignore_conds , additional_conds ,
2069+ params_list );
19292070}
19302071
19312072/*
@@ -2148,6 +2289,7 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
21482289 RangeTblEntry * rte = planner_rt_fetch (rtindex , root );
21492290 ListCell * lc ,
21502291 * lc2 ;
2292+ List * additional_conds = NIL ;
21512293
21522294 /* Set up context struct for recursion */
21532295 context .root = root ;
@@ -2189,17 +2331,17 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
21892331 {
21902332 List * ignore_conds = NIL ;
21912333
2334+
21922335 appendStringInfoString (buf , " FROM " );
21932336 deparseFromExprForRel (buf , root , foreignrel , true, rtindex ,
2194- & ignore_conds , params_list );
2337+ & ignore_conds , & additional_conds , params_list );
21952338 remote_conds = list_concat (remote_conds , ignore_conds );
21962339 }
21972340
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 );
22032345
22042346 if (foreignrel -> reloptkind == RELOPT_JOINREL )
22052347 deparseExplicitTargetList (returningList , true, retrieved_attrs ,
@@ -2255,6 +2397,7 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
22552397 List * * retrieved_attrs )
22562398{
22572399 deparse_expr_cxt context ;
2400+ List * additional_conds = NIL ;
22582401
22592402 /* Set up context struct for recursion */
22602403 context .root = root ;
@@ -2274,15 +2417,14 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
22742417
22752418 appendStringInfoString (buf , " USING " );
22762419 deparseFromExprForRel (buf , root , foreignrel , true, rtindex ,
2277- & ignore_conds , params_list );
2420+ & ignore_conds , & additional_conds , params_list );
22782421 remote_conds = list_concat (remote_conds , ignore_conds );
22792422 }
22802423
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 );
22862428
22872429 if (foreignrel -> reloptkind == RELOPT_JOINREL )
22882430 deparseExplicitTargetList (returningList , true, retrieved_attrs ,
0 commit comments