@@ -109,6 +109,8 @@ typedef struct deparse_expr_cxt
109109/* Handy macro to add relation name qualification */
110110#define ADD_REL_QUALIFIER (buf ,varno )\
111111appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
112+ #define SUBQUERY_REL_ALIAS_PREFIX "s"
113+ #define SUBQUERY_COL_ALIAS_PREFIX "c"
112114
113115/*
114116 * Functions to determine whether an expression can be evaluated safely on
@@ -132,6 +134,7 @@ static void deparseTargetList(StringInfo buf,
132134List * * retrieved_attrs );
133135static void deparseExplicitTargetList (List * tlist ,List * * retrieved_attrs ,
134136deparse_expr_cxt * context );
137+ static void deparseSubqueryTargetList (deparse_expr_cxt * context );
135138static void deparseReturningList (StringInfo buf ,PlannerInfo * root ,
136139Index rtindex ,Relation rel ,
137140bool trig_after_row ,
@@ -159,14 +162,17 @@ static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
159162deparse_expr_cxt * context );
160163static void printRemotePlaceholder (Oid paramtype ,int32 paramtypmod ,
161164deparse_expr_cxt * context );
162- static void deparseSelectSql (List * tlist ,List * * retrieved_attrs ,
165+ static void deparseSelectSql (List * tlist ,bool is_subquery , List * * retrieved_attrs ,
163166deparse_expr_cxt * context );
164167static void deparseLockingClause (deparse_expr_cxt * context );
165168static void appendOrderByClause (List * pathkeys ,deparse_expr_cxt * context );
166169static void appendConditions (List * exprs ,deparse_expr_cxt * context );
167170static void deparseFromExprForRel (StringInfo buf ,PlannerInfo * root ,
168171RelOptInfo * joinrel ,bool use_alias ,List * * params_list );
169172static void deparseFromExpr (List * quals ,deparse_expr_cxt * context );
173+ static void deparseRangeTblRef (StringInfo buf ,PlannerInfo * root ,
174+ RelOptInfo * foreignrel ,bool make_subquery ,
175+ List * * params_list );
170176static void deparseAggref (Aggref * node ,deparse_expr_cxt * context );
171177static void appendGroupByClause (List * tlist ,deparse_expr_cxt * context );
172178static void appendAggOrderBy (List * orderList ,List * targetList ,
@@ -175,6 +181,14 @@ static void appendFunctionName(Oid funcid, deparse_expr_cxt *context);
175181static Node * deparseSortGroupClause (Index ref ,List * tlist ,
176182deparse_expr_cxt * context );
177183
184+ /*
185+ * Helper functions
186+ */
187+ static bool is_subquery_var (Var * node ,RelOptInfo * foreignrel ,
188+ int * relno ,int * colno );
189+ static void get_relation_column_alias_ids (Var * node ,RelOptInfo * foreignrel ,
190+ int * relno ,int * colno );
191+
178192
179193/*
180194 * Examine each qual clause in input_conds, and classify them into two groups,
@@ -896,12 +910,16 @@ build_tlist_to_deparse(RelOptInfo *foreignrel)
896910 *
897911 * pathkeys is the list of pathkeys to order the result by.
898912 *
913+ * is_subquery is the flag to indicate whether to deparse the specified
914+ * relation as a subquery.
915+ *
899916 * List of columns selected is returned in retrieved_attrs.
900917 */
901918extern void
902919deparseSelectStmtForRel (StringInfo buf ,PlannerInfo * root ,RelOptInfo * rel ,
903920List * tlist ,List * remote_conds ,List * pathkeys ,
904- List * * retrieved_attrs ,List * * params_list )
921+ bool is_subquery ,List * * retrieved_attrs ,
922+ List * * params_list )
905923{
906924deparse_expr_cxt context ;
907925PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )rel -> fdw_private ;
@@ -925,7 +943,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
925943context .params_list = params_list ;
926944
927945/* Construct SELECT clause */
928- deparseSelectSql (tlist ,retrieved_attrs ,& context );
946+ deparseSelectSql (tlist ,is_subquery , retrieved_attrs ,& context );
929947
930948/*
931949 * For upper relations, the WHERE clause is built from the remote
@@ -972,13 +990,16 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
972990 * contains just "SELECT ... ".
973991 *
974992 * We also create an integer List of the columns being retrieved, which is
975- * returned to *retrieved_attrs.
993+ * returned to *retrieved_attrs, unless we deparse the specified relation
994+ * as a subquery.
976995 *
977- * tlist is the list of desired columns. Read prologue of
978- * deparseSelectStmtForRel() for details.
996+ * tlist is the list of desired columns. is_subquery is the flag to
997+ * indicate whether to deparse the specified relation as a subquery.
998+ * Read prologue of deparseSelectStmtForRel() for details.
979999 */
9801000static void
981- deparseSelectSql (List * tlist ,List * * retrieved_attrs ,deparse_expr_cxt * context )
1001+ deparseSelectSql (List * tlist ,bool is_subquery ,List * * retrieved_attrs ,
1002+ deparse_expr_cxt * context )
9821003{
9831004StringInfo buf = context -> buf ;
9841005RelOptInfo * foreignrel = context -> foreignrel ;
@@ -990,10 +1011,22 @@ deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context)
9901011 */
9911012appendStringInfoString (buf ,"SELECT " );
9921013
993- if (foreignrel -> reloptkind == RELOPT_JOINREL ||
994- foreignrel -> reloptkind == RELOPT_UPPER_REL )
1014+ if (is_subquery )
1015+ {
1016+ /*
1017+ * For a relation that is deparsed as a subquery, emit expressions
1018+ * specified in the relation's reltarget. Note that since this is
1019+ * for the subquery, no need to care about *retrieved_attrs.
1020+ */
1021+ deparseSubqueryTargetList (context );
1022+ }
1023+ else if (foreignrel -> reloptkind == RELOPT_JOINREL ||
1024+ foreignrel -> reloptkind == RELOPT_UPPER_REL )
9951025{
996- /* For a join relation use the input tlist */
1026+ /*
1027+ * For a join or upper relation the input tlist gives the list of
1028+ * columns required to be fetched from the foreign server.
1029+ */
9971030deparseExplicitTargetList (tlist ,retrieved_attrs ,context );
9981031}
9991032else
@@ -1155,10 +1188,18 @@ deparseLockingClause(deparse_expr_cxt *context)
11551188StringInfo buf = context -> buf ;
11561189PlannerInfo * root = context -> root ;
11571190RelOptInfo * rel = context -> scanrel ;
1191+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )rel -> fdw_private ;
11581192int relid = -1 ;
11591193
11601194while ((relid = bms_next_member (rel -> relids ,relid )) >=0 )
11611195{
1196+ /*
1197+ * Ignore relation if it appears in a lower subquery. Locking clause
1198+ * for such a relation is included in the subquery if necessary.
1199+ */
1200+ if (bms_is_member (relid ,fpinfo -> lower_subquery_rels ))
1201+ continue ;
1202+
11621203/*
11631204 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
11641205 * initial row fetch, rather than later on as is done for local
@@ -1329,6 +1370,40 @@ deparseExplicitTargetList(List *tlist, List **retrieved_attrs,
13291370appendStringInfoString (buf ,"NULL" );
13301371}
13311372
1373+ /*
1374+ * Emit expressions specified in the given relation's reltarget.
1375+ *
1376+ * This is used for deparsing the given relation as a subquery.
1377+ */
1378+ static void
1379+ deparseSubqueryTargetList (deparse_expr_cxt * context )
1380+ {
1381+ StringInfo buf = context -> buf ;
1382+ RelOptInfo * foreignrel = context -> foreignrel ;
1383+ bool first ;
1384+ ListCell * lc ;
1385+
1386+ /* Should only be called in these cases. */
1387+ Assert (foreignrel -> reloptkind == RELOPT_BASEREL ||
1388+ foreignrel -> reloptkind == RELOPT_JOINREL );
1389+
1390+ first = true;
1391+ foreach (lc ,foreignrel -> reltarget -> exprs )
1392+ {
1393+ Node * node = (Node * )lfirst (lc );
1394+
1395+ if (!first )
1396+ appendStringInfoString (buf ,", " );
1397+ first = false;
1398+
1399+ deparseExpr ((Expr * )node ,context );
1400+ }
1401+
1402+ /* Don't generate bad syntax if no expressions */
1403+ if (first )
1404+ appendStringInfoString (buf ,"NULL" );
1405+ }
1406+
13321407/*
13331408 * Construct FROM clause for given relation
13341409 *
@@ -1344,18 +1419,18 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
13441419
13451420if (foreignrel -> reloptkind == RELOPT_JOINREL )
13461421{
1347- RelOptInfo * rel_o = fpinfo -> outerrel ;
1348- RelOptInfo * rel_i = fpinfo -> innerrel ;
13491422StringInfoData join_sql_o ;
13501423StringInfoData join_sql_i ;
13511424
13521425/* Deparse outer relation */
13531426initStringInfo (& join_sql_o );
1354- deparseFromExprForRel (& join_sql_o ,root ,rel_o , true,params_list );
1427+ deparseRangeTblRef (& join_sql_o ,root ,fpinfo -> outerrel ,
1428+ fpinfo -> make_outerrel_subquery ,params_list );
13551429
13561430/* Deparse inner relation */
13571431initStringInfo (& join_sql_i );
1358- deparseFromExprForRel (& join_sql_i ,root ,rel_i , true,params_list );
1432+ deparseRangeTblRef (& join_sql_i ,root ,fpinfo -> innerrel ,
1433+ fpinfo -> make_innerrel_subquery ,params_list );
13591434
13601435/*
13611436 * For a join relation FROM clause entry is deparsed as
@@ -1410,6 +1485,63 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
14101485}
14111486}
14121487
1488+ /*
1489+ * Append FROM clause entry for the given relation into buf.
1490+ */
1491+ static void
1492+ deparseRangeTblRef (StringInfo buf ,PlannerInfo * root ,RelOptInfo * foreignrel ,
1493+ bool make_subquery ,List * * params_list )
1494+ {
1495+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )foreignrel -> fdw_private ;
1496+
1497+ /* Should only be called in these cases. */
1498+ Assert (foreignrel -> reloptkind == RELOPT_BASEREL ||
1499+ foreignrel -> reloptkind == RELOPT_JOINREL );
1500+
1501+ Assert (fpinfo -> local_conds == NIL );
1502+
1503+ /* If make_subquery is true, deparse the relation as a subquery. */
1504+ if (make_subquery )
1505+ {
1506+ List * retrieved_attrs ;
1507+ int ncols ;
1508+
1509+ /* Deparse the subquery representing the relation. */
1510+ appendStringInfoChar (buf ,'(' );
1511+ deparseSelectStmtForRel (buf ,root ,foreignrel ,NIL ,
1512+ fpinfo -> remote_conds ,NIL , true,
1513+ & retrieved_attrs ,params_list );
1514+ appendStringInfoChar (buf ,')' );
1515+
1516+ /* Append the relation alias. */
1517+ appendStringInfo (buf ," %s%d" ,SUBQUERY_REL_ALIAS_PREFIX ,
1518+ fpinfo -> relation_index );
1519+
1520+ /*
1521+ * Append the column aliases if needed. Note that the subquery emits
1522+ * expressions specified in the relation's reltarget (see
1523+ * deparseSubqueryTargetList).
1524+ */
1525+ ncols = list_length (foreignrel -> reltarget -> exprs );
1526+ if (ncols > 0 )
1527+ {
1528+ int i ;
1529+
1530+ appendStringInfoChar (buf ,'(' );
1531+ for (i = 1 ;i <=ncols ;i ++ )
1532+ {
1533+ if (i > 1 )
1534+ appendStringInfoString (buf ,", " );
1535+
1536+ appendStringInfo (buf ,"%s%d" ,SUBQUERY_COL_ALIAS_PREFIX ,i );
1537+ }
1538+ appendStringInfoChar (buf ,')' );
1539+ }
1540+ }
1541+ else
1542+ deparseFromExprForRel (buf ,root ,foreignrel , true,params_list );
1543+ }
1544+
14131545/*
14141546 * deparse remote INSERT statement
14151547 *
@@ -2054,10 +2186,25 @@ static void
20542186deparseVar (Var * node ,deparse_expr_cxt * context )
20552187{
20562188Relids relids = context -> scanrel -> relids ;
2189+ int relno ;
2190+ int colno ;
20572191
20582192/* Qualify columns when multiple relations are involved. */
20592193bool qualify_col = (bms_num_members (relids )> 1 );
20602194
2195+ /*
2196+ * If the Var belongs to the foreign relation that is deparsed as a
2197+ * subquery, use the relation and column alias to the Var provided
2198+ * by the subquery, instead of the remote name.
2199+ */
2200+ if (is_subquery_var (node ,context -> scanrel ,& relno ,& colno ))
2201+ {
2202+ appendStringInfo (context -> buf ,"%s%d.%s%d" ,
2203+ SUBQUERY_REL_ALIAS_PREFIX ,relno ,
2204+ SUBQUERY_COL_ALIAS_PREFIX ,colno );
2205+ return ;
2206+ }
2207+
20612208if (bms_is_member (node -> varno ,relids )&& node -> varlevelsup == 0 )
20622209deparseColumnRef (context -> buf ,node -> varno ,node -> varattno ,
20632210context -> root ,qualify_col );
@@ -2935,3 +3082,100 @@ deparseSortGroupClause(Index ref, List *tlist, deparse_expr_cxt *context)
29353082
29363083return (Node * )expr ;
29373084}
3085+
3086+
3087+ /*
3088+ * Returns true if given Var is deparsed as a subquery output column, in
3089+ * which case, *relno and *colno are set to the IDs for the relation and
3090+ * column alias to the Var provided by the subquery.
3091+ */
3092+ static bool
3093+ is_subquery_var (Var * node ,RelOptInfo * foreignrel ,int * relno ,int * colno )
3094+ {
3095+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )foreignrel -> fdw_private ;
3096+ RelOptInfo * outerrel = fpinfo -> outerrel ;
3097+ RelOptInfo * innerrel = fpinfo -> innerrel ;
3098+
3099+ /* Should only be called in these cases. */
3100+ Assert (foreignrel -> reloptkind == RELOPT_BASEREL ||
3101+ foreignrel -> reloptkind == RELOPT_JOINREL ||
3102+ foreignrel -> reloptkind == RELOPT_OTHER_MEMBER_REL );
3103+
3104+ /*
3105+ * If the given relation isn't a join relation, it doesn't have any lower
3106+ * subqueries, so the Var isn't a subquery output column.
3107+ */
3108+ if (foreignrel -> reloptkind != RELOPT_JOINREL )
3109+ return false;
3110+
3111+ /*
3112+ * If the Var doesn't belong to any lower subqueries, it isn't a subquery
3113+ * output column.
3114+ */
3115+ if (!bms_is_member (node -> varno ,fpinfo -> lower_subquery_rels ))
3116+ return false;
3117+
3118+ if (bms_is_member (node -> varno ,outerrel -> relids ))
3119+ {
3120+ /*
3121+ * If outer relation is deparsed as a subquery, the Var is an output
3122+ * column of the subquery; get the IDs for the relation/column alias.
3123+ */
3124+ if (fpinfo -> make_outerrel_subquery )
3125+ {
3126+ get_relation_column_alias_ids (node ,outerrel ,relno ,colno );
3127+ return true;
3128+ }
3129+
3130+ /* Otherwise, recurse into the outer relation. */
3131+ return is_subquery_var (node ,outerrel ,relno ,colno );
3132+ }
3133+ else
3134+ {
3135+ Assert (bms_is_member (node -> varno ,innerrel -> relids ));
3136+
3137+ /*
3138+ * If inner relation is deparsed as a subquery, the Var is an output
3139+ * column of the subquery; get the IDs for the relation/column alias.
3140+ */
3141+ if (fpinfo -> make_innerrel_subquery )
3142+ {
3143+ get_relation_column_alias_ids (node ,innerrel ,relno ,colno );
3144+ return true;
3145+ }
3146+
3147+ /* Otherwise, recurse into the inner relation. */
3148+ return is_subquery_var (node ,innerrel ,relno ,colno );
3149+ }
3150+ }
3151+
3152+ /*
3153+ * Get the IDs for the relation and column alias to given Var belonging to
3154+ * given relation, which are returned into *relno and *colno.
3155+ */
3156+ static void
3157+ get_relation_column_alias_ids (Var * node ,RelOptInfo * foreignrel ,
3158+ int * relno ,int * colno )
3159+ {
3160+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )foreignrel -> fdw_private ;
3161+ int i ;
3162+ ListCell * lc ;
3163+
3164+ /* Get the relation alias ID */
3165+ * relno = fpinfo -> relation_index ;
3166+
3167+ /* Get the column alias ID */
3168+ i = 1 ;
3169+ foreach (lc ,foreignrel -> reltarget -> exprs )
3170+ {
3171+ if (equal (lfirst (lc ), (Node * )node ))
3172+ {
3173+ * colno = i ;
3174+ return ;
3175+ }
3176+ i ++ ;
3177+ }
3178+
3179+ /* Shouldn't get here */
3180+ elog (ERROR ,"unexpected expression in subquery output" );
3181+ }