1 /*-------------------------------------------------------------------------
2 *
3 * deparse.c
4 * Query deparser for postgres_fdw
5 *
6 * This file includes functions that examine query WHERE clauses to see
7 * whether they're safe to send to the remote server for execution, as
8 * well as functions to construct the query text to be sent. The latter
9 * functionality is annoyingly duplicative of ruleutils.c, but there are
10 * enough special considerations that it seems best to keep this separate.
11 * One saving grace is that we only need deparse logic for node types that
12 * we consider safe to send.
13 *
14 * We assume that the remote session's search_path is exactly "pg_catalog",
15 * and thus we need schema-qualify all and only names outside pg_catalog.
16 *
17 * We do not consider that it is ever safe to send COLLATE expressions to
18 * the remote server: it might not have the same collation names we do.
19 * (Later we might consider it safe to send COLLATE "C", but even that would
20 * fail on old remote servers.) An expression is considered safe to send
21 * only if all operator/function input collations used in it are traceable to
22 * Var(s) of the foreign table. That implies that if the remote server gets
23 * a different answer than we do, the foreign table's columns are not marked
24 * with collations that match the remote table's columns, which we can
25 * consider to be user error.
26 *
27 * Portions Copyright (c) 2012-2019, PostgreSQL Global Development Group
28 *
29 * IDENTIFICATION
30 * contrib/postgres_fdw/deparse.c
31 *
32 *-------------------------------------------------------------------------
33 */
34 #include "postgres.h"
35
36 #include "postgres_fdw.h"
37
38 #include "access/htup_details.h"
39 #include "access/sysattr.h"
40 #include "access/table.h"
41 #include "catalog/pg_aggregate.h"
42 #include "catalog/pg_collation.h"
43 #include "catalog/pg_namespace.h"
44 #include "catalog/pg_operator.h"
45 #include "catalog/pg_proc.h"
46 #include "catalog/pg_type.h"
47 #include "commands/defrem.h"
48 #include "nodes/makefuncs.h"
49 #include "nodes/nodeFuncs.h"
50 #include "nodes/plannodes.h"
51 #include "optimizer/optimizer.h"
52 #include "optimizer/prep.h"
53 #include "optimizer/tlist.h"
54 #include "parser/parsetree.h"
55 #include "utils/builtins.h"
56 #include "utils/lsyscache.h"
57 #include "utils/rel.h"
58 #include "utils/syscache.h"
59 #include "utils/typcache.h"
60
61
62 /*
63 * Global context for foreign_expr_walker's search of an expression tree.
64 */
65 typedef struct foreign_glob_cxt
66 {
67 PlannerInfo *root; /* global planner state */
68 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
69 Relids relids; /* relids of base relations in the underlying
70 * scan */
71 } foreign_glob_cxt;
72
73 /*
74 * Local (per-tree-level) context for foreign_expr_walker's search.
75 * This is concerned with identifying collations used in the expression.
76 */
77 typedef enum
78 {
79 FDW_COLLATE_NONE, /* expression is of a noncollatable type, or
80 * it has default collation that is not
81 * traceable to a foreign Var */
82 FDW_COLLATE_SAFE, /* collation derives from a foreign Var */
83 FDW_COLLATE_UNSAFE /* collation is non-default and derives from
84 * something other than a foreign Var */
85 } FDWCollateState;
86
87 typedef struct foreign_loc_cxt
88 {
89 Oid collation; /* OID of current collation, if any */
90 FDWCollateState state; /* state of current collation choice */
91 } foreign_loc_cxt;
92
93 /*
94 * Context for deparseExpr
95 */
96 typedef struct deparse_expr_cxt
97 {
98 PlannerInfo *root; /* global planner state */
99 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
100 RelOptInfo *scanrel; /* the underlying scan relation. Same as
101 * foreignrel, when that represents a join or
102 * a base relation. */
103 StringInfo buf; /* output buffer to append to */
104 List **params_list; /* exprs that will become remote Params */
105 } deparse_expr_cxt;
106
107 #define REL_ALIAS_PREFIX "r"
108 /* Handy macro to add relation name qualification */
109 #define ADD_REL_QUALIFIER(buf, varno) \
110 appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
111 #define SUBQUERY_REL_ALIAS_PREFIX "s"
112 #define SUBQUERY_COL_ALIAS_PREFIX "c"
113
114 /*
115 * Functions to determine whether an expression can be evaluated safely on
116 * remote server.
117 */
118 static bool foreign_expr_walker(Node *node,
119 foreign_glob_cxt *glob_cxt,
120 foreign_loc_cxt *outer_cxt);
121 static char *deparse_type_name(Oid type_oid, int32 typemod);
122
123 /*
124 * Functions to construct string representation of a node tree.
125 */
126 static void deparseTargetList(StringInfo buf,
127 RangeTblEntry *rte,
128 Index rtindex,
129 Relation rel,
130 bool is_returning,
131 Bitmapset *attrs_used,
132 bool qualify_col,
133 List **retrieved_attrs);
134 static void deparseExplicitTargetList(List *tlist,
135 bool is_returning,
136 List **retrieved_attrs,
137 deparse_expr_cxt *context);
138 static void deparseSubqueryTargetList(deparse_expr_cxt *context);
139 static void deparseReturningList(StringInfo buf, RangeTblEntry *rte,
140 Index rtindex, Relation rel,
141 bool trig_after_row,
142 List *withCheckOptionList,
143 List *returningList,
144 List **retrieved_attrs);
145 static void deparseColumnRef(StringInfo buf, int varno, int varattno,
146 RangeTblEntry *rte, bool qualify_col);
147 static void deparseRelation(StringInfo buf, Relation rel);
148 static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
149 static void deparseVar(Var *node, deparse_expr_cxt *context);
150 static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype);
151 static void deparseParam(Param *node, deparse_expr_cxt *context);
152 static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context);
153 static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
154 static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
155 static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
156 static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context);
157 static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node,
158 deparse_expr_cxt *context);
159 static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
160 static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context);
161 static void deparseNullTest(NullTest *node, deparse_expr_cxt *context);
162 static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context);
163 static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
164 deparse_expr_cxt *context);
165 static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
166 deparse_expr_cxt *context);
167 static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
168 deparse_expr_cxt *context);
169 static void deparseLockingClause(deparse_expr_cxt *context);
170 static void appendOrderByClause(List *pathkeys, bool has_final_sort,
171 deparse_expr_cxt *context);
172 static void appendLimitClause(deparse_expr_cxt *context);
173 static void appendConditions(List *exprs, deparse_expr_cxt *context);
174 static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root,
175 RelOptInfo *foreignrel, bool use_alias,
176 Index ignore_rel, List **ignore_conds,
177 List **params_list);
178 static void deparseFromExpr(List *quals, deparse_expr_cxt *context);
179 static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root,
180 RelOptInfo *foreignrel, bool make_subquery,
181 Index ignore_rel, List **ignore_conds, List **params_list);
182 static void deparseAggref(Aggref *node, deparse_expr_cxt *context);
183 static void appendGroupByClause(List *tlist, deparse_expr_cxt *context);
184 static void appendAggOrderBy(List *orderList, List *targetList,
185 deparse_expr_cxt *context);
186 static void appendFunctionName(Oid funcid, deparse_expr_cxt *context);
187 static Node *deparseSortGroupClause(Index ref, List *tlist, bool force_colno,
188 deparse_expr_cxt *context);
189
190 /*
191 * Helper functions
192 */
193 static bool is_subquery_var(Var *node, RelOptInfo *foreignrel,
194 int *relno, int *colno);
195 static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
196 int *relno, int *colno);
197
198
199 /*
200 * Examine each qual clause in input_conds, and classify them into two groups,
201 * which are returned as two lists:
202 * - remote_conds contains expressions that can be evaluated remotely
203 * - local_conds contains expressions that can't be evaluated remotely
204 */
205 void
classifyConditions(PlannerInfo * root,RelOptInfo * baserel,List * input_conds,List ** remote_conds,List ** local_conds)206 classifyConditions(PlannerInfo *root,
207 RelOptInfo *baserel,
208 List *input_conds,
209 List **remote_conds,
210 List **local_conds)
211 {
212 ListCell *lc;
213
214 *remote_conds = NIL;
215 *local_conds = NIL;
216
217 foreach(lc, input_conds)
218 {
219 RestrictInfo *ri = lfirst_node(RestrictInfo, lc);
220
221 if (is_foreign_expr(root, baserel, ri->clause))
222 *remote_conds = lappend(*remote_conds, ri);
223 else
224 *local_conds = lappend(*local_conds, ri);
225 }
226 }
227
228 /*
229 * Returns true if given expr is safe to evaluate on the foreign server.
230 */
231 bool
is_foreign_expr(PlannerInfo * root,RelOptInfo * baserel,Expr * expr)232 is_foreign_expr(PlannerInfo *root,
233 RelOptInfo *baserel,
234 Expr *expr)
235 {
236 foreign_glob_cxt glob_cxt;
237 foreign_loc_cxt loc_cxt;
238 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
239
240 /*
241 * Check that the expression consists of nodes that are safe to execute
242 * remotely.
243 */
244 glob_cxt.root = root;
245 glob_cxt.foreignrel = baserel;
246
247 /*
248 * For an upper relation, use relids from its underneath scan relation,
249 * because the upperrel's own relids currently aren't set to anything
250 * meaningful by the core code. For other relation, use their own relids.
251 */
252 if (IS_UPPER_REL(baserel))
253 glob_cxt.relids = fpinfo->outerrel->relids;
254 else
255 glob_cxt.relids = baserel->relids;
256 loc_cxt.collation = InvalidOid;
257 loc_cxt.state = FDW_COLLATE_NONE;
258 if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt))
259 return false;
260
261 /*
262 * If the expression has a valid collation that does not arise from a
263 * foreign var, the expression can not be sent over.
264 */
265 if (loc_cxt.state == FDW_COLLATE_UNSAFE)
266 return false;
267
268 /*
269 * An expression which includes any mutable functions can't be sent over
270 * because its result is not stable. For example, sending now() remote
271 * side could cause confusion from clock offsets. Future versions might
272 * be able to make this choice with more granularity. (We check this last
273 * because it requires a lot of expensive catalog lookups.)
274 */
275 if (contain_mutable_functions((Node *) expr))
276 return false;
277
278 /* OK to evaluate on the remote server */
279 return true;
280 }
281
282 /*
283 * Check if expression is safe to execute remotely, and return true if so.
284 *
285 * In addition, *outer_cxt is updated with collation information.
286 *
287 * We must check that the expression contains only node types we can deparse,
288 * that all types/functions/operators are safe to send (they are "shippable"),
289 * and that all collations used in the expression derive from Vars of the
290 * foreign table. Because of the latter, the logic is pretty close to
291 * assign_collations_walker() in parse_collate.c, though we can assume here
292 * that the given expression is valid. Note function mutability is not
293 * currently considered here.
294 */
295 static bool
foreign_expr_walker(Node * node,foreign_glob_cxt * glob_cxt,foreign_loc_cxt * outer_cxt)296 foreign_expr_walker(Node *node,
297 foreign_glob_cxt *glob_cxt,
298 foreign_loc_cxt *outer_cxt)
299 {
300 bool check_type = true;
301 PgFdwRelationInfo *fpinfo;
302 foreign_loc_cxt inner_cxt;
303 Oid collation;
304 FDWCollateState state;
305
306 /* Need do nothing for empty subexpressions */
307 if (node == NULL)
308 return true;
309
310 /* May need server info from baserel's fdw_private struct */
311 fpinfo = (PgFdwRelationInfo *) (glob_cxt->foreignrel->fdw_private);
312
313 /* Set up inner_cxt for possible recursion to child nodes */
314 inner_cxt.collation = InvalidOid;
315 inner_cxt.state = FDW_COLLATE_NONE;
316
317 switch (nodeTag(node))
318 {
319 case T_Var:
320 {
321 Var *var = (Var *) node;
322
323 /*
324 * If the Var is from the foreign table, we consider its
325 * collation (if any) safe to use. If it is from another
326 * table, we treat its collation the same way as we would a
327 * Param's collation, ie it's not safe for it to have a
328 * non-default collation.
329 */
330 if (bms_is_member(var->varno, glob_cxt->relids) &&
331 var->varlevelsup == 0)
332 {
333 /* Var belongs to foreign table */
334
335 /*
336 * System columns other than ctid should not be sent to
337 * the remote, since we don't make any effort to ensure
338 * that local and remote values match (tableoid, in
339 * particular, almost certainly doesn't match).
340 */
341 if (var->varattno < 0 &&
342 var->varattno != SelfItemPointerAttributeNumber)
343 return false;
344
345 /* Else check the collation */
346 collation = var->varcollid;
347 state = OidIsValid(collation) ? FDW_COLLATE_SAFE : FDW_COLLATE_NONE;
348 }
349 else
350 {
351 /* Var belongs to some other table */
352 collation = var->varcollid;
353 if (collation == InvalidOid ||
354 collation == DEFAULT_COLLATION_OID)
355 {
356 /*
357 * It's noncollatable, or it's safe to combine with a
358 * collatable foreign Var, so set state to NONE.
359 */
360 state = FDW_COLLATE_NONE;
361 }
362 else
363 {
364 /*
365 * Do not fail right away, since the Var might appear
366 * in a collation-insensitive context.
367 */
368 state = FDW_COLLATE_UNSAFE;
369 }
370 }
371 }
372 break;
373 case T_Const:
374 {
375 Const *c = (Const *) node;
376
377 /*
378 * If the constant has nondefault collation, either it's of a
379 * non-builtin type, or it reflects folding of a CollateExpr.
380 * It's unsafe to send to the remote unless it's used in a
381 * non-collation-sensitive context.
382 */
383 collation = c->constcollid;
384 if (collation == InvalidOid ||
385 collation == DEFAULT_COLLATION_OID)
386 state = FDW_COLLATE_NONE;
387 else
388 state = FDW_COLLATE_UNSAFE;
389 }
390 break;
391 case T_Param:
392 {
393 Param *p = (Param *) node;
394
395 /*
396 * If it's a MULTIEXPR Param, punt. We can't tell from here
397 * whether the referenced sublink/subplan contains any remote
398 * Vars; if it does, handling that is too complicated to
399 * consider supporting at present. Fortunately, MULTIEXPR
400 * Params are not reduced to plain PARAM_EXEC until the end of
401 * planning, so we can easily detect this case. (Normal
402 * PARAM_EXEC Params are safe to ship because their values
403 * come from somewhere else in the plan tree; but a MULTIEXPR
404 * references a sub-select elsewhere in the same targetlist,
405 * so we'd be on the hook to evaluate it somehow if we wanted
406 * to handle such cases as direct foreign updates.)
407 */
408 if (p->paramkind == PARAM_MULTIEXPR)
409 return false;
410
411 /*
412 * Collation rule is same as for Consts and non-foreign Vars.
413 */
414 collation = p->paramcollid;
415 if (collation == InvalidOid ||
416 collation == DEFAULT_COLLATION_OID)
417 state = FDW_COLLATE_NONE;
418 else
419 state = FDW_COLLATE_UNSAFE;
420 }
421 break;
422 case T_SubscriptingRef:
423 {
424 SubscriptingRef *sr = (SubscriptingRef *) node;
425
426 /* Assignment should not be in restrictions. */
427 if (sr->refassgnexpr != NULL)
428 return false;
429
430 /*
431 * Recurse to remaining subexpressions. Since the container
432 * subscripts must yield (noncollatable) integers, they won't
433 * affect the inner_cxt state.
434 */
435 if (!foreign_expr_walker((Node *) sr->refupperindexpr,
436 glob_cxt, &inner_cxt))
437 return false;
438 if (!foreign_expr_walker((Node *) sr->reflowerindexpr,
439 glob_cxt, &inner_cxt))
440 return false;
441 if (!foreign_expr_walker((Node *) sr->refexpr,
442 glob_cxt, &inner_cxt))
443 return false;
444
445 /*
446 * Container subscripting should yield same collation as
447 * input, but for safety use same logic as for function nodes.
448 */
449 collation = sr->refcollid;
450 if (collation == InvalidOid)
451 state = FDW_COLLATE_NONE;
452 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
453 collation == inner_cxt.collation)
454 state = FDW_COLLATE_SAFE;
455 else if (collation == DEFAULT_COLLATION_OID)
456 state = FDW_COLLATE_NONE;
457 else
458 state = FDW_COLLATE_UNSAFE;
459 }
460 break;
461 case T_FuncExpr:
462 {
463 FuncExpr *fe = (FuncExpr *) node;
464
465 /*
466 * If function used by the expression is not shippable, it
467 * can't be sent to remote because it might have incompatible
468 * semantics on remote side.
469 */
470 if (!is_shippable(fe->funcid, ProcedureRelationId, fpinfo))
471 return false;
472
473 /*
474 * Recurse to input subexpressions.
475 */
476 if (!foreign_expr_walker((Node *) fe->args,
477 glob_cxt, &inner_cxt))
478 return false;
479
480 /*
481 * If function's input collation is not derived from a foreign
482 * Var, it can't be sent to remote.
483 */
484 if (fe->inputcollid == InvalidOid)
485 /* OK, inputs are all noncollatable */ ;
486 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
487 fe->inputcollid != inner_cxt.collation)
488 return false;
489
490 /*
491 * Detect whether node is introducing a collation not derived
492 * from a foreign Var. (If so, we just mark it unsafe for now
493 * rather than immediately returning false, since the parent
494 * node might not care.)
495 */
496 collation = fe->funccollid;
497 if (collation == InvalidOid)
498 state = FDW_COLLATE_NONE;
499 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
500 collation == inner_cxt.collation)
501 state = FDW_COLLATE_SAFE;
502 else if (collation == DEFAULT_COLLATION_OID)
503 state = FDW_COLLATE_NONE;
504 else
505 state = FDW_COLLATE_UNSAFE;
506 }
507 break;
508 case T_OpExpr:
509 case T_DistinctExpr: /* struct-equivalent to OpExpr */
510 {
511 OpExpr *oe = (OpExpr *) node;
512
513 /*
514 * Similarly, only shippable operators can be sent to remote.
515 * (If the operator is shippable, we assume its underlying
516 * function is too.)
517 */
518 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
519 return false;
520
521 /*
522 * Recurse to input subexpressions.
523 */
524 if (!foreign_expr_walker((Node *) oe->args,
525 glob_cxt, &inner_cxt))
526 return false;
527
528 /*
529 * If operator's input collation is not derived from a foreign
530 * Var, it can't be sent to remote.
531 */
532 if (oe->inputcollid == InvalidOid)
533 /* OK, inputs are all noncollatable */ ;
534 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
535 oe->inputcollid != inner_cxt.collation)
536 return false;
537
538 /* Result-collation handling is same as for functions */
539 collation = oe->opcollid;
540 if (collation == InvalidOid)
541 state = FDW_COLLATE_NONE;
542 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
543 collation == inner_cxt.collation)
544 state = FDW_COLLATE_SAFE;
545 else if (collation == DEFAULT_COLLATION_OID)
546 state = FDW_COLLATE_NONE;
547 else
548 state = FDW_COLLATE_UNSAFE;
549 }
550 break;
551 case T_ScalarArrayOpExpr:
552 {
553 ScalarArrayOpExpr *oe = (ScalarArrayOpExpr *) node;
554
555 /*
556 * Again, only shippable operators can be sent to remote.
557 */
558 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
559 return false;
560
561 /*
562 * Recurse to input subexpressions.
563 */
564 if (!foreign_expr_walker((Node *) oe->args,
565 glob_cxt, &inner_cxt))
566 return false;
567
568 /*
569 * If operator's input collation is not derived from a foreign
570 * Var, it can't be sent to remote.
571 */
572 if (oe->inputcollid == InvalidOid)
573 /* OK, inputs are all noncollatable */ ;
574 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
575 oe->inputcollid != inner_cxt.collation)
576 return false;
577
578 /* Output is always boolean and so noncollatable. */
579 collation = InvalidOid;
580 state = FDW_COLLATE_NONE;
581 }
582 break;
583 case T_RelabelType:
584 {
585 RelabelType *r = (RelabelType *) node;
586
587 /*
588 * Recurse to input subexpression.
589 */
590 if (!foreign_expr_walker((Node *) r->arg,
591 glob_cxt, &inner_cxt))
592 return false;
593
594 /*
595 * RelabelType must not introduce a collation not derived from
596 * an input foreign Var (same logic as for a real function).
597 */
598 collation = r->resultcollid;
599 if (collation == InvalidOid)
600 state = FDW_COLLATE_NONE;
601 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
602 collation == inner_cxt.collation)
603 state = FDW_COLLATE_SAFE;
604 else if (collation == DEFAULT_COLLATION_OID)
605 state = FDW_COLLATE_NONE;
606 else
607 state = FDW_COLLATE_UNSAFE;
608 }
609 break;
610 case T_BoolExpr:
611 {
612 BoolExpr *b = (BoolExpr *) node;
613
614 /*
615 * Recurse to input subexpressions.
616 */
617 if (!foreign_expr_walker((Node *) b->args,
618 glob_cxt, &inner_cxt))
619 return false;
620
621 /* Output is always boolean and so noncollatable. */
622 collation = InvalidOid;
623 state = FDW_COLLATE_NONE;
624 }
625 break;
626 case T_NullTest:
627 {
628 NullTest *nt = (NullTest *) node;
629
630 /*
631 * Recurse to input subexpressions.
632 */
633 if (!foreign_expr_walker((Node *) nt->arg,
634 glob_cxt, &inner_cxt))
635 return false;
636
637 /* Output is always boolean and so noncollatable. */
638 collation = InvalidOid;
639 state = FDW_COLLATE_NONE;
640 }
641 break;
642 case T_ArrayExpr:
643 {
644 ArrayExpr *a = (ArrayExpr *) node;
645
646 /*
647 * Recurse to input subexpressions.
648 */
649 if (!foreign_expr_walker((Node *) a->elements,
650 glob_cxt, &inner_cxt))
651 return false;
652
653 /*
654 * ArrayExpr must not introduce a collation not derived from
655 * an input foreign Var (same logic as for a function).
656 */
657 collation = a->array_collid;
658 if (collation == InvalidOid)
659 state = FDW_COLLATE_NONE;
660 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
661 collation == inner_cxt.collation)
662 state = FDW_COLLATE_SAFE;
663 else if (collation == DEFAULT_COLLATION_OID)
664 state = FDW_COLLATE_NONE;
665 else
666 state = FDW_COLLATE_UNSAFE;
667 }
668 break;
669 case T_List:
670 {
671 List *l = (List *) node;
672 ListCell *lc;
673
674 /*
675 * Recurse to component subexpressions.
676 */
677 foreach(lc, l)
678 {
679 if (!foreign_expr_walker((Node *) lfirst(lc),
680 glob_cxt, &inner_cxt))
681 return false;
682 }
683
684 /*
685 * When processing a list, collation state just bubbles up
686 * from the list elements.
687 */
688 collation = inner_cxt.collation;
689 state = inner_cxt.state;
690
691 /* Don't apply exprType() to the list. */
692 check_type = false;
693 }
694 break;
695 case T_Aggref:
696 {
697 Aggref *agg = (Aggref *) node;
698 ListCell *lc;
699
700 /* Not safe to pushdown when not in grouping context */
701 if (!IS_UPPER_REL(glob_cxt->foreignrel))
702 return false;
703
704 /* Only non-split aggregates are pushable. */
705 if (agg->aggsplit != AGGSPLIT_SIMPLE)
706 return false;
707
708 /* As usual, it must be shippable. */
709 if (!is_shippable(agg->aggfnoid, ProcedureRelationId, fpinfo))
710 return false;
711
712 /*
713 * Recurse to input args. aggdirectargs, aggorder and
714 * aggdistinct are all present in args, so no need to check
715 * their shippability explicitly.
716 */
717 foreach(lc, agg->args)
718 {
719 Node *n = (Node *) lfirst(lc);
720
721 /* If TargetEntry, extract the expression from it */
722 if (IsA(n, TargetEntry))
723 {
724 TargetEntry *tle = (TargetEntry *) n;
725
726 n = (Node *) tle->expr;
727 }
728
729 if (!foreign_expr_walker(n, glob_cxt, &inner_cxt))
730 return false;
731 }
732
733 /*
734 * For aggorder elements, check whether the sort operator, if
735 * specified, is shippable or not.
736 */
737 if (agg->aggorder)
738 {
739 ListCell *lc;
740
741 foreach(lc, agg->aggorder)
742 {
743 SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
744 Oid sortcoltype;
745 TypeCacheEntry *typentry;
746 TargetEntry *tle;
747
748 tle = get_sortgroupref_tle(srt->tleSortGroupRef,
749 agg->args);
750 sortcoltype = exprType((Node *) tle->expr);
751 typentry = lookup_type_cache(sortcoltype,
752 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
753 /* Check shippability of non-default sort operator. */
754 if (srt->sortop != typentry->lt_opr &&
755 srt->sortop != typentry->gt_opr &&
756 !is_shippable(srt->sortop, OperatorRelationId,
757 fpinfo))
758 return false;
759 }
760 }
761
762 /* Check aggregate filter */
763 if (!foreign_expr_walker((Node *) agg->aggfilter,
764 glob_cxt, &inner_cxt))
765 return false;
766
767 /*
768 * If aggregate's input collation is not derived from a
769 * foreign Var, it can't be sent to remote.
770 */
771 if (agg->inputcollid == InvalidOid)
772 /* OK, inputs are all noncollatable */ ;
773 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
774 agg->inputcollid != inner_cxt.collation)
775 return false;
776
777 /*
778 * Detect whether node is introducing a collation not derived
779 * from a foreign Var. (If so, we just mark it unsafe for now
780 * rather than immediately returning false, since the parent
781 * node might not care.)
782 */
783 collation = agg->aggcollid;
784 if (collation == InvalidOid)
785 state = FDW_COLLATE_NONE;
786 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
787 collation == inner_cxt.collation)
788 state = FDW_COLLATE_SAFE;
789 else if (collation == DEFAULT_COLLATION_OID)
790 state = FDW_COLLATE_NONE;
791 else
792 state = FDW_COLLATE_UNSAFE;
793 }
794 break;
795 default:
796
797 /*
798 * If it's anything else, assume it's unsafe. This list can be
799 * expanded later, but don't forget to add deparse support below.
800 */
801 return false;
802 }
803
804 /*
805 * If result type of given expression is not shippable, it can't be sent
806 * to remote because it might have incompatible semantics on remote side.
807 */
808 if (check_type && !is_shippable(exprType(node), TypeRelationId, fpinfo))
809 return false;
810
811 /*
812 * Now, merge my collation information into my parent's state.
813 */
814 if (state > outer_cxt->state)
815 {
816 /* Override previous parent state */
817 outer_cxt->collation = collation;
818 outer_cxt->state = state;
819 }
820 else if (state == outer_cxt->state)
821 {
822 /* Merge, or detect error if there's a collation conflict */
823 switch (state)
824 {
825 case FDW_COLLATE_NONE:
826 /* Nothing + nothing is still nothing */
827 break;
828 case FDW_COLLATE_SAFE:
829 if (collation != outer_cxt->collation)
830 {
831 /*
832 * Non-default collation always beats default.
833 */
834 if (outer_cxt->collation == DEFAULT_COLLATION_OID)
835 {
836 /* Override previous parent state */
837 outer_cxt->collation = collation;
838 }
839 else if (collation != DEFAULT_COLLATION_OID)
840 {
841 /*
842 * Conflict; show state as indeterminate. We don't
843 * want to "return false" right away, since parent
844 * node might not care about collation.
845 */
846 outer_cxt->state = FDW_COLLATE_UNSAFE;
847 }
848 }
849 break;
850 case FDW_COLLATE_UNSAFE:
851 /* We're still conflicted ... */
852 break;
853 }
854 }
855
856 /* It looks OK */
857 return true;
858 }
859
860 /*
861 * Returns true if given expr is something we'd have to send the value of
862 * to the foreign server.
863 *
864 * This should return true when the expression is a shippable node that
865 * deparseExpr would add to context->params_list. Note that we don't care
866 * if the expression *contains* such a node, only whether one appears at top
867 * level. We need this to detect cases where setrefs.c would recognize a
868 * false match between an fdw_exprs item (which came from the params_list)
869 * and an entry in fdw_scan_tlist (which we're considering putting the given
870 * expression into).
871 */
872 bool
is_foreign_param(PlannerInfo * root,RelOptInfo * baserel,Expr * expr)873 is_foreign_param(PlannerInfo *root,
874 RelOptInfo *baserel,
875 Expr *expr)
876 {
877 if (expr == NULL)
878 return false;
879
880 switch (nodeTag(expr))
881 {
882 case T_Var:
883 {
884 /* It would have to be sent unless it's a foreign Var */
885 Var *var = (Var *) expr;
886 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
887 Relids relids;
888
889 if (IS_UPPER_REL(baserel))
890 relids = fpinfo->outerrel->relids;
891 else
892 relids = baserel->relids;
893
894 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
895 return false; /* foreign Var, so not a param */
896 else
897 return true; /* it'd have to be a param */
898 break;
899 }
900 case T_Param:
901 /* Params always have to be sent to the foreign server */
902 return true;
903 default:
904 break;
905 }
906 return false;
907 }
908
909 /*
910 * Convert type OID + typmod info into a type name we can ship to the remote
911 * server. Someplace else had better have verified that this type name is
912 * expected to be known on the remote end.
913 *
914 * This is almost just format_type_with_typemod(), except that if left to its
915 * own devices, that function will make schema-qualification decisions based
916 * on the local search_path, which is wrong. We must schema-qualify all
917 * type names that are not in pg_catalog. We assume here that built-in types
918 * are all in pg_catalog and need not be qualified; otherwise, qualify.
919 */
920 static char *
deparse_type_name(Oid type_oid,int32 typemod)921 deparse_type_name(Oid type_oid, int32 typemod)
922 {
923 bits16 flags = FORMAT_TYPE_TYPEMOD_GIVEN;
924
925 if (!is_builtin(type_oid))
926 flags |= FORMAT_TYPE_FORCE_QUALIFY;
927
928 return format_type_extended(type_oid, typemod, flags);
929 }
930
931 /*
932 * Build the targetlist for given relation to be deparsed as SELECT clause.
933 *
934 * The output targetlist contains the columns that need to be fetched from the
935 * foreign server for the given relation. If foreignrel is an upper relation,
936 * then the output targetlist can also contain expressions to be evaluated on
937 * foreign server.
938 */
939 List *
build_tlist_to_deparse(RelOptInfo * foreignrel)940 build_tlist_to_deparse(RelOptInfo *foreignrel)
941 {
942 List *tlist = NIL;
943 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
944 ListCell *lc;
945
946 /*
947 * For an upper relation, we have already built the target list while
948 * checking shippability, so just return that.
949 */
950 if (IS_UPPER_REL(foreignrel))
951 return fpinfo->grouped_tlist;
952
953 /*
954 * We require columns specified in foreignrel->reltarget->exprs and those
955 * required for evaluating the local conditions.
956 */
957 tlist = add_to_flat_tlist(tlist,
958 pull_var_clause((Node *) foreignrel->reltarget->exprs,
959 PVC_RECURSE_PLACEHOLDERS));
960 foreach(lc, fpinfo->local_conds)
961 {
962 RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
963
964 tlist = add_to_flat_tlist(tlist,
965 pull_var_clause((Node *) rinfo->clause,
966 PVC_RECURSE_PLACEHOLDERS));
967 }
968
969 return tlist;
970 }
971
972 /*
973 * Deparse SELECT statement for given relation into buf.
974 *
975 * tlist contains the list of desired columns to be fetched from foreign server.
976 * For a base relation fpinfo->attrs_used is used to construct SELECT clause,
977 * hence the tlist is ignored for a base relation.
978 *
979 * remote_conds is the list of conditions to be deparsed into the WHERE clause
980 * (or, in the case of upper relations, into the HAVING clause).
981 *
982 * If params_list is not NULL, it receives a list of Params and other-relation
983 * Vars used in the clauses; these values must be transmitted to the remote
984 * server as parameter values.
985 *
986 * If params_list is NULL, we're generating the query for EXPLAIN purposes,
987 * so Params and other-relation Vars should be replaced by dummy values.
988 *
989 * pathkeys is the list of pathkeys to order the result by.
990 *
991 * is_subquery is the flag to indicate whether to deparse the specified
992 * relation as a subquery.
993 *
994 * List of columns selected is returned in retrieved_attrs.
995 */
996 void
deparseSelectStmtForRel(StringInfo buf,PlannerInfo * root,RelOptInfo * rel,List * tlist,List * remote_conds,List * pathkeys,bool has_final_sort,bool has_limit,bool is_subquery,List ** retrieved_attrs,List ** params_list)997 deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
998 List *tlist, List *remote_conds, List *pathkeys,
999 bool has_final_sort, bool has_limit, bool is_subquery,
1000 List **retrieved_attrs, List **params_list)
1001 {
1002 deparse_expr_cxt context;
1003 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1004 List *quals;
1005
1006 /*
1007 * We handle relations for foreign tables, joins between those and upper
1008 * relations.
1009 */
1010 Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1011
1012 /* Fill portions of context common to upper, join and base relation */
1013 context.buf = buf;
1014 context.root = root;
1015 context.foreignrel = rel;
1016 context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1017 context.params_list = params_list;
1018
1019 /* Construct SELECT clause */
1020 deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1021
1022 /*
1023 * For upper relations, the WHERE clause is built from the remote
1024 * conditions of the underlying scan relation; otherwise, we can use the
1025 * supplied list of remote conditions directly.
1026 */
1027 if (IS_UPPER_REL(rel))
1028 {
1029 PgFdwRelationInfo *ofpinfo;
1030
1031 ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1032 quals = ofpinfo->remote_conds;
1033 }
1034 else
1035 quals = remote_conds;
1036
1037 /* Construct FROM and WHERE clauses */
1038 deparseFromExpr(quals, &context);
1039
1040 if (IS_UPPER_REL(rel))
1041 {
1042 /* Append GROUP BY clause */
1043 appendGroupByClause(tlist, &context);
1044
1045 /* Append HAVING clause */
1046 if (remote_conds)
1047 {
1048 appendStringInfoString(buf, " HAVING ");
1049 appendConditions(remote_conds, &context);
1050 }
1051 }
1052
1053 /* Add ORDER BY clause if we found any useful pathkeys */
1054 if (pathkeys)
1055 appendOrderByClause(pathkeys, has_final_sort, &context);
1056
1057 /* Add LIMIT clause if necessary */
1058 if (has_limit)
1059 appendLimitClause(&context);
1060
1061 /* Add any necessary FOR UPDATE/SHARE. */
1062 deparseLockingClause(&context);
1063 }
1064
1065 /*
1066 * Construct a simple SELECT statement that retrieves desired columns
1067 * of the specified foreign table, and append it to "buf". The output
1068 * contains just "SELECT ... ".
1069 *
1070 * We also create an integer List of the columns being retrieved, which is
1071 * returned to *retrieved_attrs, unless we deparse the specified relation
1072 * as a subquery.
1073 *
1074 * tlist is the list of desired columns. is_subquery is the flag to
1075 * indicate whether to deparse the specified relation as a subquery.
1076 * Read prologue of deparseSelectStmtForRel() for details.
1077 */
1078 static void
deparseSelectSql(List * tlist,bool is_subquery,List ** retrieved_attrs,deparse_expr_cxt * context)1079 deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
1080 deparse_expr_cxt *context)
1081 {
1082 StringInfo buf = context->buf;
1083 RelOptInfo *foreignrel = context->foreignrel;
1084 PlannerInfo *root = context->root;
1085 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1086
1087 /*
1088 * Construct SELECT list
1089 */
1090 appendStringInfoString(buf, "SELECT ");
1091
1092 if (is_subquery)
1093 {
1094 /*
1095 * For a relation that is deparsed as a subquery, emit expressions
1096 * specified in the relation's reltarget. Note that since this is for
1097 * the subquery, no need to care about *retrieved_attrs.
1098 */
1099 deparseSubqueryTargetList(context);
1100 }
1101 else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1102 {
1103 /*
1104 * For a join or upper relation the input tlist gives the list of
1105 * columns required to be fetched from the foreign server.
1106 */
1107 deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1108 }
1109 else
1110 {
1111 /*
1112 * For a base relation fpinfo->attrs_used gives the list of columns
1113 * required to be fetched from the foreign server.
1114 */
1115 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1116
1117 /*
1118 * Core code already has some lock on each rel being planned, so we
1119 * can use NoLock here.
1120 */
1121 Relation rel = table_open(rte->relid, NoLock);
1122
1123 deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1124 fpinfo->attrs_used, false, retrieved_attrs);
1125 table_close(rel, NoLock);
1126 }
1127 }
1128
1129 /*
1130 * Construct a FROM clause and, if needed, a WHERE clause, and append those to
1131 * "buf".
1132 *
1133 * quals is the list of clauses to be included in the WHERE clause.
1134 * (These may or may not include RestrictInfo decoration.)
1135 */
1136 static void
deparseFromExpr(List * quals,deparse_expr_cxt * context)1137 deparseFromExpr(List *quals, deparse_expr_cxt *context)
1138 {
1139 StringInfo buf = context->buf;
1140 RelOptInfo *scanrel = context->scanrel;
1141
1142 /* For upper relations, scanrel must be either a joinrel or a baserel */
1143 Assert(!IS_UPPER_REL(context->foreignrel) ||
1144 IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1145
1146 /* Construct FROM clause */
1147 appendStringInfoString(buf, " FROM ");
1148 deparseFromExprForRel(buf, context->root, scanrel,
1149 (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1150 (Index) 0, NULL, context->params_list);
1151
1152 /* Construct WHERE clause */
1153 if (quals != NIL)
1154 {
1155 appendStringInfoString(buf, " WHERE ");
1156 appendConditions(quals, context);
1157 }
1158 }
1159
1160 /*
1161 * Emit a target list that retrieves the columns specified in attrs_used.
1162 * This is used for both SELECT and RETURNING targetlists; the is_returning
1163 * parameter is true only for a RETURNING targetlist.
1164 *
1165 * The tlist text is appended to buf, and we also create an integer List
1166 * of the columns being retrieved, which is returned to *retrieved_attrs.
1167 *
1168 * If qualify_col is true, add relation alias before the column name.
1169 */
1170 static void
deparseTargetList(StringInfo buf,RangeTblEntry * rte,Index rtindex,Relation rel,bool is_returning,Bitmapset * attrs_used,bool qualify_col,List ** retrieved_attrs)1171 deparseTargetList(StringInfo buf,
1172 RangeTblEntry *rte,
1173 Index rtindex,
1174 Relation rel,
1175 bool is_returning,
1176 Bitmapset *attrs_used,
1177 bool qualify_col,
1178 List **retrieved_attrs)
1179 {
1180 TupleDesc tupdesc = RelationGetDescr(rel);
1181 bool have_wholerow;
1182 bool first;
1183 int i;
1184
1185 *retrieved_attrs = NIL;
1186
1187 /* If there's a whole-row reference, we'll need all the columns. */
1188 have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
1189 attrs_used);
1190
1191 first = true;
1192 for (i = 1; i <= tupdesc->natts; i++)
1193 {
1194 Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
1195
1196 /* Ignore dropped attributes. */
1197 if (attr->attisdropped)
1198 continue;
1199
1200 if (have_wholerow ||
1201 bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
1202 attrs_used))
1203 {
1204 if (!first)
1205 appendStringInfoString(buf, ", ");
1206 else if (is_returning)
1207 appendStringInfoString(buf, " RETURNING ");
1208 first = false;
1209
1210 deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1211
1212 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1213 }
1214 }
1215
1216 /*
1217 * Add ctid if needed. We currently don't support retrieving any other
1218 * system columns.
1219 */
1220 if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber,
1221 attrs_used))
1222 {
1223 if (!first)
1224 appendStringInfoString(buf, ", ");
1225 else if (is_returning)
1226 appendStringInfoString(buf, " RETURNING ");
1227 first = false;
1228
1229 if (qualify_col)
1230 ADD_REL_QUALIFIER(buf, rtindex);
1231 appendStringInfoString(buf, "ctid");
1232
1233 *retrieved_attrs = lappend_int(*retrieved_attrs,
1234 SelfItemPointerAttributeNumber);
1235 }
1236
1237 /* Don't generate bad syntax if no undropped columns */
1238 if (first && !is_returning)
1239 appendStringInfoString(buf, "NULL");
1240 }
1241
1242 /*
1243 * Deparse the appropriate locking clause (FOR UPDATE or FOR SHARE) for a
1244 * given relation (context->scanrel).
1245 */
1246 static void
deparseLockingClause(deparse_expr_cxt * context)1247 deparseLockingClause(deparse_expr_cxt *context)
1248 {
1249 StringInfo buf = context->buf;
1250 PlannerInfo *root = context->root;
1251 RelOptInfo *rel = context->scanrel;
1252 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1253 int relid = -1;
1254
1255 while ((relid = bms_next_member(rel->relids, relid)) >= 0)
1256 {
1257 /*
1258 * Ignore relation if it appears in a lower subquery. Locking clause
1259 * for such a relation is included in the subquery if necessary.
1260 */
1261 if (bms_is_member(relid, fpinfo->lower_subquery_rels))
1262 continue;
1263
1264 /*
1265 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1266 * initial row fetch, rather than later on as is done for local
1267 * tables. The extra roundtrips involved in trying to duplicate the
1268 * local semantics exactly don't seem worthwhile (see also comments
1269 * for RowMarkType).
1270 *
1271 * Note: because we actually run the query as a cursor, this assumes
1272 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1273 * before 8.3.
1274 */
1275 if (relid == root->parse->resultRelation &&
1276 (root->parse->commandType == CMD_UPDATE ||
1277 root->parse->commandType == CMD_DELETE))
1278 {
1279 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1280 appendStringInfoString(buf, " FOR UPDATE");
1281
1282 /* Add the relation alias if we are here for a join relation */
1283 if (IS_JOIN_REL(rel))
1284 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1285 }
1286 else
1287 {
1288 PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
1289
1290 if (rc)
1291 {
1292 /*
1293 * Relation is specified as a FOR UPDATE/SHARE target, so
1294 * handle that. (But we could also see LCS_NONE, meaning this
1295 * isn't a target relation after all.)
1296 *
1297 * For now, just ignore any [NO] KEY specification, since (a)
1298 * it's not clear what that means for a remote table that we
1299 * don't have complete information about, and (b) it wouldn't
1300 * work anyway on older remote servers. Likewise, we don't
1301 * worry about NOWAIT.
1302 */
1303 switch (rc->strength)
1304 {
1305 case LCS_NONE:
1306 /* No locking needed */
1307 break;
1308 case LCS_FORKEYSHARE:
1309 case LCS_FORSHARE:
1310 appendStringInfoString(buf, " FOR SHARE");
1311 break;
1312 case LCS_FORNOKEYUPDATE:
1313 case LCS_FORUPDATE:
1314 appendStringInfoString(buf, " FOR UPDATE");
1315 break;
1316 }
1317
1318 /* Add the relation alias if we are here for a join relation */
1319 if (bms_membership(rel->relids) == BMS_MULTIPLE &&
1320 rc->strength != LCS_NONE)
1321 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1322 }
1323 }
1324 }
1325 }
1326
1327 /*
1328 * Deparse conditions from the provided list and append them to buf.
1329 *
1330 * The conditions in the list are assumed to be ANDed. This function is used to
1331 * deparse WHERE clauses, JOIN .. ON clauses and HAVING clauses.
1332 *
1333 * Depending on the caller, the list elements might be either RestrictInfos
1334 * or bare clauses.
1335 */
1336 static void
appendConditions(List * exprs,deparse_expr_cxt * context)1337 appendConditions(List *exprs, deparse_expr_cxt *context)
1338 {
1339 int nestlevel;
1340 ListCell *lc;
1341 bool is_first = true;
1342 StringInfo buf = context->buf;
1343
1344 /* Make sure any constants in the exprs are printed portably */
1345 nestlevel = set_transmission_modes();
1346
1347 foreach(lc, exprs)
1348 {
1349 Expr *expr = (Expr *) lfirst(lc);
1350
1351 /* Extract clause from RestrictInfo, if required */
1352 if (IsA(expr, RestrictInfo))
1353 expr = ((RestrictInfo *) expr)->clause;
1354
1355 /* Connect expressions with "AND" and parenthesize each condition. */
1356 if (!is_first)
1357 appendStringInfoString(buf, " AND ");
1358
1359 appendStringInfoChar(buf, '(');
1360 deparseExpr(expr, context);
1361 appendStringInfoChar(buf, ')');
1362
1363 is_first = false;
1364 }
1365
1366 reset_transmission_modes(nestlevel);
1367 }
1368
1369 /* Output join name for given join type */
1370 const char *
get_jointype_name(JoinType jointype)1371 get_jointype_name(JoinType jointype)
1372 {
1373 switch (jointype)
1374 {
1375 case JOIN_INNER:
1376 return "INNER";
1377
1378 case JOIN_LEFT:
1379 return "LEFT";
1380
1381 case JOIN_RIGHT:
1382 return "RIGHT";
1383
1384 case JOIN_FULL:
1385 return "FULL";
1386
1387 default:
1388 /* Shouldn't come here, but protect from buggy code. */
1389 elog(ERROR, "unsupported join type %d", jointype);
1390 }
1391
1392 /* Keep compiler happy */
1393 return NULL;
1394 }
1395
1396 /*
1397 * Deparse given targetlist and append it to context->buf.
1398 *
1399 * tlist is list of TargetEntry's which in turn contain Var nodes.
1400 *
1401 * retrieved_attrs is the list of continuously increasing integers starting
1402 * from 1. It has same number of entries as tlist.
1403 *
1404 * This is used for both SELECT and RETURNING targetlists; the is_returning
1405 * parameter is true only for a RETURNING targetlist.
1406 */
1407 static void
deparseExplicitTargetList(List * tlist,bool is_returning,List ** retrieved_attrs,deparse_expr_cxt * context)1408 deparseExplicitTargetList(List *tlist,
1409 bool is_returning,
1410 List **retrieved_attrs,
1411 deparse_expr_cxt *context)
1412 {
1413 ListCell *lc;
1414 StringInfo buf = context->buf;
1415 int i = 0;
1416
1417 *retrieved_attrs = NIL;
1418
1419 foreach(lc, tlist)
1420 {
1421 TargetEntry *tle = lfirst_node(TargetEntry, lc);
1422
1423 if (i > 0)
1424 appendStringInfoString(buf, ", ");
1425 else if (is_returning)
1426 appendStringInfoString(buf, " RETURNING ");
1427
1428 deparseExpr((Expr *) tle->expr, context);
1429
1430 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1431 i++;
1432 }
1433
1434 if (i == 0 && !is_returning)
1435 appendStringInfoString(buf, "NULL");
1436 }
1437
1438 /*
1439 * Emit expressions specified in the given relation's reltarget.
1440 *
1441 * This is used for deparsing the given relation as a subquery.
1442 */
1443 static void
deparseSubqueryTargetList(deparse_expr_cxt * context)1444 deparseSubqueryTargetList(deparse_expr_cxt *context)
1445 {
1446 StringInfo buf = context->buf;
1447 RelOptInfo *foreignrel = context->foreignrel;
1448 bool first;
1449 ListCell *lc;
1450
1451 /* Should only be called in these cases. */
1452 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1453
1454 first = true;
1455 foreach(lc, foreignrel->reltarget->exprs)
1456 {
1457 Node *node = (Node *) lfirst(lc);
1458
1459 if (!first)
1460 appendStringInfoString(buf, ", ");
1461 first = false;
1462
1463 deparseExpr((Expr *) node, context);
1464 }
1465
1466 /* Don't generate bad syntax if no expressions */
1467 if (first)
1468 appendStringInfoString(buf, "NULL");
1469 }
1470
1471 /*
1472 * Construct FROM clause for given relation
1473 *
1474 * The function constructs ... JOIN ... ON ... for join relation. For a base
1475 * relation it just returns schema-qualified tablename, with the appropriate
1476 * alias if so requested.
1477 *
1478 * 'ignore_rel' is either zero or the RT index of a target relation. In the
1479 * latter case the function constructs FROM clause of UPDATE or USING clause
1480 * of DELETE; it deparses the join relation as if the relation never contained
1481 * the target relation, and creates a List of conditions to be deparsed into
1482 * the top-level WHERE clause, which is returned to *ignore_conds.
1483 */
1484 static void
deparseFromExprForRel(StringInfo buf,PlannerInfo * root,RelOptInfo * foreignrel,bool use_alias,Index ignore_rel,List ** ignore_conds,List ** params_list)1485 deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1486 bool use_alias, Index ignore_rel, List **ignore_conds,
1487 List **params_list)
1488 {
1489 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1490
1491 if (IS_JOIN_REL(foreignrel))
1492 {
1493 StringInfoData join_sql_o;
1494 StringInfoData join_sql_i;
1495 RelOptInfo *outerrel = fpinfo->outerrel;
1496 RelOptInfo *innerrel = fpinfo->innerrel;
1497 bool outerrel_is_target = false;
1498 bool innerrel_is_target = false;
1499
1500 if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1501 {
1502 /*
1503 * If this is an inner join, add joinclauses to *ignore_conds and
1504 * set it to empty so that those can be deparsed into the WHERE
1505 * clause. Note that since the target relation can never be
1506 * within the nullable side of an outer join, those could safely
1507 * be pulled up into the WHERE clause (see foreign_join_ok()).
1508 * Note also that since the target relation is only inner-joined
1509 * to any other relation in the query, all conditions in the join
1510 * tree mentioning the target relation could be deparsed into the
1511 * WHERE clause by doing this recursively.
1512 */
1513 if (fpinfo->jointype == JOIN_INNER)
1514 {
1515 *ignore_conds = list_concat(*ignore_conds,
1516 list_copy(fpinfo->joinclauses));
1517 fpinfo->joinclauses = NIL;
1518 }
1519
1520 /*
1521 * Check if either of the input relations is the target relation.
1522 */
1523 if (outerrel->relid == ignore_rel)
1524 outerrel_is_target = true;
1525 else if (innerrel->relid == ignore_rel)
1526 innerrel_is_target = true;
1527 }
1528
1529 /* Deparse outer relation if not the target relation. */
1530 if (!outerrel_is_target)
1531 {
1532 initStringInfo(&join_sql_o);
1533 deparseRangeTblRef(&join_sql_o, root, outerrel,
1534 fpinfo->make_outerrel_subquery,
1535 ignore_rel, ignore_conds, params_list);
1536
1537 /*
1538 * If inner relation is the target relation, skip deparsing it.
1539 * Note that since the join of the target relation with any other
1540 * relation in the query is an inner join and can never be within
1541 * the nullable side of an outer join, the join could be
1542 * interchanged with higher-level joins (cf. identity 1 on outer
1543 * join reordering shown in src/backend/optimizer/README), which
1544 * means it's safe to skip the target-relation deparsing here.
1545 */
1546 if (innerrel_is_target)
1547 {
1548 Assert(fpinfo->jointype == JOIN_INNER);
1549 Assert(fpinfo->joinclauses == NIL);
1550 appendStringInfo(buf, "%s", join_sql_o.data);
1551 return;
1552 }
1553 }
1554
1555 /* Deparse inner relation if not the target relation. */
1556 if (!innerrel_is_target)
1557 {
1558 initStringInfo(&join_sql_i);
1559 deparseRangeTblRef(&join_sql_i, root, innerrel,
1560 fpinfo->make_innerrel_subquery,
1561 ignore_rel, ignore_conds, params_list);
1562
1563 /*
1564 * If outer relation is the target relation, skip deparsing it.
1565 * See the above note about safety.
1566 */
1567 if (outerrel_is_target)
1568 {
1569 Assert(fpinfo->jointype == JOIN_INNER);
1570 Assert(fpinfo->joinclauses == NIL);
1571 appendStringInfo(buf, "%s", join_sql_i.data);
1572 return;
1573 }
1574 }
1575
1576 /* Neither of the relations is the target relation. */
1577 Assert(!outerrel_is_target && !innerrel_is_target);
1578
1579 /*
1580 * For a join relation FROM clause entry is deparsed as
1581 *
1582 * ((outer relation) <join type> (inner relation) ON (joinclauses))
1583 */
1584 appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1585 get_jointype_name(fpinfo->jointype), join_sql_i.data);
1586
1587 /* Append join clause; (TRUE) if no join clause */
1588 if (fpinfo->joinclauses)
1589 {
1590 deparse_expr_cxt context;
1591
1592 context.buf = buf;
1593 context.foreignrel = foreignrel;
1594 context.scanrel = foreignrel;
1595 context.root = root;
1596 context.params_list = params_list;
1597
1598 appendStringInfoChar(buf, '(');
1599 appendConditions(fpinfo->joinclauses, &context);
1600 appendStringInfoChar(buf, ')');
1601 }
1602 else
1603 appendStringInfoString(buf, "(TRUE)");
1604
1605 /* End the FROM clause entry. */
1606 appendStringInfoChar(buf, ')');
1607 }
1608 else
1609 {
1610 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1611
1612 /*
1613 * Core code already has some lock on each rel being planned, so we
1614 * can use NoLock here.
1615 */
1616 Relation rel = table_open(rte->relid, NoLock);
1617
1618 deparseRelation(buf, rel);
1619
1620 /*
1621 * Add a unique alias to avoid any conflict in relation names due to
1622 * pulled up subqueries in the query being built for a pushed down
1623 * join.
1624 */
1625 if (use_alias)
1626 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
1627
1628 table_close(rel, NoLock);
1629 }
1630 }
1631
1632 /*
1633 * Append FROM clause entry for the given relation into buf.
1634 */
1635 static void
deparseRangeTblRef(StringInfo buf,PlannerInfo * root,RelOptInfo * foreignrel,bool make_subquery,Index ignore_rel,List ** ignore_conds,List ** params_list)1636 deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1637 bool make_subquery, Index ignore_rel, List **ignore_conds,
1638 List **params_list)
1639 {
1640 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1641
1642 /* Should only be called in these cases. */
1643 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1644
1645 Assert(fpinfo->local_conds == NIL);
1646
1647 /* If make_subquery is true, deparse the relation as a subquery. */
1648 if (make_subquery)
1649 {
1650 List *retrieved_attrs;
1651 int ncols;
1652
1653 /*
1654 * The given relation shouldn't contain the target relation, because
1655 * this should only happen for input relations for a full join, and
1656 * such relations can never contain an UPDATE/DELETE target.
1657 */
1658 Assert(ignore_rel == 0 ||
1659 !bms_is_member(ignore_rel, foreignrel->relids));
1660
1661 /* Deparse the subquery representing the relation. */
1662 appendStringInfoChar(buf, '(');
1663 deparseSelectStmtForRel(buf, root, foreignrel, NIL,
1664 fpinfo->remote_conds, NIL,
1665 false, false, true,
1666 &retrieved_attrs, params_list);
1667 appendStringInfoChar(buf, ')');
1668
1669 /* Append the relation alias. */
1670 appendStringInfo(buf, " %s%d", SUBQUERY_REL_ALIAS_PREFIX,
1671 fpinfo->relation_index);
1672
1673 /*
1674 * Append the column aliases if needed. Note that the subquery emits
1675 * expressions specified in the relation's reltarget (see
1676 * deparseSubqueryTargetList).
1677 */
1678 ncols = list_length(foreignrel->reltarget->exprs);
1679 if (ncols > 0)
1680 {
1681 int i;
1682
1683 appendStringInfoChar(buf, '(');
1684 for (i = 1; i <= ncols; i++)
1685 {
1686 if (i > 1)
1687 appendStringInfoString(buf, ", ");
1688
1689 appendStringInfo(buf, "%s%d", SUBQUERY_COL_ALIAS_PREFIX, i);
1690 }
1691 appendStringInfoChar(buf, ')');
1692 }
1693 }
1694 else
1695 deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
1696 ignore_conds, params_list);
1697 }
1698
1699 /*
1700 * deparse remote INSERT statement
1701 *
1702 * The statement text is appended to buf, and we also create an integer List
1703 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
1704 * which is returned to *retrieved_attrs.
1705 */
1706 void
deparseInsertSql(StringInfo buf,RangeTblEntry * rte,Index rtindex,Relation rel,List * targetAttrs,bool doNothing,List * withCheckOptionList,List * returningList,List ** retrieved_attrs)1707 deparseInsertSql(StringInfo buf, RangeTblEntry *rte,
1708 Index rtindex, Relation rel,
1709 List *targetAttrs, bool doNothing,
1710 List *withCheckOptionList, List *returningList,
1711 List **retrieved_attrs)
1712 {
1713 TupleDesc tupdesc = RelationGetDescr(rel);
1714 AttrNumber pindex;
1715 bool first;
1716 ListCell *lc;
1717
1718 appendStringInfoString(buf, "INSERT INTO ");
1719 deparseRelation(buf, rel);
1720
1721 if (targetAttrs)
1722 {
1723 appendStringInfoChar(buf, '(');
1724
1725 first = true;
1726 foreach(lc, targetAttrs)
1727 {
1728 int attnum = lfirst_int(lc);
1729
1730 if (!first)
1731 appendStringInfoString(buf, ", ");
1732 first = false;
1733
1734 deparseColumnRef(buf, rtindex, attnum, rte, false);
1735 }
1736
1737 appendStringInfoString(buf, ") VALUES (");
1738
1739 pindex = 1;
1740 first = true;
1741 foreach(lc, targetAttrs)
1742 {
1743 int attnum = lfirst_int(lc);
1744 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1745
1746 if (!first)
1747 appendStringInfoString(buf, ", ");
1748 first = false;
1749
1750 if (attr->attgenerated)
1751 appendStringInfoString(buf, "DEFAULT");
1752 else
1753 {
1754 appendStringInfo(buf, "$%d", pindex);
1755 pindex++;
1756 }
1757 }
1758
1759 appendStringInfoChar(buf, ')');
1760 }
1761 else
1762 appendStringInfoString(buf, " DEFAULT VALUES");
1763
1764 if (doNothing)
1765 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
1766
1767 deparseReturningList(buf, rte, rtindex, rel,
1768 rel->trigdesc && rel->trigdesc->trig_insert_after_row,
1769 withCheckOptionList, returningList, retrieved_attrs);
1770 }
1771
1772 /*
1773 * deparse remote UPDATE statement
1774 *
1775 * The statement text is appended to buf, and we also create an integer List
1776 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
1777 * which is returned to *retrieved_attrs.
1778 */
1779 void
deparseUpdateSql(StringInfo buf,RangeTblEntry * rte,Index rtindex,Relation rel,List * targetAttrs,List * withCheckOptionList,List * returningList,List ** retrieved_attrs)1780 deparseUpdateSql(StringInfo buf, RangeTblEntry *rte,
1781 Index rtindex, Relation rel,
1782 List *targetAttrs,
1783 List *withCheckOptionList, List *returningList,
1784 List **retrieved_attrs)
1785 {
1786 TupleDesc tupdesc = RelationGetDescr(rel);
1787 AttrNumber pindex;
1788 bool first;
1789 ListCell *lc;
1790
1791 appendStringInfoString(buf, "UPDATE ");
1792 deparseRelation(buf, rel);
1793 appendStringInfoString(buf, " SET ");
1794
1795 pindex = 2; /* ctid is always the first param */
1796 first = true;
1797 foreach(lc, targetAttrs)
1798 {
1799 int attnum = lfirst_int(lc);
1800 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1801
1802 if (!first)
1803 appendStringInfoString(buf, ", ");
1804 first = false;
1805
1806 deparseColumnRef(buf, rtindex, attnum, rte, false);
1807 if (attr->attgenerated)
1808 appendStringInfoString(buf, " = DEFAULT");
1809 else
1810 {
1811 appendStringInfo(buf, " = $%d", pindex);
1812 pindex++;
1813 }
1814 }
1815 appendStringInfoString(buf, " WHERE ctid = $1");
1816
1817 deparseReturningList(buf, rte, rtindex, rel,
1818 rel->trigdesc && rel->trigdesc->trig_update_after_row,
1819 withCheckOptionList, returningList, retrieved_attrs);
1820 }
1821
1822 /*
1823 * deparse remote UPDATE statement
1824 *
1825 * 'buf' is the output buffer to append the statement to
1826 * 'rtindex' is the RT index of the associated target relation
1827 * 'rel' is the relation descriptor for the target relation
1828 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
1829 * containing all base relations in the query
1830 * 'targetlist' is the tlist of the underlying foreign-scan plan node
1831 * 'targetAttrs' is the target columns of the UPDATE
1832 * 'remote_conds' is the qual clauses that must be evaluated remotely
1833 * '*params_list' is an output list of exprs that will become remote Params
1834 * 'returningList' is the RETURNING targetlist
1835 * '*retrieved_attrs' is an output list of integers of columns being retrieved
1836 * by RETURNING (if any)
1837 */
1838 void
deparseDirectUpdateSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,RelOptInfo * foreignrel,List * targetlist,List * targetAttrs,List * remote_conds,List ** params_list,List * returningList,List ** retrieved_attrs)1839 deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
1840 Index rtindex, Relation rel,
1841 RelOptInfo *foreignrel,
1842 List *targetlist,
1843 List *targetAttrs,
1844 List *remote_conds,
1845 List **params_list,
1846 List *returningList,
1847 List **retrieved_attrs)
1848 {
1849 deparse_expr_cxt context;
1850 int nestlevel;
1851 bool first;
1852 ListCell *lc;
1853 RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
1854
1855 /* Set up context struct for recursion */
1856 context.root = root;
1857 context.foreignrel = foreignrel;
1858 context.scanrel = foreignrel;
1859 context.buf = buf;
1860 context.params_list = params_list;
1861
1862 appendStringInfoString(buf, "UPDATE ");
1863 deparseRelation(buf, rel);
1864 if (foreignrel->reloptkind == RELOPT_JOINREL)
1865 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
1866 appendStringInfoString(buf, " SET ");
1867
1868 /* Make sure any constants in the exprs are printed portably */
1869 nestlevel = set_transmission_modes();
1870
1871 first = true;
1872 foreach(lc, targetAttrs)
1873 {
1874 int attnum = lfirst_int(lc);
1875 TargetEntry *tle = get_tle_by_resno(targetlist, attnum);
1876
1877 if (!tle)
1878 elog(ERROR, "attribute number %d not found in UPDATE targetlist",
1879 attnum);
1880
1881 if (!first)
1882 appendStringInfoString(buf, ", ");
1883 first = false;
1884
1885 deparseColumnRef(buf, rtindex, attnum, rte, false);
1886 appendStringInfoString(buf, " = ");
1887 deparseExpr((Expr *) tle->expr, &context);
1888 }
1889
1890 reset_transmission_modes(nestlevel);
1891
1892 if (foreignrel->reloptkind == RELOPT_JOINREL)
1893 {
1894 List *ignore_conds = NIL;
1895
1896 appendStringInfo(buf, " FROM ");
1897 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
1898 &ignore_conds, params_list);
1899 remote_conds = list_concat(remote_conds, ignore_conds);
1900 }
1901
1902 if (remote_conds)
1903 {
1904 appendStringInfoString(buf, " WHERE ");
1905 appendConditions(remote_conds, &context);
1906 }
1907
1908 if (foreignrel->reloptkind == RELOPT_JOINREL)
1909 deparseExplicitTargetList(returningList, true, retrieved_attrs,
1910 &context);
1911 else
1912 deparseReturningList(buf, rte, rtindex, rel, false,
1913 NIL, returningList, retrieved_attrs);
1914 }
1915
1916 /*
1917 * deparse remote DELETE statement
1918 *
1919 * The statement text is appended to buf, and we also create an integer List
1920 * of the columns being retrieved by RETURNING (if any), which is returned
1921 * to *retrieved_attrs.
1922 */
1923 void
deparseDeleteSql(StringInfo buf,RangeTblEntry * rte,Index rtindex,Relation rel,List * returningList,List ** retrieved_attrs)1924 deparseDeleteSql(StringInfo buf, RangeTblEntry *rte,
1925 Index rtindex, Relation rel,
1926 List *returningList,
1927 List **retrieved_attrs)
1928 {
1929 appendStringInfoString(buf, "DELETE FROM ");
1930 deparseRelation(buf, rel);
1931 appendStringInfoString(buf, " WHERE ctid = $1");
1932
1933 deparseReturningList(buf, rte, rtindex, rel,
1934 rel->trigdesc && rel->trigdesc->trig_delete_after_row,
1935 NIL, returningList, retrieved_attrs);
1936 }
1937
1938 /*
1939 * deparse remote DELETE statement
1940 *
1941 * 'buf' is the output buffer to append the statement to
1942 * 'rtindex' is the RT index of the associated target relation
1943 * 'rel' is the relation descriptor for the target relation
1944 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
1945 * containing all base relations in the query
1946 * 'remote_conds' is the qual clauses that must be evaluated remotely
1947 * '*params_list' is an output list of exprs that will become remote Params
1948 * 'returningList' is the RETURNING targetlist
1949 * '*retrieved_attrs' is an output list of integers of columns being retrieved
1950 * by RETURNING (if any)
1951 */
1952 void
deparseDirectDeleteSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,RelOptInfo * foreignrel,List * remote_conds,List ** params_list,List * returningList,List ** retrieved_attrs)1953 deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
1954 Index rtindex, Relation rel,
1955 RelOptInfo *foreignrel,
1956 List *remote_conds,
1957 List **params_list,
1958 List *returningList,
1959 List **retrieved_attrs)
1960 {
1961 deparse_expr_cxt context;
1962
1963 /* Set up context struct for recursion */
1964 context.root = root;
1965 context.foreignrel = foreignrel;
1966 context.scanrel = foreignrel;
1967 context.buf = buf;
1968 context.params_list = params_list;
1969
1970 appendStringInfoString(buf, "DELETE FROM ");
1971 deparseRelation(buf, rel);
1972 if (foreignrel->reloptkind == RELOPT_JOINREL)
1973 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
1974
1975 if (foreignrel->reloptkind == RELOPT_JOINREL)
1976 {
1977 List *ignore_conds = NIL;
1978
1979 appendStringInfo(buf, " USING ");
1980 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
1981 &ignore_conds, params_list);
1982 remote_conds = list_concat(remote_conds, ignore_conds);
1983 }
1984
1985 if (remote_conds)
1986 {
1987 appendStringInfoString(buf, " WHERE ");
1988 appendConditions(remote_conds, &context);
1989 }
1990
1991 if (foreignrel->reloptkind == RELOPT_JOINREL)
1992 deparseExplicitTargetList(returningList, true, retrieved_attrs,
1993 &context);
1994 else
1995 deparseReturningList(buf, planner_rt_fetch(rtindex, root),
1996 rtindex, rel, false,
1997 NIL, returningList, retrieved_attrs);
1998 }
1999
2000 /*
2001 * Add a RETURNING clause, if needed, to an INSERT/UPDATE/DELETE.
2002 */
2003 static void
deparseReturningList(StringInfo buf,RangeTblEntry * rte,Index rtindex,Relation rel,bool trig_after_row,List * withCheckOptionList,List * returningList,List ** retrieved_attrs)2004 deparseReturningList(StringInfo buf, RangeTblEntry *rte,
2005 Index rtindex, Relation rel,
2006 bool trig_after_row,
2007 List *withCheckOptionList,
2008 List *returningList,
2009 List **retrieved_attrs)
2010 {
2011 Bitmapset *attrs_used = NULL;
2012
2013 if (trig_after_row)
2014 {
2015 /* whole-row reference acquires all non-system columns */
2016 attrs_used =
2017 bms_make_singleton(0 - FirstLowInvalidHeapAttributeNumber);
2018 }
2019
2020 if (withCheckOptionList != NIL)
2021 {
2022 /*
2023 * We need the attrs, non-system and system, mentioned in the local
2024 * query's WITH CHECK OPTION list.
2025 *
2026 * Note: we do this to ensure that WCO constraints will be evaluated
2027 * on the data actually inserted/updated on the remote side, which
2028 * might differ from the data supplied by the core code, for example
2029 * as a result of remote triggers.
2030 */
2031 pull_varattnos((Node *) withCheckOptionList, rtindex,
2032 &attrs_used);
2033 }
2034
2035 if (returningList != NIL)
2036 {
2037 /*
2038 * We need the attrs, non-system and system, mentioned in the local
2039 * query's RETURNING list.
2040 */
2041 pull_varattnos((Node *) returningList, rtindex,
2042 &attrs_used);
2043 }
2044
2045 if (attrs_used != NULL)
2046 deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2047 retrieved_attrs);
2048 else
2049 *retrieved_attrs = NIL;
2050 }
2051
2052 /*
2053 * Construct SELECT statement to acquire size in blocks of given relation.
2054 *
2055 * Note: we use local definition of block size, not remote definition.
2056 * This is perhaps debatable.
2057 *
2058 * Note: pg_relation_size() exists in 8.1 and later.
2059 */
2060 void
deparseAnalyzeSizeSql(StringInfo buf,Relation rel)2061 deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
2062 {
2063 StringInfoData relname;
2064
2065 /* We'll need the remote relation name as a literal. */
2066 initStringInfo(&relname);
2067 deparseRelation(&relname, rel);
2068
2069 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2070 deparseStringLiteral(buf, relname.data);
2071 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2072 }
2073
2074 /*
2075 * Construct SELECT statement to acquire sample rows of given relation.
2076 *
2077 * SELECT command is appended to buf, and list of columns retrieved
2078 * is returned to *retrieved_attrs.
2079 */
2080 void
deparseAnalyzeSql(StringInfo buf,Relation rel,List ** retrieved_attrs)2081 deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
2082 {
2083 Oid relid = RelationGetRelid(rel);
2084 TupleDesc tupdesc = RelationGetDescr(rel);
2085 int i;
2086 char *colname;
2087 List *options;
2088 ListCell *lc;
2089 bool first = true;
2090
2091 *retrieved_attrs = NIL;
2092
2093 appendStringInfoString(buf, "SELECT ");
2094 for (i = 0; i < tupdesc->natts; i++)
2095 {
2096 /* Ignore dropped columns. */
2097 if (TupleDescAttr(tupdesc, i)->attisdropped)
2098 continue;
2099
2100 if (!first)
2101 appendStringInfoString(buf, ", ");
2102 first = false;
2103
2104 /* Use attribute name or column_name option. */
2105 colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2106 options = GetForeignColumnOptions(relid, i + 1);
2107
2108 foreach(lc, options)
2109 {
2110 DefElem *def = (DefElem *) lfirst(lc);
2111
2112 if (strcmp(def->defname, "column_name") == 0)
2113 {
2114 colname = defGetString(def);
2115 break;
2116 }
2117 }
2118
2119 appendStringInfoString(buf, quote_identifier(colname));
2120
2121 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2122 }
2123
2124 /* Don't generate bad syntax for zero-column relation. */
2125 if (first)
2126 appendStringInfoString(buf, "NULL");
2127
2128 /*
2129 * Construct FROM clause
2130 */
2131 appendStringInfoString(buf, " FROM ");
2132 deparseRelation(buf, rel);
2133 }
2134
2135 /*
2136 * Construct name to use for given column, and emit it into buf.
2137 * If it has a column_name FDW option, use that instead of attribute name.
2138 *
2139 * If qualify_col is true, qualify column name with the alias of relation.
2140 */
2141 static void
deparseColumnRef(StringInfo buf,int varno,int varattno,RangeTblEntry * rte,bool qualify_col)2142 deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte,
2143 bool qualify_col)
2144 {
2145 /* We support fetching the remote side's CTID and OID. */
2146 if (varattno == SelfItemPointerAttributeNumber)
2147 {
2148 if (qualify_col)
2149 ADD_REL_QUALIFIER(buf, varno);
2150 appendStringInfoString(buf, "ctid");
2151 }
2152 else if (varattno < 0)
2153 {
2154 /*
2155 * All other system attributes are fetched as 0, except for table OID,
2156 * which is fetched as the local table OID. However, we must be
2157 * careful; the table could be beneath an outer join, in which case it
2158 * must go to NULL whenever the rest of the row does.
2159 */
2160 Oid fetchval = 0;
2161
2162 if (varattno == TableOidAttributeNumber)
2163 fetchval = rte->relid;
2164
2165 if (qualify_col)
2166 {
2167 appendStringInfoString(buf, "CASE WHEN (");
2168 ADD_REL_QUALIFIER(buf, varno);
2169 appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2170 }
2171 else
2172 appendStringInfo(buf, "%u", fetchval);
2173 }
2174 else if (varattno == 0)
2175 {
2176 /* Whole row reference */
2177 Relation rel;
2178 Bitmapset *attrs_used;
2179
2180 /* Required only to be passed down to deparseTargetList(). */
2181 List *retrieved_attrs;
2182
2183 /*
2184 * The lock on the relation will be held by upper callers, so it's
2185 * fine to open it with no lock here.
2186 */
2187 rel = table_open(rte->relid, NoLock);
2188
2189 /*
2190 * The local name of the foreign table can not be recognized by the
2191 * foreign server and the table it references on foreign server might
2192 * have different column ordering or different columns than those
2193 * declared locally. Hence we have to deparse whole-row reference as
2194 * ROW(columns referenced locally). Construct this by deparsing a
2195 * "whole row" attribute.
2196 */
2197 attrs_used = bms_add_member(NULL,
2198 0 - FirstLowInvalidHeapAttributeNumber);
2199
2200 /*
2201 * In case the whole-row reference is under an outer join then it has
2202 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2203 * query would always involve multiple relations, thus qualify_col
2204 * would be true.
2205 */
2206 if (qualify_col)
2207 {
2208 appendStringInfoString(buf, "CASE WHEN (");
2209 ADD_REL_QUALIFIER(buf, varno);
2210 appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2211 }
2212
2213 appendStringInfoString(buf, "ROW(");
2214 deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2215 &retrieved_attrs);
2216 appendStringInfoChar(buf, ')');
2217
2218 /* Complete the CASE WHEN statement started above. */
2219 if (qualify_col)
2220 appendStringInfoString(buf, " END");
2221
2222 table_close(rel, NoLock);
2223 bms_free(attrs_used);
2224 }
2225 else
2226 {
2227 char *colname = NULL;
2228 List *options;
2229 ListCell *lc;
2230
2231 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2232 Assert(!IS_SPECIAL_VARNO(varno));
2233
2234 /*
2235 * If it's a column of a foreign table, and it has the column_name FDW
2236 * option, use that value.
2237 */
2238 options = GetForeignColumnOptions(rte->relid, varattno);
2239 foreach(lc, options)
2240 {
2241 DefElem *def = (DefElem *) lfirst(lc);
2242
2243 if (strcmp(def->defname, "column_name") == 0)
2244 {
2245 colname = defGetString(def);
2246 break;
2247 }
2248 }
2249
2250 /*
2251 * If it's a column of a regular table or it doesn't have column_name
2252 * FDW option, use attribute name.
2253 */
2254 if (colname == NULL)
2255 colname = get_attname(rte->relid, varattno, false);
2256
2257 if (qualify_col)
2258 ADD_REL_QUALIFIER(buf, varno);
2259
2260 appendStringInfoString(buf, quote_identifier(colname));
2261 }
2262 }
2263
2264 /*
2265 * Append remote name of specified foreign table to buf.
2266 * Use value of table_name FDW option (if any) instead of relation's name.
2267 * Similarly, schema_name FDW option overrides schema name.
2268 */
2269 static void
deparseRelation(StringInfo buf,Relation rel)2270 deparseRelation(StringInfo buf, Relation rel)
2271 {
2272 ForeignTable *table;
2273 const char *nspname = NULL;
2274 const char *relname = NULL;
2275 ListCell *lc;
2276
2277 /* obtain additional catalog information. */
2278 table = GetForeignTable(RelationGetRelid(rel));
2279
2280 /*
2281 * Use value of FDW options if any, instead of the name of object itself.
2282 */
2283 foreach(lc, table->options)
2284 {
2285 DefElem *def = (DefElem *) lfirst(lc);
2286
2287 if (strcmp(def->defname, "schema_name") == 0)
2288 nspname = defGetString(def);
2289 else if (strcmp(def->defname, "table_name") == 0)
2290 relname = defGetString(def);
2291 }
2292
2293 /*
2294 * Note: we could skip printing the schema name if it's pg_catalog, but
2295 * that doesn't seem worth the trouble.
2296 */
2297 if (nspname == NULL)
2298 nspname = get_namespace_name(RelationGetNamespace(rel));
2299 if (relname == NULL)
2300 relname = RelationGetRelationName(rel);
2301
2302 appendStringInfo(buf, "%s.%s",
2303 quote_identifier(nspname), quote_identifier(relname));
2304 }
2305
2306 /*
2307 * Append a SQL string literal representing "val" to buf.
2308 */
2309 void
deparseStringLiteral(StringInfo buf,const char * val)2310 deparseStringLiteral(StringInfo buf, const char *val)
2311 {
2312 const char *valptr;
2313
2314 /*
2315 * Rather than making assumptions about the remote server's value of
2316 * standard_conforming_strings, always use E'foo' syntax if there are any
2317 * backslashes. This will fail on remote servers before 8.1, but those
2318 * are long out of support.
2319 */
2320 if (strchr(val, '\\') != NULL)
2321 appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
2322 appendStringInfoChar(buf, '\'');
2323 for (valptr = val; *valptr; valptr++)
2324 {
2325 char ch = *valptr;
2326
2327 if (SQL_STR_DOUBLE(ch, true))
2328 appendStringInfoChar(buf, ch);
2329 appendStringInfoChar(buf, ch);
2330 }
2331 appendStringInfoChar(buf, '\'');
2332 }
2333
2334 /*
2335 * Deparse given expression into context->buf.
2336 *
2337 * This function must support all the same node types that foreign_expr_walker
2338 * accepts.
2339 *
2340 * Note: unlike ruleutils.c, we just use a simple hard-wired parenthesization
2341 * scheme: anything more complex than a Var, Const, function call or cast
2342 * should be self-parenthesized.
2343 */
2344 static void
deparseExpr(Expr * node,deparse_expr_cxt * context)2345 deparseExpr(Expr *node, deparse_expr_cxt *context)
2346 {
2347 if (node == NULL)
2348 return;
2349
2350 switch (nodeTag(node))
2351 {
2352 case T_Var:
2353 deparseVar((Var *) node, context);
2354 break;
2355 case T_Const:
2356 deparseConst((Const *) node, context, 0);
2357 break;
2358 case T_Param:
2359 deparseParam((Param *) node, context);
2360 break;
2361 case T_SubscriptingRef:
2362 deparseSubscriptingRef((SubscriptingRef *) node, context);
2363 break;
2364 case T_FuncExpr:
2365 deparseFuncExpr((FuncExpr *) node, context);
2366 break;
2367 case T_OpExpr:
2368 deparseOpExpr((OpExpr *) node, context);
2369 break;
2370 case T_DistinctExpr:
2371 deparseDistinctExpr((DistinctExpr *) node, context);
2372 break;
2373 case T_ScalarArrayOpExpr:
2374 deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
2375 break;
2376 case T_RelabelType:
2377 deparseRelabelType((RelabelType *) node, context);
2378 break;
2379 case T_BoolExpr:
2380 deparseBoolExpr((BoolExpr *) node, context);
2381 break;
2382 case T_NullTest:
2383 deparseNullTest((NullTest *) node, context);
2384 break;
2385 case T_ArrayExpr:
2386 deparseArrayExpr((ArrayExpr *) node, context);
2387 break;
2388 case T_Aggref:
2389 deparseAggref((Aggref *) node, context);
2390 break;
2391 default:
2392 elog(ERROR, "unsupported expression type for deparse: %d",
2393 (int) nodeTag(node));
2394 break;
2395 }
2396 }
2397
2398 /*
2399 * Deparse given Var node into context->buf.
2400 *
2401 * If the Var belongs to the foreign relation, just print its remote name.
2402 * Otherwise, it's effectively a Param (and will in fact be a Param at
2403 * run time). Handle it the same way we handle plain Params --- see
2404 * deparseParam for comments.
2405 */
2406 static void
deparseVar(Var * node,deparse_expr_cxt * context)2407 deparseVar(Var *node, deparse_expr_cxt *context)
2408 {
2409 Relids relids = context->scanrel->relids;
2410 int relno;
2411 int colno;
2412
2413 /* Qualify columns when multiple relations are involved. */
2414 bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2415
2416 /*
2417 * If the Var belongs to the foreign relation that is deparsed as a
2418 * subquery, use the relation and column alias to the Var provided by the
2419 * subquery, instead of the remote name.
2420 */
2421 if (is_subquery_var(node, context->scanrel, &relno, &colno))
2422 {
2423 appendStringInfo(context->buf, "%s%d.%s%d",
2424 SUBQUERY_REL_ALIAS_PREFIX, relno,
2425 SUBQUERY_COL_ALIAS_PREFIX, colno);
2426 return;
2427 }
2428
2429 if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
2430 deparseColumnRef(context->buf, node->varno, node->varattno,
2431 planner_rt_fetch(node->varno, context->root),
2432 qualify_col);
2433 else
2434 {
2435 /* Treat like a Param */
2436 if (context->params_list)
2437 {
2438 int pindex = 0;
2439 ListCell *lc;
2440
2441 /* find its index in params_list */
2442 foreach(lc, *context->params_list)
2443 {
2444 pindex++;
2445 if (equal(node, (Node *) lfirst(lc)))
2446 break;
2447 }
2448 if (lc == NULL)
2449 {
2450 /* not in list, so add it */
2451 pindex++;
2452 *context->params_list = lappend(*context->params_list, node);
2453 }
2454
2455 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
2456 }
2457 else
2458 {
2459 printRemotePlaceholder(node->vartype, node->vartypmod, context);
2460 }
2461 }
2462 }
2463
2464 /*
2465 * Deparse given constant value into context->buf.
2466 *
2467 * This function has to be kept in sync with ruleutils.c's get_const_expr.
2468 * As for that function, showtype can be -1 to never show "::typename" decoration,
2469 * or +1 to always show it, or 0 to show it only if the constant wouldn't be assumed
2470 * to be the right type by default.
2471 */
2472 static void
deparseConst(Const * node,deparse_expr_cxt * context,int showtype)2473 deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
2474 {
2475 StringInfo buf = context->buf;
2476 Oid typoutput;
2477 bool typIsVarlena;
2478 char *extval;
2479 bool isfloat = false;
2480 bool needlabel;
2481
2482 if (node->constisnull)
2483 {
2484 appendStringInfoString(buf, "NULL");
2485 if (showtype >= 0)
2486 appendStringInfo(buf, "::%s",
2487 deparse_type_name(node->consttype,
2488 node->consttypmod));
2489 return;
2490 }
2491
2492 getTypeOutputInfo(node->consttype,
2493 &typoutput, &typIsVarlena);
2494 extval = OidOutputFunctionCall(typoutput, node->constvalue);
2495
2496 switch (node->consttype)
2497 {
2498 case INT2OID:
2499 case INT4OID:
2500 case INT8OID:
2501 case OIDOID:
2502 case FLOAT4OID:
2503 case FLOAT8OID:
2504 case NUMERICOID:
2505 {
2506 /*
2507 * No need to quote unless it's a special value such as 'NaN'.
2508 * See comments in get_const_expr().
2509 */
2510 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
2511 {
2512 if (extval[0] == '+' || extval[0] == '-')
2513 appendStringInfo(buf, "(%s)", extval);
2514 else
2515 appendStringInfoString(buf, extval);
2516 if (strcspn(extval, "eE.") != strlen(extval))
2517 isfloat = true; /* it looks like a float */
2518 }
2519 else
2520 appendStringInfo(buf, "'%s'", extval);
2521 }
2522 break;
2523 case BITOID:
2524 case VARBITOID:
2525 appendStringInfo(buf, "B'%s'", extval);
2526 break;
2527 case BOOLOID:
2528 if (strcmp(extval, "t") == 0)
2529 appendStringInfoString(buf, "true");
2530 else
2531 appendStringInfoString(buf, "false");
2532 break;
2533 default:
2534 deparseStringLiteral(buf, extval);
2535 break;
2536 }
2537
2538 pfree(extval);
2539
2540 if (showtype < 0)
2541 return;
2542
2543 /*
2544 * For showtype == 0, append ::typename unless the constant will be
2545 * implicitly typed as the right type when it is read in.
2546 *
2547 * XXX this code has to be kept in sync with the behavior of the parser,
2548 * especially make_const.
2549 */
2550 switch (node->consttype)
2551 {
2552 case BOOLOID:
2553 case INT4OID:
2554 case UNKNOWNOID:
2555 needlabel = false;
2556 break;
2557 case NUMERICOID:
2558 needlabel = !isfloat || (node->consttypmod >= 0);
2559 break;
2560 default:
2561 needlabel = true;
2562 break;
2563 }
2564 if (needlabel || showtype > 0)
2565 appendStringInfo(buf, "::%s",
2566 deparse_type_name(node->consttype,
2567 node->consttypmod));
2568 }
2569
2570 /*
2571 * Deparse given Param node.
2572 *
2573 * If we're generating the query "for real", add the Param to
2574 * context->params_list if it's not already present, and then use its index
2575 * in that list as the remote parameter number. During EXPLAIN, there's
2576 * no need to identify a parameter number.
2577 */
2578 static void
deparseParam(Param * node,deparse_expr_cxt * context)2579 deparseParam(Param *node, deparse_expr_cxt *context)
2580 {
2581 if (context->params_list)
2582 {
2583 int pindex = 0;
2584 ListCell *lc;
2585
2586 /* find its index in params_list */
2587 foreach(lc, *context->params_list)
2588 {
2589 pindex++;
2590 if (equal(node, (Node *) lfirst(lc)))
2591 break;
2592 }
2593 if (lc == NULL)
2594 {
2595 /* not in list, so add it */
2596 pindex++;
2597 *context->params_list = lappend(*context->params_list, node);
2598 }
2599
2600 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
2601 }
2602 else
2603 {
2604 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
2605 }
2606 }
2607
2608 /*
2609 * Deparse a container subscript expression.
2610 */
2611 static void
deparseSubscriptingRef(SubscriptingRef * node,deparse_expr_cxt * context)2612 deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
2613 {
2614 StringInfo buf = context->buf;
2615 ListCell *lowlist_item;
2616 ListCell *uplist_item;
2617
2618 /* Always parenthesize the expression. */
2619 appendStringInfoChar(buf, '(');
2620
2621 /*
2622 * Deparse referenced array expression first. If that expression includes
2623 * a cast, we have to parenthesize to prevent the array subscript from
2624 * being taken as typename decoration. We can avoid that in the typical
2625 * case of subscripting a Var, but otherwise do it.
2626 */
2627 if (IsA(node->refexpr, Var))
2628 deparseExpr(node->refexpr, context);
2629 else
2630 {
2631 appendStringInfoChar(buf, '(');
2632 deparseExpr(node->refexpr, context);
2633 appendStringInfoChar(buf, ')');
2634 }
2635
2636 /* Deparse subscript expressions. */
2637 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
2638 foreach(uplist_item, node->refupperindexpr)
2639 {
2640 appendStringInfoChar(buf, '[');
2641 if (lowlist_item)
2642 {
2643 deparseExpr(lfirst(lowlist_item), context);
2644 appendStringInfoChar(buf, ':');
2645 lowlist_item = lnext(lowlist_item);
2646 }
2647 deparseExpr(lfirst(uplist_item), context);
2648 appendStringInfoChar(buf, ']');
2649 }
2650
2651 appendStringInfoChar(buf, ')');
2652 }
2653
2654 /*
2655 * Deparse a function call.
2656 */
2657 static void
deparseFuncExpr(FuncExpr * node,deparse_expr_cxt * context)2658 deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
2659 {
2660 StringInfo buf = context->buf;
2661 bool use_variadic;
2662 bool first;
2663 ListCell *arg;
2664
2665 /*
2666 * If the function call came from an implicit coercion, then just show the
2667 * first argument.
2668 */
2669 if (node->funcformat == COERCE_IMPLICIT_CAST)
2670 {
2671 deparseExpr((Expr *) linitial(node->args), context);
2672 return;
2673 }
2674
2675 /*
2676 * If the function call came from a cast, then show the first argument
2677 * plus an explicit cast operation.
2678 */
2679 if (node->funcformat == COERCE_EXPLICIT_CAST)
2680 {
2681 Oid rettype = node->funcresulttype;
2682 int32 coercedTypmod;
2683
2684 /* Get the typmod if this is a length-coercion function */
2685 (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
2686
2687 deparseExpr((Expr *) linitial(node->args), context);
2688 appendStringInfo(buf, "::%s",
2689 deparse_type_name(rettype, coercedTypmod));
2690 return;
2691 }
2692
2693 /* Check if need to print VARIADIC (cf. ruleutils.c) */
2694 use_variadic = node->funcvariadic;
2695
2696 /*
2697 * Normal function: display as proname(args).
2698 */
2699 appendFunctionName(node->funcid, context);
2700 appendStringInfoChar(buf, '(');
2701
2702 /* ... and all the arguments */
2703 first = true;
2704 foreach(arg, node->args)
2705 {
2706 if (!first)
2707 appendStringInfoString(buf, ", ");
2708 if (use_variadic && lnext(arg) == NULL)
2709 appendStringInfoString(buf, "VARIADIC ");
2710 deparseExpr((Expr *) lfirst(arg), context);
2711 first = false;
2712 }
2713 appendStringInfoChar(buf, ')');
2714 }
2715
2716 /*
2717 * Deparse given operator expression. To avoid problems around
2718 * priority of operations, we always parenthesize the arguments.
2719 */
2720 static void
deparseOpExpr(OpExpr * node,deparse_expr_cxt * context)2721 deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
2722 {
2723 StringInfo buf = context->buf;
2724 HeapTuple tuple;
2725 Form_pg_operator form;
2726 char oprkind;
2727 ListCell *arg;
2728
2729 /* Retrieve information about the operator from system catalog. */
2730 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
2731 if (!HeapTupleIsValid(tuple))
2732 elog(ERROR, "cache lookup failed for operator %u", node->opno);
2733 form = (Form_pg_operator) GETSTRUCT(tuple);
2734 oprkind = form->oprkind;
2735
2736 /* Sanity check. */
2737 Assert((oprkind == 'r' && list_length(node->args) == 1) ||
2738 (oprkind == 'l' && list_length(node->args) == 1) ||
2739 (oprkind == 'b' && list_length(node->args) == 2));
2740
2741 /* Always parenthesize the expression. */
2742 appendStringInfoChar(buf, '(');
2743
2744 /* Deparse left operand. */
2745 if (oprkind == 'r' || oprkind == 'b')
2746 {
2747 arg = list_head(node->args);
2748 deparseExpr(lfirst(arg), context);
2749 appendStringInfoChar(buf, ' ');
2750 }
2751
2752 /* Deparse operator name. */
2753 deparseOperatorName(buf, form);
2754
2755 /* Deparse right operand. */
2756 if (oprkind == 'l' || oprkind == 'b')
2757 {
2758 arg = list_tail(node->args);
2759 appendStringInfoChar(buf, ' ');
2760 deparseExpr(lfirst(arg), context);
2761 }
2762
2763 appendStringInfoChar(buf, ')');
2764
2765 ReleaseSysCache(tuple);
2766 }
2767
2768 /*
2769 * Print the name of an operator.
2770 */
2771 static void
deparseOperatorName(StringInfo buf,Form_pg_operator opform)2772 deparseOperatorName(StringInfo buf, Form_pg_operator opform)
2773 {
2774 char *opname;
2775
2776 /* opname is not a SQL identifier, so we should not quote it. */
2777 opname = NameStr(opform->oprname);
2778
2779 /* Print schema name only if it's not pg_catalog */
2780 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
2781 {
2782 const char *opnspname;
2783
2784 opnspname = get_namespace_name(opform->oprnamespace);
2785 /* Print fully qualified operator name. */
2786 appendStringInfo(buf, "OPERATOR(%s.%s)",
2787 quote_identifier(opnspname), opname);
2788 }
2789 else
2790 {
2791 /* Just print operator name. */
2792 appendStringInfoString(buf, opname);
2793 }
2794 }
2795
2796 /*
2797 * Deparse IS DISTINCT FROM.
2798 */
2799 static void
deparseDistinctExpr(DistinctExpr * node,deparse_expr_cxt * context)2800 deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
2801 {
2802 StringInfo buf = context->buf;
2803
2804 Assert(list_length(node->args) == 2);
2805
2806 appendStringInfoChar(buf, '(');
2807 deparseExpr(linitial(node->args), context);
2808 appendStringInfoString(buf, " IS DISTINCT FROM ");
2809 deparseExpr(lsecond(node->args), context);
2810 appendStringInfoChar(buf, ')');
2811 }
2812
2813 /*
2814 * Deparse given ScalarArrayOpExpr expression. To avoid problems
2815 * around priority of operations, we always parenthesize the arguments.
2816 */
2817 static void
deparseScalarArrayOpExpr(ScalarArrayOpExpr * node,deparse_expr_cxt * context)2818 deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
2819 {
2820 StringInfo buf = context->buf;
2821 HeapTuple tuple;
2822 Form_pg_operator form;
2823 Expr *arg1;
2824 Expr *arg2;
2825
2826 /* Retrieve information about the operator from system catalog. */
2827 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
2828 if (!HeapTupleIsValid(tuple))
2829 elog(ERROR, "cache lookup failed for operator %u", node->opno);
2830 form = (Form_pg_operator) GETSTRUCT(tuple);
2831
2832 /* Sanity check. */
2833 Assert(list_length(node->args) == 2);
2834
2835 /* Always parenthesize the expression. */
2836 appendStringInfoChar(buf, '(');
2837
2838 /* Deparse left operand. */
2839 arg1 = linitial(node->args);
2840 deparseExpr(arg1, context);
2841 appendStringInfoChar(buf, ' ');
2842
2843 /* Deparse operator name plus decoration. */
2844 deparseOperatorName(buf, form);
2845 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
2846
2847 /* Deparse right operand. */
2848 arg2 = lsecond(node->args);
2849 deparseExpr(arg2, context);
2850
2851 appendStringInfoChar(buf, ')');
2852
2853 /* Always parenthesize the expression. */
2854 appendStringInfoChar(buf, ')');
2855
2856 ReleaseSysCache(tuple);
2857 }
2858
2859 /*
2860 * Deparse a RelabelType (binary-compatible cast) node.
2861 */
2862 static void
deparseRelabelType(RelabelType * node,deparse_expr_cxt * context)2863 deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
2864 {
2865 deparseExpr(node->arg, context);
2866 if (node->relabelformat != COERCE_IMPLICIT_CAST)
2867 appendStringInfo(context->buf, "::%s",
2868 deparse_type_name(node->resulttype,
2869 node->resulttypmod));
2870 }
2871
2872 /*
2873 * Deparse a BoolExpr node.
2874 */
2875 static void
deparseBoolExpr(BoolExpr * node,deparse_expr_cxt * context)2876 deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
2877 {
2878 StringInfo buf = context->buf;
2879 const char *op = NULL; /* keep compiler quiet */
2880 bool first;
2881 ListCell *lc;
2882
2883 switch (node->boolop)
2884 {
2885 case AND_EXPR:
2886 op = "AND";
2887 break;
2888 case OR_EXPR:
2889 op = "OR";
2890 break;
2891 case NOT_EXPR:
2892 appendStringInfoString(buf, "(NOT ");
2893 deparseExpr(linitial(node->args), context);
2894 appendStringInfoChar(buf, ')');
2895 return;
2896 }
2897
2898 appendStringInfoChar(buf, '(');
2899 first = true;
2900 foreach(lc, node->args)
2901 {
2902 if (!first)
2903 appendStringInfo(buf, " %s ", op);
2904 deparseExpr((Expr *) lfirst(lc), context);
2905 first = false;
2906 }
2907 appendStringInfoChar(buf, ')');
2908 }
2909
2910 /*
2911 * Deparse IS [NOT] NULL expression.
2912 */
2913 static void
deparseNullTest(NullTest * node,deparse_expr_cxt * context)2914 deparseNullTest(NullTest *node, deparse_expr_cxt *context)
2915 {
2916 StringInfo buf = context->buf;
2917
2918 appendStringInfoChar(buf, '(');
2919 deparseExpr(node->arg, context);
2920
2921 /*
2922 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
2923 * shorter and traditional. If it's a rowtype input but we're applying a
2924 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
2925 * correct.
2926 */
2927 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
2928 {
2929 if (node->nulltesttype == IS_NULL)
2930 appendStringInfoString(buf, " IS NULL)");
2931 else
2932 appendStringInfoString(buf, " IS NOT NULL)");
2933 }
2934 else
2935 {
2936 if (node->nulltesttype == IS_NULL)
2937 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
2938 else
2939 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
2940 }
2941 }
2942
2943 /*
2944 * Deparse ARRAY[...] construct.
2945 */
2946 static void
deparseArrayExpr(ArrayExpr * node,deparse_expr_cxt * context)2947 deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
2948 {
2949 StringInfo buf = context->buf;
2950 bool first = true;
2951 ListCell *lc;
2952
2953 appendStringInfoString(buf, "ARRAY[");
2954 foreach(lc, node->elements)
2955 {
2956 if (!first)
2957 appendStringInfoString(buf, ", ");
2958 deparseExpr(lfirst(lc), context);
2959 first = false;
2960 }
2961 appendStringInfoChar(buf, ']');
2962
2963 /* If the array is empty, we need an explicit cast to the array type. */
2964 if (node->elements == NIL)
2965 appendStringInfo(buf, "::%s",
2966 deparse_type_name(node->array_typeid, -1));
2967 }
2968
2969 /*
2970 * Deparse an Aggref node.
2971 */
2972 static void
deparseAggref(Aggref * node,deparse_expr_cxt * context)2973 deparseAggref(Aggref *node, deparse_expr_cxt *context)
2974 {
2975 StringInfo buf = context->buf;
2976 bool use_variadic;
2977
2978 /* Only basic, non-split aggregation accepted. */
2979 Assert(node->aggsplit == AGGSPLIT_SIMPLE);
2980
2981 /* Check if need to print VARIADIC (cf. ruleutils.c) */
2982 use_variadic = node->aggvariadic;
2983
2984 /* Find aggregate name from aggfnoid which is a pg_proc entry */
2985 appendFunctionName(node->aggfnoid, context);
2986 appendStringInfoChar(buf, '(');
2987
2988 /* Add DISTINCT */
2989 appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
2990
2991 if (AGGKIND_IS_ORDERED_SET(node->aggkind))
2992 {
2993 /* Add WITHIN GROUP (ORDER BY ..) */
2994 ListCell *arg;
2995 bool first = true;
2996
2997 Assert(!node->aggvariadic);
2998 Assert(node->aggorder != NIL);
2999
3000 foreach(arg, node->aggdirectargs)
3001 {
3002 if (!first)
3003 appendStringInfoString(buf, ", ");
3004 first = false;
3005
3006 deparseExpr((Expr *) lfirst(arg), context);
3007 }
3008
3009 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3010 appendAggOrderBy(node->aggorder, node->args, context);
3011 }
3012 else
3013 {
3014 /* aggstar can be set only in zero-argument aggregates */
3015 if (node->aggstar)
3016 appendStringInfoChar(buf, '*');
3017 else
3018 {
3019 ListCell *arg;
3020 bool first = true;
3021
3022 /* Add all the arguments */
3023 foreach(arg, node->args)
3024 {
3025 TargetEntry *tle = (TargetEntry *) lfirst(arg);
3026 Node *n = (Node *) tle->expr;
3027
3028 if (tle->resjunk)
3029 continue;
3030
3031 if (!first)
3032 appendStringInfoString(buf, ", ");
3033 first = false;
3034
3035 /* Add VARIADIC */
3036 if (use_variadic && lnext(arg) == NULL)
3037 appendStringInfoString(buf, "VARIADIC ");
3038
3039 deparseExpr((Expr *) n, context);
3040 }
3041 }
3042
3043 /* Add ORDER BY */
3044 if (node->aggorder != NIL)
3045 {
3046 appendStringInfoString(buf, " ORDER BY ");
3047 appendAggOrderBy(node->aggorder, node->args, context);
3048 }
3049 }
3050
3051 /* Add FILTER (WHERE ..) */
3052 if (node->aggfilter != NULL)
3053 {
3054 appendStringInfoString(buf, ") FILTER (WHERE ");
3055 deparseExpr((Expr *) node->aggfilter, context);
3056 }
3057
3058 appendStringInfoChar(buf, ')');
3059 }
3060
3061 /*
3062 * Append ORDER BY within aggregate function.
3063 */
3064 static void
appendAggOrderBy(List * orderList,List * targetList,deparse_expr_cxt * context)3065 appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
3066 {
3067 StringInfo buf = context->buf;
3068 ListCell *lc;
3069 bool first = true;
3070
3071 foreach(lc, orderList)
3072 {
3073 SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3074 Node *sortexpr;
3075 Oid sortcoltype;
3076 TypeCacheEntry *typentry;
3077
3078 if (!first)
3079 appendStringInfoString(buf, ", ");
3080 first = false;
3081
3082 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3083 false, context);
3084 sortcoltype = exprType(sortexpr);
3085 /* See whether operator is default < or > for datatype */
3086 typentry = lookup_type_cache(sortcoltype,
3087 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
3088 if (srt->sortop == typentry->lt_opr)
3089 appendStringInfoString(buf, " ASC");
3090 else if (srt->sortop == typentry->gt_opr)
3091 appendStringInfoString(buf, " DESC");
3092 else
3093 {
3094 HeapTuple opertup;
3095 Form_pg_operator operform;
3096
3097 appendStringInfoString(buf, " USING ");
3098
3099 /* Append operator name. */
3100 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(srt->sortop));
3101 if (!HeapTupleIsValid(opertup))
3102 elog(ERROR, "cache lookup failed for operator %u", srt->sortop);
3103 operform = (Form_pg_operator) GETSTRUCT(opertup);
3104 deparseOperatorName(buf, operform);
3105 ReleaseSysCache(opertup);
3106 }
3107
3108 if (srt->nulls_first)
3109 appendStringInfoString(buf, " NULLS FIRST");
3110 else
3111 appendStringInfoString(buf, " NULLS LAST");
3112 }
3113 }
3114
3115 /*
3116 * Print the representation of a parameter to be sent to the remote side.
3117 *
3118 * Note: we always label the Param's type explicitly rather than relying on
3119 * transmitting a numeric type OID in PQexecParams(). This allows us to
3120 * avoid assuming that types have the same OIDs on the remote side as they
3121 * do locally --- they need only have the same names.
3122 */
3123 static void
printRemoteParam(int paramindex,Oid paramtype,int32 paramtypmod,deparse_expr_cxt * context)3124 printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
3125 deparse_expr_cxt *context)
3126 {
3127 StringInfo buf = context->buf;
3128 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3129
3130 appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3131 }
3132
3133 /*
3134 * Print the representation of a placeholder for a parameter that will be
3135 * sent to the remote side at execution time.
3136 *
3137 * This is used when we're just trying to EXPLAIN the remote query.
3138 * We don't have the actual value of the runtime parameter yet, and we don't
3139 * want the remote planner to generate a plan that depends on such a value
3140 * anyway. Thus, we can't do something simple like "$1::paramtype".
3141 * Instead, we emit "((SELECT null::paramtype)::paramtype)".
3142 * In all extant versions of Postgres, the planner will see that as an unknown
3143 * constant value, which is what we want. This might need adjustment if we
3144 * ever make the planner flatten scalar subqueries. Note: the reason for the
3145 * apparently useless outer cast is to ensure that the representation as a
3146 * whole will be parsed as an a_expr and not a select_with_parens; the latter
3147 * would do the wrong thing in the context "x = ANY(...)".
3148 */
3149 static void
printRemotePlaceholder(Oid paramtype,int32 paramtypmod,deparse_expr_cxt * context)3150 printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
3151 deparse_expr_cxt *context)
3152 {
3153 StringInfo buf = context->buf;
3154 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3155
3156 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3157 }
3158
3159 /*
3160 * Deparse GROUP BY clause.
3161 */
3162 static void
appendGroupByClause(List * tlist,deparse_expr_cxt * context)3163 appendGroupByClause(List *tlist, deparse_expr_cxt *context)
3164 {
3165 StringInfo buf = context->buf;
3166 Query *query = context->root->parse;
3167 ListCell *lc;
3168 bool first = true;
3169
3170 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3171 if (!query->groupClause)
3172 return;
3173
3174 appendStringInfoString(buf, " GROUP BY ");
3175
3176 /*
3177 * Queries with grouping sets are not pushed down, so we don't expect
3178 * grouping sets here.
3179 */
3180 Assert(!query->groupingSets);
3181
3182 foreach(lc, query->groupClause)
3183 {
3184 SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3185
3186 if (!first)
3187 appendStringInfoString(buf, ", ");
3188 first = false;
3189
3190 deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3191 }
3192 }
3193
3194 /*
3195 * Deparse ORDER BY clause according to the given pathkeys for given base
3196 * relation. From given pathkeys expressions belonging entirely to the given
3197 * base relation are obtained and deparsed.
3198 */
3199 static void
appendOrderByClause(List * pathkeys,bool has_final_sort,deparse_expr_cxt * context)3200 appendOrderByClause(List *pathkeys, bool has_final_sort,
3201 deparse_expr_cxt *context)
3202 {
3203 ListCell *lcell;
3204 int nestlevel;
3205 char *delim = " ";
3206 RelOptInfo *baserel = context->scanrel;
3207 StringInfo buf = context->buf;
3208
3209 /* Make sure any constants in the exprs are printed portably */
3210 nestlevel = set_transmission_modes();
3211
3212 appendStringInfoString(buf, " ORDER BY");
3213 foreach(lcell, pathkeys)
3214 {
3215 PathKey *pathkey = lfirst(lcell);
3216 Expr *em_expr;
3217
3218 if (has_final_sort)
3219 {
3220 /*
3221 * By construction, context->foreignrel is the input relation to
3222 * the final sort.
3223 */
3224 em_expr = find_em_expr_for_input_target(context->root,
3225 pathkey->pk_eclass,
3226 context->foreignrel->reltarget);
3227 }
3228 else
3229 em_expr = find_em_expr_for_rel(pathkey->pk_eclass, baserel);
3230
3231 Assert(em_expr != NULL);
3232
3233 appendStringInfoString(buf, delim);
3234 deparseExpr(em_expr, context);
3235 if (pathkey->pk_strategy == BTLessStrategyNumber)
3236 appendStringInfoString(buf, " ASC");
3237 else
3238 appendStringInfoString(buf, " DESC");
3239
3240 if (pathkey->pk_nulls_first)
3241 appendStringInfoString(buf, " NULLS FIRST");
3242 else
3243 appendStringInfoString(buf, " NULLS LAST");
3244
3245 delim = ", ";
3246 }
3247 reset_transmission_modes(nestlevel);
3248 }
3249
3250 /*
3251 * Deparse LIMIT/OFFSET clause.
3252 */
3253 static void
appendLimitClause(deparse_expr_cxt * context)3254 appendLimitClause(deparse_expr_cxt *context)
3255 {
3256 PlannerInfo *root = context->root;
3257 StringInfo buf = context->buf;
3258 int nestlevel;
3259
3260 /* Make sure any constants in the exprs are printed portably */
3261 nestlevel = set_transmission_modes();
3262
3263 if (root->parse->limitCount)
3264 {
3265 appendStringInfoString(buf, " LIMIT ");
3266 deparseExpr((Expr *) root->parse->limitCount, context);
3267 }
3268 if (root->parse->limitOffset)
3269 {
3270 appendStringInfoString(buf, " OFFSET ");
3271 deparseExpr((Expr *) root->parse->limitOffset, context);
3272 }
3273
3274 reset_transmission_modes(nestlevel);
3275 }
3276
3277 /*
3278 * appendFunctionName
3279 * Deparses function name from given function oid.
3280 */
3281 static void
appendFunctionName(Oid funcid,deparse_expr_cxt * context)3282 appendFunctionName(Oid funcid, deparse_expr_cxt *context)
3283 {
3284 StringInfo buf = context->buf;
3285 HeapTuple proctup;
3286 Form_pg_proc procform;
3287 const char *proname;
3288
3289 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3290 if (!HeapTupleIsValid(proctup))
3291 elog(ERROR, "cache lookup failed for function %u", funcid);
3292 procform = (Form_pg_proc) GETSTRUCT(proctup);
3293
3294 /* Print schema name only if it's not pg_catalog */
3295 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
3296 {
3297 const char *schemaname;
3298
3299 schemaname = get_namespace_name(procform->pronamespace);
3300 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
3301 }
3302
3303 /* Always print the function name */
3304 proname = NameStr(procform->proname);
3305 appendStringInfoString(buf, quote_identifier(proname));
3306
3307 ReleaseSysCache(proctup);
3308 }
3309
3310 /*
3311 * Appends a sort or group clause.
3312 *
3313 * Like get_rule_sortgroupclause(), returns the expression tree, so caller
3314 * need not find it again.
3315 */
3316 static Node *
deparseSortGroupClause(Index ref,List * tlist,bool force_colno,deparse_expr_cxt * context)3317 deparseSortGroupClause(Index ref, List *tlist, bool force_colno,
3318 deparse_expr_cxt *context)
3319 {
3320 StringInfo buf = context->buf;
3321 TargetEntry *tle;
3322 Expr *expr;
3323
3324 tle = get_sortgroupref_tle(ref, tlist);
3325 expr = tle->expr;
3326
3327 if (force_colno)
3328 {
3329 /* Use column-number form when requested by caller. */
3330 Assert(!tle->resjunk);
3331 appendStringInfo(buf, "%d", tle->resno);
3332 }
3333 else if (expr && IsA(expr, Const))
3334 {
3335 /*
3336 * Force a typecast here so that we don't emit something like "GROUP
3337 * BY 2", which will be misconstrued as a column position rather than
3338 * a constant.
3339 */
3340 deparseConst((Const *) expr, context, 1);
3341 }
3342 else if (!expr || IsA(expr, Var))
3343 deparseExpr(expr, context);
3344 else
3345 {
3346 /* Always parenthesize the expression. */
3347 appendStringInfoChar(buf, '(');
3348 deparseExpr(expr, context);
3349 appendStringInfoChar(buf, ')');
3350 }
3351
3352 return (Node *) expr;
3353 }
3354
3355
3356 /*
3357 * Returns true if given Var is deparsed as a subquery output column, in
3358 * which case, *relno and *colno are set to the IDs for the relation and
3359 * column alias to the Var provided by the subquery.
3360 */
3361 static bool
is_subquery_var(Var * node,RelOptInfo * foreignrel,int * relno,int * colno)3362 is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
3363 {
3364 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3365 RelOptInfo *outerrel = fpinfo->outerrel;
3366 RelOptInfo *innerrel = fpinfo->innerrel;
3367
3368 /* Should only be called in these cases. */
3369 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
3370
3371 /*
3372 * If the given relation isn't a join relation, it doesn't have any lower
3373 * subqueries, so the Var isn't a subquery output column.
3374 */
3375 if (!IS_JOIN_REL(foreignrel))
3376 return false;
3377
3378 /*
3379 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
3380 * output column.
3381 */
3382 if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
3383 return false;
3384
3385 if (bms_is_member(node->varno, outerrel->relids))
3386 {
3387 /*
3388 * If outer relation is deparsed as a subquery, the Var is an output
3389 * column of the subquery; get the IDs for the relation/column alias.
3390 */
3391 if (fpinfo->make_outerrel_subquery)
3392 {
3393 get_relation_column_alias_ids(node, outerrel, relno, colno);
3394 return true;
3395 }
3396
3397 /* Otherwise, recurse into the outer relation. */
3398 return is_subquery_var(node, outerrel, relno, colno);
3399 }
3400 else
3401 {
3402 Assert(bms_is_member(node->varno, innerrel->relids));
3403
3404 /*
3405 * If inner relation is deparsed as a subquery, the Var is an output
3406 * column of the subquery; get the IDs for the relation/column alias.
3407 */
3408 if (fpinfo->make_innerrel_subquery)
3409 {
3410 get_relation_column_alias_ids(node, innerrel, relno, colno);
3411 return true;
3412 }
3413
3414 /* Otherwise, recurse into the inner relation. */
3415 return is_subquery_var(node, innerrel, relno, colno);
3416 }
3417 }
3418
3419 /*
3420 * Get the IDs for the relation and column alias to given Var belonging to
3421 * given relation, which are returned into *relno and *colno.
3422 */
3423 static void
get_relation_column_alias_ids(Var * node,RelOptInfo * foreignrel,int * relno,int * colno)3424 get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
3425 int *relno, int *colno)
3426 {
3427 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3428 int i;
3429 ListCell *lc;
3430
3431 /* Get the relation alias ID */
3432 *relno = fpinfo->relation_index;
3433
3434 /* Get the column alias ID */
3435 i = 1;
3436 foreach(lc, foreignrel->reltarget->exprs)
3437 {
3438 if (equal(lfirst(lc), (Node *) node))
3439 {
3440 *colno = i;
3441 return;
3442 }
3443 i++;
3444 }
3445
3446 /* Shouldn't get here */
3447 elog(ERROR, "unexpected expression in subquery output");
3448 }
3449