@@ -109,6 +109,8 @@ typedef struct deparse_expr_cxt
109
109
/* Handy macro to add relation name qualification */
110
110
#define ADD_REL_QUALIFIER (buf , varno ) \
111
111
appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
112
+ #define SUBQUERY_REL_ALIAS_PREFIX "s"
113
+ #define SUBQUERY_COL_ALIAS_PREFIX "c"
112
114
113
115
/*
114
116
* Functions to determine whether an expression can be evaluated safely on
@@ -132,6 +134,7 @@ static void deparseTargetList(StringInfo buf,
132
134
List * * retrieved_attrs );
133
135
static void deparseExplicitTargetList (List * tlist , List * * retrieved_attrs ,
134
136
deparse_expr_cxt * context );
137
+ static void deparseSubqueryTargetList (deparse_expr_cxt * context );
135
138
static void deparseReturningList (StringInfo buf , PlannerInfo * root ,
136
139
Index rtindex , Relation rel ,
137
140
bool trig_after_row ,
@@ -159,14 +162,17 @@ static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
159
162
deparse_expr_cxt * context );
160
163
static void printRemotePlaceholder (Oid paramtype , int32 paramtypmod ,
161
164
deparse_expr_cxt * context );
162
- static void deparseSelectSql (List * tlist , List * * retrieved_attrs ,
165
+ static void deparseSelectSql (List * tlist , bool is_subquery , List * * retrieved_attrs ,
163
166
deparse_expr_cxt * context );
164
167
static void deparseLockingClause (deparse_expr_cxt * context );
165
168
static void appendOrderByClause (List * pathkeys , deparse_expr_cxt * context );
166
169
static void appendConditions (List * exprs , deparse_expr_cxt * context );
167
170
static void deparseFromExprForRel (StringInfo buf , PlannerInfo * root ,
168
171
RelOptInfo * joinrel , bool use_alias , List * * params_list );
169
172
static 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 );
170
176
static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
171
177
static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
172
178
static void appendAggOrderBy (List * orderList , List * targetList ,
@@ -175,6 +181,14 @@ static void appendFunctionName(Oid funcid, deparse_expr_cxt *context);
175
181
static Node * deparseSortGroupClause (Index ref , List * tlist ,
176
182
deparse_expr_cxt * context );
177
183
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
+
178
192
179
193
/*
180
194
* Examine each qual clause in input_conds, and classify them into two groups,
@@ -896,12 +910,16 @@ build_tlist_to_deparse(RelOptInfo *foreignrel)
896
910
*
897
911
* pathkeys is the list of pathkeys to order the result by.
898
912
*
913
+ * is_subquery is the flag to indicate whether to deparse the specified
914
+ * relation as a subquery.
915
+ *
899
916
* List of columns selected is returned in retrieved_attrs.
900
917
*/
901
918
extern void
902
919
deparseSelectStmtForRel (StringInfo buf , PlannerInfo * root , RelOptInfo * rel ,
903
920
List * tlist , List * remote_conds , List * pathkeys ,
904
- List * * retrieved_attrs , List * * params_list )
921
+ bool is_subquery , List * * retrieved_attrs ,
922
+ List * * params_list )
905
923
{
906
924
deparse_expr_cxt context ;
907
925
PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) rel -> fdw_private ;
@@ -925,7 +943,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
925
943
context .params_list = params_list ;
926
944
927
945
/* Construct SELECT clause */
928
- deparseSelectSql (tlist , retrieved_attrs , & context );
946
+ deparseSelectSql (tlist , is_subquery , retrieved_attrs , & context );
929
947
930
948
/*
931
949
* For upper relations, the WHERE clause is built from the remote
@@ -972,13 +990,16 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
972
990
* contains just "SELECT ... ".
973
991
*
974
992
* 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.
976
995
*
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.
979
999
*/
980
1000
static 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 )
982
1003
{
983
1004
StringInfo buf = context -> buf ;
984
1005
RelOptInfo * foreignrel = context -> foreignrel ;
@@ -990,10 +1011,22 @@ deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context)
990
1011
*/
991
1012
appendStringInfoString (buf , "SELECT " );
992
1013
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 )
995
1025
{
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
+ */
997
1030
deparseExplicitTargetList (tlist , retrieved_attrs , context );
998
1031
}
999
1032
else
@@ -1155,10 +1188,18 @@ deparseLockingClause(deparse_expr_cxt *context)
1155
1188
StringInfo buf = context -> buf ;
1156
1189
PlannerInfo * root = context -> root ;
1157
1190
RelOptInfo * rel = context -> scanrel ;
1191
+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) rel -> fdw_private ;
1158
1192
int relid = -1 ;
1159
1193
1160
1194
while ((relid = bms_next_member (rel -> relids , relid )) >= 0 )
1161
1195
{
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
+
1162
1203
/*
1163
1204
* Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1164
1205
* initial row fetch, rather than later on as is done for local
@@ -1329,6 +1370,40 @@ deparseExplicitTargetList(List *tlist, List **retrieved_attrs,
1329
1370
appendStringInfoString (buf , "NULL" );
1330
1371
}
1331
1372
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
+
1332
1407
/*
1333
1408
* Construct FROM clause for given relation
1334
1409
*
@@ -1344,18 +1419,18 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1344
1419
1345
1420
if (foreignrel -> reloptkind == RELOPT_JOINREL )
1346
1421
{
1347
- RelOptInfo * rel_o = fpinfo -> outerrel ;
1348
- RelOptInfo * rel_i = fpinfo -> innerrel ;
1349
1422
StringInfoData join_sql_o ;
1350
1423
StringInfoData join_sql_i ;
1351
1424
1352
1425
/* Deparse outer relation */
1353
1426
initStringInfo (& 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 );
1355
1429
1356
1430
/* Deparse inner relation */
1357
1431
initStringInfo (& 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 );
1359
1434
1360
1435
/*
1361
1436
* For a join relation FROM clause entry is deparsed as
@@ -1410,6 +1485,63 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1410
1485
}
1411
1486
}
1412
1487
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
+
1413
1545
/*
1414
1546
* deparse remote INSERT statement
1415
1547
*
@@ -2054,10 +2186,25 @@ static void
2054
2186
deparseVar (Var * node , deparse_expr_cxt * context )
2055
2187
{
2056
2188
Relids relids = context -> scanrel -> relids ;
2189
+ int relno ;
2190
+ int colno ;
2057
2191
2058
2192
/* Qualify columns when multiple relations are involved. */
2059
2193
bool qualify_col = (bms_num_members (relids ) > 1 );
2060
2194
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
+
2061
2208
if (bms_is_member (node -> varno , relids ) && node -> varlevelsup == 0 )
2062
2209
deparseColumnRef (context -> buf , node -> varno , node -> varattno ,
2063
2210
context -> root , qualify_col );
@@ -2935,3 +3082,100 @@ deparseSortGroupClause(Index ref, List *tlist, deparse_expr_cxt *context)
2935
3082
2936
3083
return (Node * ) expr ;
2937
3084
}
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
+ }
0 commit comments