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-2016, 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/heapam.h"
39 #include "access/htup_details.h"
40 #include "access/sysattr.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_namespace.h"
43 #include "catalog/pg_operator.h"
44 #include "catalog/pg_proc.h"
45 #include "catalog/pg_type.h"
46 #include "commands/defrem.h"
47 #include "nodes/makefuncs.h"
48 #include "nodes/nodeFuncs.h"
49 #include "nodes/plannodes.h"
50 #include "optimizer/clauses.h"
51 #include "optimizer/prep.h"
52 #include "optimizer/tlist.h"
53 #include "optimizer/var.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
60
61 /*
62 * Global context for foreign_expr_walker's search of an expression tree.
63 */
64 typedef struct foreign_glob_cxt
65 {
66 PlannerInfo *root; /* global planner state */
67 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
68 } foreign_glob_cxt;
69
70 /*
71 * Local (per-tree-level) context for foreign_expr_walker's search.
72 * This is concerned with identifying collations used in the expression.
73 */
74 typedef enum
75 {
76 FDW_COLLATE_NONE, /* expression is of a noncollatable type, or
77 * it has default collation that is not
78 * traceable to a foreign Var */
79 FDW_COLLATE_SAFE, /* collation derives from a foreign Var */
80 FDW_COLLATE_UNSAFE /* collation is non-default and derives from
81 * something other than a foreign Var */
82 } FDWCollateState;
83
84 typedef struct foreign_loc_cxt
85 {
86 Oid collation; /* OID of current collation, if any */
87 FDWCollateState state; /* state of current collation choice */
88 } foreign_loc_cxt;
89
90 /*
91 * Context for deparseExpr
92 */
93 typedef struct deparse_expr_cxt
94 {
95 PlannerInfo *root; /* global planner state */
96 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
97 StringInfo buf; /* output buffer to append to */
98 List **params_list; /* exprs that will become remote Params */
99 } deparse_expr_cxt;
100
101 #define REL_ALIAS_PREFIX "r"
102 /* Handy macro to add relation name qualification */
103 #define ADD_REL_QUALIFIER(buf, varno) \
104 appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
105
106 /*
107 * Functions to determine whether an expression can be evaluated safely on
108 * remote server.
109 */
110 static bool foreign_expr_walker(Node *node,
111 foreign_glob_cxt *glob_cxt,
112 foreign_loc_cxt *outer_cxt);
113 static char *deparse_type_name(Oid type_oid, int32 typemod);
114
115 /*
116 * Functions to construct string representation of a node tree.
117 */
118 static void deparseTargetList(StringInfo buf,
119 PlannerInfo *root,
120 Index rtindex,
121 Relation rel,
122 bool is_returning,
123 Bitmapset *attrs_used,
124 bool qualify_col,
125 List **retrieved_attrs);
126 static void deparseExplicitTargetList(List *tlist, List **retrieved_attrs,
127 deparse_expr_cxt *context);
128 static void deparseReturningList(StringInfo buf, PlannerInfo *root,
129 Index rtindex, Relation rel,
130 bool trig_after_row,
131 List *returningList,
132 List **retrieved_attrs);
133 static void deparseColumnRef(StringInfo buf, int varno, int varattno,
134 PlannerInfo *root, bool qualify_col);
135 static void deparseRelation(StringInfo buf, Relation rel);
136 static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
137 static void deparseVar(Var *node, deparse_expr_cxt *context);
138 static void deparseConst(Const *node, deparse_expr_cxt *context);
139 static void deparseParam(Param *node, deparse_expr_cxt *context);
140 static void deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context);
141 static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
142 static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
143 static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
144 static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context);
145 static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node,
146 deparse_expr_cxt *context);
147 static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
148 static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context);
149 static void deparseNullTest(NullTest *node, deparse_expr_cxt *context);
150 static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context);
151 static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
152 deparse_expr_cxt *context);
153 static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
154 deparse_expr_cxt *context);
155 static void deparseSelectSql(List *tlist, List **retrieved_attrs,
156 deparse_expr_cxt *context);
157 static void deparseLockingClause(deparse_expr_cxt *context);
158 static void appendOrderByClause(List *pathkeys, deparse_expr_cxt *context);
159 static void appendConditions(List *exprs, deparse_expr_cxt *context);
160 static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root,
161 RelOptInfo *joinrel, bool use_alias, List **params_list);
162
163
164 /*
165 * Examine each qual clause in input_conds, and classify them into two groups,
166 * which are returned as two lists:
167 * - remote_conds contains expressions that can be evaluated remotely
168 * - local_conds contains expressions that can't be evaluated remotely
169 */
170 void
classifyConditions(PlannerInfo * root,RelOptInfo * baserel,List * input_conds,List ** remote_conds,List ** local_conds)171 classifyConditions(PlannerInfo *root,
172 RelOptInfo *baserel,
173 List *input_conds,
174 List **remote_conds,
175 List **local_conds)
176 {
177 ListCell *lc;
178
179 *remote_conds = NIL;
180 *local_conds = NIL;
181
182 foreach(lc, input_conds)
183 {
184 RestrictInfo *ri = (RestrictInfo *) lfirst(lc);
185
186 if (is_foreign_expr(root, baserel, ri->clause))
187 *remote_conds = lappend(*remote_conds, ri);
188 else
189 *local_conds = lappend(*local_conds, ri);
190 }
191 }
192
193 /*
194 * Returns true if given expr is safe to evaluate on the foreign server.
195 */
196 bool
is_foreign_expr(PlannerInfo * root,RelOptInfo * baserel,Expr * expr)197 is_foreign_expr(PlannerInfo *root,
198 RelOptInfo *baserel,
199 Expr *expr)
200 {
201 foreign_glob_cxt glob_cxt;
202 foreign_loc_cxt loc_cxt;
203
204 /*
205 * Check that the expression consists of nodes that are safe to execute
206 * remotely.
207 */
208 glob_cxt.root = root;
209 glob_cxt.foreignrel = baserel;
210 loc_cxt.collation = InvalidOid;
211 loc_cxt.state = FDW_COLLATE_NONE;
212 if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt))
213 return false;
214
215 /*
216 * If the expression has a valid collation that does not arise from a
217 * foreign var, the expression can not be sent over.
218 */
219 if (loc_cxt.state == FDW_COLLATE_UNSAFE)
220 return false;
221
222 /*
223 * An expression which includes any mutable functions can't be sent over
224 * because its result is not stable. For example, sending now() remote
225 * side could cause confusion from clock offsets. Future versions might
226 * be able to make this choice with more granularity. (We check this last
227 * because it requires a lot of expensive catalog lookups.)
228 */
229 if (contain_mutable_functions((Node *) expr))
230 return false;
231
232 /* OK to evaluate on the remote server */
233 return true;
234 }
235
236 /*
237 * Check if expression is safe to execute remotely, and return true if so.
238 *
239 * In addition, *outer_cxt is updated with collation information.
240 *
241 * We must check that the expression contains only node types we can deparse,
242 * that all types/functions/operators are safe to send (they are "shippable"),
243 * and that all collations used in the expression derive from Vars of the
244 * foreign table. Because of the latter, the logic is pretty close to
245 * assign_collations_walker() in parse_collate.c, though we can assume here
246 * that the given expression is valid. Note function mutability is not
247 * currently considered here.
248 */
249 static bool
foreign_expr_walker(Node * node,foreign_glob_cxt * glob_cxt,foreign_loc_cxt * outer_cxt)250 foreign_expr_walker(Node *node,
251 foreign_glob_cxt *glob_cxt,
252 foreign_loc_cxt *outer_cxt)
253 {
254 bool check_type = true;
255 PgFdwRelationInfo *fpinfo;
256 foreign_loc_cxt inner_cxt;
257 Oid collation;
258 FDWCollateState state;
259
260 /* Need do nothing for empty subexpressions */
261 if (node == NULL)
262 return true;
263
264 /* May need server info from baserel's fdw_private struct */
265 fpinfo = (PgFdwRelationInfo *) (glob_cxt->foreignrel->fdw_private);
266
267 /* Set up inner_cxt for possible recursion to child nodes */
268 inner_cxt.collation = InvalidOid;
269 inner_cxt.state = FDW_COLLATE_NONE;
270
271 switch (nodeTag(node))
272 {
273 case T_Var:
274 {
275 Var *var = (Var *) node;
276
277 /*
278 * If the Var is from the foreign table, we consider its
279 * collation (if any) safe to use. If it is from another
280 * table, we treat its collation the same way as we would a
281 * Param's collation, ie it's not safe for it to have a
282 * non-default collation.
283 */
284 if (bms_is_member(var->varno, glob_cxt->foreignrel->relids) &&
285 var->varlevelsup == 0)
286 {
287 /* Var belongs to foreign table */
288
289 /*
290 * System columns other than ctid should not be sent to
291 * the remote, since we don't make any effort to ensure
292 * that local and remote values match (tableoid, in
293 * particular, almost certainly doesn't match).
294 */
295 if (var->varattno < 0 &&
296 var->varattno != SelfItemPointerAttributeNumber)
297 return false;
298
299 /* Else check the collation */
300 collation = var->varcollid;
301 state = OidIsValid(collation) ? FDW_COLLATE_SAFE : FDW_COLLATE_NONE;
302 }
303 else
304 {
305 /* Var belongs to some other table */
306 collation = var->varcollid;
307 if (collation == InvalidOid ||
308 collation == DEFAULT_COLLATION_OID)
309 {
310 /*
311 * It's noncollatable, or it's safe to combine with a
312 * collatable foreign Var, so set state to NONE.
313 */
314 state = FDW_COLLATE_NONE;
315 }
316 else
317 {
318 /*
319 * Do not fail right away, since the Var might appear
320 * in a collation-insensitive context.
321 */
322 state = FDW_COLLATE_UNSAFE;
323 }
324 }
325 }
326 break;
327 case T_Const:
328 {
329 Const *c = (Const *) node;
330
331 /*
332 * If the constant has nondefault collation, either it's of a
333 * non-builtin type, or it reflects folding of a CollateExpr.
334 * It's unsafe to send to the remote unless it's used in a
335 * non-collation-sensitive context.
336 */
337 collation = c->constcollid;
338 if (collation == InvalidOid ||
339 collation == DEFAULT_COLLATION_OID)
340 state = FDW_COLLATE_NONE;
341 else
342 state = FDW_COLLATE_UNSAFE;
343 }
344 break;
345 case T_Param:
346 {
347 Param *p = (Param *) node;
348
349 /*
350 * If it's a MULTIEXPR Param, punt. We can't tell from here
351 * whether the referenced sublink/subplan contains any remote
352 * Vars; if it does, handling that is too complicated to
353 * consider supporting at present. Fortunately, MULTIEXPR
354 * Params are not reduced to plain PARAM_EXEC until the end of
355 * planning, so we can easily detect this case. (Normal
356 * PARAM_EXEC Params are safe to ship because their values
357 * come from somewhere else in the plan tree; but a MULTIEXPR
358 * references a sub-select elsewhere in the same targetlist,
359 * so we'd be on the hook to evaluate it somehow if we wanted
360 * to handle such cases as direct foreign updates.)
361 */
362 if (p->paramkind == PARAM_MULTIEXPR)
363 return false;
364
365 /*
366 * Collation rule is same as for Consts and non-foreign Vars.
367 */
368 collation = p->paramcollid;
369 if (collation == InvalidOid ||
370 collation == DEFAULT_COLLATION_OID)
371 state = FDW_COLLATE_NONE;
372 else
373 state = FDW_COLLATE_UNSAFE;
374 }
375 break;
376 case T_ArrayRef:
377 {
378 ArrayRef *ar = (ArrayRef *) node;
379
380 /* Assignment should not be in restrictions. */
381 if (ar->refassgnexpr != NULL)
382 return false;
383
384 /*
385 * Recurse to remaining subexpressions. Since the array
386 * subscripts must yield (noncollatable) integers, they won't
387 * affect the inner_cxt state.
388 */
389 if (!foreign_expr_walker((Node *) ar->refupperindexpr,
390 glob_cxt, &inner_cxt))
391 return false;
392 if (!foreign_expr_walker((Node *) ar->reflowerindexpr,
393 glob_cxt, &inner_cxt))
394 return false;
395 if (!foreign_expr_walker((Node *) ar->refexpr,
396 glob_cxt, &inner_cxt))
397 return false;
398
399 /*
400 * Array subscripting should yield same collation as input,
401 * but for safety use same logic as for function nodes.
402 */
403 collation = ar->refcollid;
404 if (collation == InvalidOid)
405 state = FDW_COLLATE_NONE;
406 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
407 collation == inner_cxt.collation)
408 state = FDW_COLLATE_SAFE;
409 else if (collation == DEFAULT_COLLATION_OID)
410 state = FDW_COLLATE_NONE;
411 else
412 state = FDW_COLLATE_UNSAFE;
413 }
414 break;
415 case T_FuncExpr:
416 {
417 FuncExpr *fe = (FuncExpr *) node;
418
419 /*
420 * If function used by the expression is not shippable, it
421 * can't be sent to remote because it might have incompatible
422 * semantics on remote side.
423 */
424 if (!is_shippable(fe->funcid, ProcedureRelationId, fpinfo))
425 return false;
426
427 /*
428 * Recurse to input subexpressions.
429 */
430 if (!foreign_expr_walker((Node *) fe->args,
431 glob_cxt, &inner_cxt))
432 return false;
433
434 /*
435 * If function's input collation is not derived from a foreign
436 * Var, it can't be sent to remote.
437 */
438 if (fe->inputcollid == InvalidOid)
439 /* OK, inputs are all noncollatable */ ;
440 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
441 fe->inputcollid != inner_cxt.collation)
442 return false;
443
444 /*
445 * Detect whether node is introducing a collation not derived
446 * from a foreign Var. (If so, we just mark it unsafe for now
447 * rather than immediately returning false, since the parent
448 * node might not care.)
449 */
450 collation = fe->funccollid;
451 if (collation == InvalidOid)
452 state = FDW_COLLATE_NONE;
453 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
454 collation == inner_cxt.collation)
455 state = FDW_COLLATE_SAFE;
456 else if (collation == DEFAULT_COLLATION_OID)
457 state = FDW_COLLATE_NONE;
458 else
459 state = FDW_COLLATE_UNSAFE;
460 }
461 break;
462 case T_OpExpr:
463 case T_DistinctExpr: /* struct-equivalent to OpExpr */
464 {
465 OpExpr *oe = (OpExpr *) node;
466
467 /*
468 * Similarly, only shippable operators can be sent to remote.
469 * (If the operator is shippable, we assume its underlying
470 * function is too.)
471 */
472 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
473 return false;
474
475 /*
476 * Recurse to input subexpressions.
477 */
478 if (!foreign_expr_walker((Node *) oe->args,
479 glob_cxt, &inner_cxt))
480 return false;
481
482 /*
483 * If operator's input collation is not derived from a foreign
484 * Var, it can't be sent to remote.
485 */
486 if (oe->inputcollid == InvalidOid)
487 /* OK, inputs are all noncollatable */ ;
488 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
489 oe->inputcollid != inner_cxt.collation)
490 return false;
491
492 /* Result-collation handling is same as for functions */
493 collation = oe->opcollid;
494 if (collation == InvalidOid)
495 state = FDW_COLLATE_NONE;
496 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
497 collation == inner_cxt.collation)
498 state = FDW_COLLATE_SAFE;
499 else if (collation == DEFAULT_COLLATION_OID)
500 state = FDW_COLLATE_NONE;
501 else
502 state = FDW_COLLATE_UNSAFE;
503 }
504 break;
505 case T_ScalarArrayOpExpr:
506 {
507 ScalarArrayOpExpr *oe = (ScalarArrayOpExpr *) node;
508
509 /*
510 * Again, only shippable operators can be sent to remote.
511 */
512 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
513 return false;
514
515 /*
516 * Recurse to input subexpressions.
517 */
518 if (!foreign_expr_walker((Node *) oe->args,
519 glob_cxt, &inner_cxt))
520 return false;
521
522 /*
523 * If operator's input collation is not derived from a foreign
524 * Var, it can't be sent to remote.
525 */
526 if (oe->inputcollid == InvalidOid)
527 /* OK, inputs are all noncollatable */ ;
528 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
529 oe->inputcollid != inner_cxt.collation)
530 return false;
531
532 /* Output is always boolean and so noncollatable. */
533 collation = InvalidOid;
534 state = FDW_COLLATE_NONE;
535 }
536 break;
537 case T_RelabelType:
538 {
539 RelabelType *r = (RelabelType *) node;
540
541 /*
542 * Recurse to input subexpression.
543 */
544 if (!foreign_expr_walker((Node *) r->arg,
545 glob_cxt, &inner_cxt))
546 return false;
547
548 /*
549 * RelabelType must not introduce a collation not derived from
550 * an input foreign Var (same logic as for a real function).
551 */
552 collation = r->resultcollid;
553 if (collation == InvalidOid)
554 state = FDW_COLLATE_NONE;
555 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
556 collation == inner_cxt.collation)
557 state = FDW_COLLATE_SAFE;
558 else if (collation == DEFAULT_COLLATION_OID)
559 state = FDW_COLLATE_NONE;
560 else
561 state = FDW_COLLATE_UNSAFE;
562 }
563 break;
564 case T_BoolExpr:
565 {
566 BoolExpr *b = (BoolExpr *) node;
567
568 /*
569 * Recurse to input subexpressions.
570 */
571 if (!foreign_expr_walker((Node *) b->args,
572 glob_cxt, &inner_cxt))
573 return false;
574
575 /* Output is always boolean and so noncollatable. */
576 collation = InvalidOid;
577 state = FDW_COLLATE_NONE;
578 }
579 break;
580 case T_NullTest:
581 {
582 NullTest *nt = (NullTest *) node;
583
584 /*
585 * Recurse to input subexpressions.
586 */
587 if (!foreign_expr_walker((Node *) nt->arg,
588 glob_cxt, &inner_cxt))
589 return false;
590
591 /* Output is always boolean and so noncollatable. */
592 collation = InvalidOid;
593 state = FDW_COLLATE_NONE;
594 }
595 break;
596 case T_ArrayExpr:
597 {
598 ArrayExpr *a = (ArrayExpr *) node;
599
600 /*
601 * Recurse to input subexpressions.
602 */
603 if (!foreign_expr_walker((Node *) a->elements,
604 glob_cxt, &inner_cxt))
605 return false;
606
607 /*
608 * ArrayExpr must not introduce a collation not derived from
609 * an input foreign Var (same logic as for a function).
610 */
611 collation = a->array_collid;
612 if (collation == InvalidOid)
613 state = FDW_COLLATE_NONE;
614 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
615 collation == inner_cxt.collation)
616 state = FDW_COLLATE_SAFE;
617 else if (collation == DEFAULT_COLLATION_OID)
618 state = FDW_COLLATE_NONE;
619 else
620 state = FDW_COLLATE_UNSAFE;
621 }
622 break;
623 case T_List:
624 {
625 List *l = (List *) node;
626 ListCell *lc;
627
628 /*
629 * Recurse to component subexpressions.
630 */
631 foreach(lc, l)
632 {
633 if (!foreign_expr_walker((Node *) lfirst(lc),
634 glob_cxt, &inner_cxt))
635 return false;
636 }
637
638 /*
639 * When processing a list, collation state just bubbles up
640 * from the list elements.
641 */
642 collation = inner_cxt.collation;
643 state = inner_cxt.state;
644
645 /* Don't apply exprType() to the list. */
646 check_type = false;
647 }
648 break;
649 default:
650
651 /*
652 * If it's anything else, assume it's unsafe. This list can be
653 * expanded later, but don't forget to add deparse support below.
654 */
655 return false;
656 }
657
658 /*
659 * If result type of given expression is not shippable, it can't be sent
660 * to remote because it might have incompatible semantics on remote side.
661 */
662 if (check_type && !is_shippable(exprType(node), TypeRelationId, fpinfo))
663 return false;
664
665 /*
666 * Now, merge my collation information into my parent's state.
667 */
668 if (state > outer_cxt->state)
669 {
670 /* Override previous parent state */
671 outer_cxt->collation = collation;
672 outer_cxt->state = state;
673 }
674 else if (state == outer_cxt->state)
675 {
676 /* Merge, or detect error if there's a collation conflict */
677 switch (state)
678 {
679 case FDW_COLLATE_NONE:
680 /* Nothing + nothing is still nothing */
681 break;
682 case FDW_COLLATE_SAFE:
683 if (collation != outer_cxt->collation)
684 {
685 /*
686 * Non-default collation always beats default.
687 */
688 if (outer_cxt->collation == DEFAULT_COLLATION_OID)
689 {
690 /* Override previous parent state */
691 outer_cxt->collation = collation;
692 }
693 else if (collation != DEFAULT_COLLATION_OID)
694 {
695 /*
696 * Conflict; show state as indeterminate. We don't
697 * want to "return false" right away, since parent
698 * node might not care about collation.
699 */
700 outer_cxt->state = FDW_COLLATE_UNSAFE;
701 }
702 }
703 break;
704 case FDW_COLLATE_UNSAFE:
705 /* We're still conflicted ... */
706 break;
707 }
708 }
709
710 /* It looks OK */
711 return true;
712 }
713
714 /*
715 * Convert type OID + typmod info into a type name we can ship to the remote
716 * server. Someplace else had better have verified that this type name is
717 * expected to be known on the remote end.
718 *
719 * This is almost just format_type_with_typemod(), except that if left to its
720 * own devices, that function will make schema-qualification decisions based
721 * on the local search_path, which is wrong. We must schema-qualify all
722 * type names that are not in pg_catalog. We assume here that built-in types
723 * are all in pg_catalog and need not be qualified; otherwise, qualify.
724 */
725 static char *
deparse_type_name(Oid type_oid,int32 typemod)726 deparse_type_name(Oid type_oid, int32 typemod)
727 {
728 if (is_builtin(type_oid))
729 return format_type_with_typemod(type_oid, typemod);
730 else
731 return format_type_with_typemod_qualified(type_oid, typemod);
732 }
733
734 /*
735 * Build the targetlist for given relation to be deparsed as SELECT clause.
736 *
737 * The output targetlist contains the columns that need to be fetched from the
738 * foreign server for the given relation.
739 */
740 List *
build_tlist_to_deparse(RelOptInfo * foreignrel)741 build_tlist_to_deparse(RelOptInfo *foreignrel)
742 {
743 List *tlist = NIL;
744 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
745
746 /*
747 * We require columns specified in foreignrel->reltarget->exprs and those
748 * required for evaluating the local conditions.
749 */
750 tlist = add_to_flat_tlist(tlist,
751 pull_var_clause((Node *) foreignrel->reltarget->exprs,
752 PVC_RECURSE_PLACEHOLDERS));
753 tlist = add_to_flat_tlist(tlist,
754 pull_var_clause((Node *) fpinfo->local_conds,
755 PVC_RECURSE_PLACEHOLDERS));
756
757 return tlist;
758 }
759
760 /*
761 * Deparse SELECT statement for given relation into buf.
762 *
763 * tlist contains the list of desired columns to be fetched from foreign server.
764 * For a base relation fpinfo->attrs_used is used to construct SELECT clause,
765 * hence the tlist is ignored for a base relation.
766 *
767 * remote_conds is the list of conditions to be deparsed as WHERE clause.
768 *
769 * If params_list is not NULL, it receives a list of Params and other-relation
770 * Vars used in the clauses; these values must be transmitted to the remote
771 * server as parameter values.
772 *
773 * If params_list is NULL, we're generating the query for EXPLAIN purposes,
774 * so Params and other-relation Vars should be replaced by dummy values.
775 *
776 * pathkeys is the list of pathkeys to order the result by.
777 *
778 * List of columns selected is returned in retrieved_attrs.
779 */
780 extern void
deparseSelectStmtForRel(StringInfo buf,PlannerInfo * root,RelOptInfo * rel,List * tlist,List * remote_conds,List * pathkeys,List ** retrieved_attrs,List ** params_list)781 deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
782 List *tlist, List *remote_conds, List *pathkeys,
783 List **retrieved_attrs, List **params_list)
784 {
785 deparse_expr_cxt context;
786
787 /* We handle relations for foreign tables and joins between those */
788 Assert(rel->reloptkind == RELOPT_JOINREL ||
789 rel->reloptkind == RELOPT_BASEREL ||
790 rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
791
792 /* Fill portions of context common to join and base relation */
793 context.buf = buf;
794 context.root = root;
795 context.foreignrel = rel;
796 context.params_list = params_list;
797
798 /* Construct SELECT clause and FROM clause */
799 deparseSelectSql(tlist, retrieved_attrs, &context);
800
801 /*
802 * Construct WHERE clause
803 */
804 if (remote_conds)
805 {
806 appendStringInfo(buf, " WHERE ");
807 appendConditions(remote_conds, &context);
808 }
809
810 /* Add ORDER BY clause if we found any useful pathkeys */
811 if (pathkeys)
812 appendOrderByClause(pathkeys, &context);
813
814 /* Add any necessary FOR UPDATE/SHARE. */
815 deparseLockingClause(&context);
816 }
817
818 /*
819 * Construct a simple SELECT statement that retrieves desired columns
820 * of the specified foreign table, and append it to "buf". The output
821 * contains just "SELECT ... FROM ....".
822 *
823 * We also create an integer List of the columns being retrieved, which is
824 * returned to *retrieved_attrs.
825 *
826 * tlist is the list of desired columns. Read prologue of
827 * deparseSelectStmtForRel() for details.
828 */
829 static void
deparseSelectSql(List * tlist,List ** retrieved_attrs,deparse_expr_cxt * context)830 deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context)
831 {
832 StringInfo buf = context->buf;
833 RelOptInfo *foreignrel = context->foreignrel;
834 PlannerInfo *root = context->root;
835 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
836
837 /*
838 * Construct SELECT list
839 */
840 appendStringInfoString(buf, "SELECT ");
841
842 if (foreignrel->reloptkind == RELOPT_JOINREL)
843 {
844 /* For a join relation use the input tlist */
845 deparseExplicitTargetList(tlist, retrieved_attrs, context);
846 }
847 else
848 {
849 /*
850 * For a base relation fpinfo->attrs_used gives the list of columns
851 * required to be fetched from the foreign server.
852 */
853 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
854
855 /*
856 * Core code already has some lock on each rel being planned, so we
857 * can use NoLock here.
858 */
859 Relation rel = heap_open(rte->relid, NoLock);
860
861 deparseTargetList(buf, root, foreignrel->relid, rel, false,
862 fpinfo->attrs_used, false, retrieved_attrs);
863 heap_close(rel, NoLock);
864 }
865
866 /*
867 * Construct FROM clause
868 */
869 appendStringInfoString(buf, " FROM ");
870 deparseFromExprForRel(buf, root, foreignrel,
871 (foreignrel->reloptkind == RELOPT_JOINREL),
872 context->params_list);
873 }
874
875 /*
876 * Emit a target list that retrieves the columns specified in attrs_used.
877 * This is used for both SELECT and RETURNING targetlists; the is_returning
878 * parameter is true only for a RETURNING targetlist.
879 *
880 * The tlist text is appended to buf, and we also create an integer List
881 * of the columns being retrieved, which is returned to *retrieved_attrs.
882 *
883 * If qualify_col is true, add relation alias before the column name.
884 */
885 static void
deparseTargetList(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,bool is_returning,Bitmapset * attrs_used,bool qualify_col,List ** retrieved_attrs)886 deparseTargetList(StringInfo buf,
887 PlannerInfo *root,
888 Index rtindex,
889 Relation rel,
890 bool is_returning,
891 Bitmapset *attrs_used,
892 bool qualify_col,
893 List **retrieved_attrs)
894 {
895 TupleDesc tupdesc = RelationGetDescr(rel);
896 bool have_wholerow;
897 bool first;
898 int i;
899
900 *retrieved_attrs = NIL;
901
902 /* If there's a whole-row reference, we'll need all the columns. */
903 have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
904 attrs_used);
905
906 first = true;
907 for (i = 1; i <= tupdesc->natts; i++)
908 {
909 Form_pg_attribute attr = tupdesc->attrs[i - 1];
910
911 /* Ignore dropped attributes. */
912 if (attr->attisdropped)
913 continue;
914
915 if (have_wholerow ||
916 bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
917 attrs_used))
918 {
919 if (!first)
920 appendStringInfoString(buf, ", ");
921 else if (is_returning)
922 appendStringInfoString(buf, " RETURNING ");
923 first = false;
924
925 deparseColumnRef(buf, rtindex, i, root, qualify_col);
926
927 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
928 }
929 }
930
931 /*
932 * Add ctid if needed. We currently don't support retrieving any other
933 * system columns.
934 */
935 if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber,
936 attrs_used))
937 {
938 if (!first)
939 appendStringInfoString(buf, ", ");
940 else if (is_returning)
941 appendStringInfoString(buf, " RETURNING ");
942 first = false;
943
944 if (qualify_col)
945 ADD_REL_QUALIFIER(buf, rtindex);
946 appendStringInfoString(buf, "ctid");
947
948 *retrieved_attrs = lappend_int(*retrieved_attrs,
949 SelfItemPointerAttributeNumber);
950 }
951
952 /* Don't generate bad syntax if no undropped columns */
953 if (first && !is_returning)
954 appendStringInfoString(buf, "NULL");
955 }
956
957 /*
958 * Deparse the appropriate locking clause (FOR SELECT or FOR SHARE) for a
959 * given relation (context->foreignrel).
960 */
961 static void
deparseLockingClause(deparse_expr_cxt * context)962 deparseLockingClause(deparse_expr_cxt *context)
963 {
964 StringInfo buf = context->buf;
965 PlannerInfo *root = context->root;
966 RelOptInfo *rel = context->foreignrel;
967 int relid = -1;
968
969 while ((relid = bms_next_member(rel->relids, relid)) >= 0)
970 {
971 /*
972 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
973 * initial row fetch, rather than later on as is done for local
974 * tables. The extra roundtrips involved in trying to duplicate the
975 * local semantics exactly don't seem worthwhile (see also comments
976 * for RowMarkType).
977 *
978 * Note: because we actually run the query as a cursor, this assumes
979 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
980 * before 8.3.
981 */
982 if (relid == root->parse->resultRelation &&
983 (root->parse->commandType == CMD_UPDATE ||
984 root->parse->commandType == CMD_DELETE))
985 {
986 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
987 appendStringInfoString(buf, " FOR UPDATE");
988
989 /* Add the relation alias if we are here for a join relation */
990 if (rel->reloptkind == RELOPT_JOINREL)
991 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
992 }
993 else
994 {
995 PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
996
997 if (rc)
998 {
999 /*
1000 * Relation is specified as a FOR UPDATE/SHARE target, so
1001 * handle that. (But we could also see LCS_NONE, meaning this
1002 * isn't a target relation after all.)
1003 *
1004 * For now, just ignore any [NO] KEY specification, since (a)
1005 * it's not clear what that means for a remote table that we
1006 * don't have complete information about, and (b) it wouldn't
1007 * work anyway on older remote servers. Likewise, we don't
1008 * worry about NOWAIT.
1009 */
1010 switch (rc->strength)
1011 {
1012 case LCS_NONE:
1013 /* No locking needed */
1014 break;
1015 case LCS_FORKEYSHARE:
1016 case LCS_FORSHARE:
1017 appendStringInfoString(buf, " FOR SHARE");
1018 break;
1019 case LCS_FORNOKEYUPDATE:
1020 case LCS_FORUPDATE:
1021 appendStringInfoString(buf, " FOR UPDATE");
1022 break;
1023 }
1024
1025 /* Add the relation alias if we are here for a join relation */
1026 if (rel->reloptkind == RELOPT_JOINREL &&
1027 rc->strength != LCS_NONE)
1028 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1029 }
1030 }
1031 }
1032 }
1033
1034 /*
1035 * Deparse conditions from the provided list and append them to buf.
1036 *
1037 * The conditions in the list are assumed to be ANDed. This function is used to
1038 * deparse both WHERE clauses and JOIN .. ON clauses.
1039 */
1040 static void
appendConditions(List * exprs,deparse_expr_cxt * context)1041 appendConditions(List *exprs, deparse_expr_cxt *context)
1042 {
1043 int nestlevel;
1044 ListCell *lc;
1045 bool is_first = true;
1046 StringInfo buf = context->buf;
1047
1048 /* Make sure any constants in the exprs are printed portably */
1049 nestlevel = set_transmission_modes();
1050
1051 foreach(lc, exprs)
1052 {
1053 Expr *expr = (Expr *) lfirst(lc);
1054
1055 /*
1056 * Extract clause from RestrictInfo, if required. See comments in
1057 * declaration of PgFdwRelationInfo for details.
1058 */
1059 if (IsA(expr, RestrictInfo))
1060 {
1061 RestrictInfo *ri = (RestrictInfo *) expr;
1062
1063 expr = ri->clause;
1064 }
1065
1066 /* Connect expressions with "AND" and parenthesize each condition. */
1067 if (!is_first)
1068 appendStringInfoString(buf, " AND ");
1069
1070 appendStringInfoChar(buf, '(');
1071 deparseExpr(expr, context);
1072 appendStringInfoChar(buf, ')');
1073
1074 is_first = false;
1075 }
1076
1077 reset_transmission_modes(nestlevel);
1078 }
1079
1080 /* Output join name for given join type */
1081 extern const char *
get_jointype_name(JoinType jointype)1082 get_jointype_name(JoinType jointype)
1083 {
1084 switch (jointype)
1085 {
1086 case JOIN_INNER:
1087 return "INNER";
1088
1089 case JOIN_LEFT:
1090 return "LEFT";
1091
1092 case JOIN_RIGHT:
1093 return "RIGHT";
1094
1095 case JOIN_FULL:
1096 return "FULL";
1097
1098 default:
1099 /* Shouldn't come here, but protect from buggy code. */
1100 elog(ERROR, "unsupported join type %d", jointype);
1101 }
1102
1103 /* Keep compiler happy */
1104 return NULL;
1105 }
1106
1107 /*
1108 * Deparse given targetlist and append it to context->buf.
1109 *
1110 * tlist is list of TargetEntry's which in turn contain Var nodes.
1111 *
1112 * retrieved_attrs is the list of continuously increasing integers starting
1113 * from 1. It has same number of entries as tlist.
1114 */
1115 static void
deparseExplicitTargetList(List * tlist,List ** retrieved_attrs,deparse_expr_cxt * context)1116 deparseExplicitTargetList(List *tlist, List **retrieved_attrs,
1117 deparse_expr_cxt *context)
1118 {
1119 ListCell *lc;
1120 StringInfo buf = context->buf;
1121 int i = 0;
1122
1123 *retrieved_attrs = NIL;
1124
1125 foreach(lc, tlist)
1126 {
1127 TargetEntry *tle = (TargetEntry *) lfirst(lc);
1128 Var *var;
1129
1130 /* Extract expression if TargetEntry node */
1131 Assert(IsA(tle, TargetEntry));
1132 var = (Var *) tle->expr;
1133
1134 /* We expect only Var nodes here */
1135 if (!IsA(var, Var))
1136 elog(ERROR, "non-Var not expected in target list");
1137
1138 if (i > 0)
1139 appendStringInfoString(buf, ", ");
1140 deparseVar(var, context);
1141
1142 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1143
1144 i++;
1145 }
1146
1147 if (i == 0)
1148 appendStringInfoString(buf, "NULL");
1149 }
1150
1151 /*
1152 * Construct FROM clause for given relation
1153 *
1154 * The function constructs ... JOIN ... ON ... for join relation. For a base
1155 * relation it just returns schema-qualified tablename, with the appropriate
1156 * alias if so requested.
1157 */
1158 static void
deparseFromExprForRel(StringInfo buf,PlannerInfo * root,RelOptInfo * foreignrel,bool use_alias,List ** params_list)1159 deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
1160 bool use_alias, List **params_list)
1161 {
1162 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1163
1164 if (foreignrel->reloptkind == RELOPT_JOINREL)
1165 {
1166 RelOptInfo *rel_o = fpinfo->outerrel;
1167 RelOptInfo *rel_i = fpinfo->innerrel;
1168 StringInfoData join_sql_o;
1169 StringInfoData join_sql_i;
1170
1171 /* Deparse outer relation */
1172 initStringInfo(&join_sql_o);
1173 deparseFromExprForRel(&join_sql_o, root, rel_o, true, params_list);
1174
1175 /* Deparse inner relation */
1176 initStringInfo(&join_sql_i);
1177 deparseFromExprForRel(&join_sql_i, root, rel_i, true, params_list);
1178
1179 /*
1180 * For a join relation FROM clause entry is deparsed as
1181 *
1182 * ((outer relation) <join type> (inner relation) ON (joinclauses)
1183 */
1184 appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1185 get_jointype_name(fpinfo->jointype), join_sql_i.data);
1186
1187 /* Append join clause; (TRUE) if no join clause */
1188 if (fpinfo->joinclauses)
1189 {
1190 deparse_expr_cxt context;
1191
1192 context.buf = buf;
1193 context.foreignrel = foreignrel;
1194 context.root = root;
1195 context.params_list = params_list;
1196
1197 appendStringInfo(buf, "(");
1198 appendConditions(fpinfo->joinclauses, &context);
1199 appendStringInfo(buf, ")");
1200 }
1201 else
1202 appendStringInfoString(buf, "(TRUE)");
1203
1204 /* End the FROM clause entry. */
1205 appendStringInfo(buf, ")");
1206 }
1207 else
1208 {
1209 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1210
1211 /*
1212 * Core code already has some lock on each rel being planned, so we
1213 * can use NoLock here.
1214 */
1215 Relation rel = heap_open(rte->relid, NoLock);
1216
1217 deparseRelation(buf, rel);
1218
1219 /*
1220 * Add a unique alias to avoid any conflict in relation names due to
1221 * pulled up subqueries in the query being built for a pushed down
1222 * join.
1223 */
1224 if (use_alias)
1225 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
1226
1227 heap_close(rel, NoLock);
1228 }
1229 }
1230
1231 /*
1232 * deparse remote INSERT statement
1233 *
1234 * The statement text is appended to buf, and we also create an integer List
1235 * of the columns being retrieved by RETURNING (if any), which is returned
1236 * to *retrieved_attrs.
1237 */
1238 void
deparseInsertSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,List * targetAttrs,bool doNothing,List * returningList,List ** retrieved_attrs)1239 deparseInsertSql(StringInfo buf, PlannerInfo *root,
1240 Index rtindex, Relation rel,
1241 List *targetAttrs, bool doNothing,
1242 List *returningList, List **retrieved_attrs)
1243 {
1244 AttrNumber pindex;
1245 bool first;
1246 ListCell *lc;
1247
1248 appendStringInfoString(buf, "INSERT INTO ");
1249 deparseRelation(buf, rel);
1250
1251 if (targetAttrs)
1252 {
1253 appendStringInfoChar(buf, '(');
1254
1255 first = true;
1256 foreach(lc, targetAttrs)
1257 {
1258 int attnum = lfirst_int(lc);
1259
1260 if (!first)
1261 appendStringInfoString(buf, ", ");
1262 first = false;
1263
1264 deparseColumnRef(buf, rtindex, attnum, root, false);
1265 }
1266
1267 appendStringInfoString(buf, ") VALUES (");
1268
1269 pindex = 1;
1270 first = true;
1271 foreach(lc, targetAttrs)
1272 {
1273 if (!first)
1274 appendStringInfoString(buf, ", ");
1275 first = false;
1276
1277 appendStringInfo(buf, "$%d", pindex);
1278 pindex++;
1279 }
1280
1281 appendStringInfoChar(buf, ')');
1282 }
1283 else
1284 appendStringInfoString(buf, " DEFAULT VALUES");
1285
1286 if (doNothing)
1287 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
1288
1289 deparseReturningList(buf, root, rtindex, rel,
1290 rel->trigdesc && rel->trigdesc->trig_insert_after_row,
1291 returningList, retrieved_attrs);
1292 }
1293
1294 /*
1295 * deparse remote UPDATE statement
1296 *
1297 * The statement text is appended to buf, and we also create an integer List
1298 * of the columns being retrieved by RETURNING (if any), which is returned
1299 * to *retrieved_attrs.
1300 */
1301 void
deparseUpdateSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,List * targetAttrs,List * returningList,List ** retrieved_attrs)1302 deparseUpdateSql(StringInfo buf, PlannerInfo *root,
1303 Index rtindex, Relation rel,
1304 List *targetAttrs, List *returningList,
1305 List **retrieved_attrs)
1306 {
1307 AttrNumber pindex;
1308 bool first;
1309 ListCell *lc;
1310
1311 appendStringInfoString(buf, "UPDATE ");
1312 deparseRelation(buf, rel);
1313 appendStringInfoString(buf, " SET ");
1314
1315 pindex = 2; /* ctid is always the first param */
1316 first = true;
1317 foreach(lc, targetAttrs)
1318 {
1319 int attnum = lfirst_int(lc);
1320
1321 if (!first)
1322 appendStringInfoString(buf, ", ");
1323 first = false;
1324
1325 deparseColumnRef(buf, rtindex, attnum, root, false);
1326 appendStringInfo(buf, " = $%d", pindex);
1327 pindex++;
1328 }
1329 appendStringInfoString(buf, " WHERE ctid = $1");
1330
1331 deparseReturningList(buf, root, rtindex, rel,
1332 rel->trigdesc && rel->trigdesc->trig_update_after_row,
1333 returningList, retrieved_attrs);
1334 }
1335
1336 /*
1337 * deparse remote UPDATE statement
1338 *
1339 * The statement text is appended to buf, and we also create an integer List
1340 * of the columns being retrieved by RETURNING (if any), which is returned
1341 * to *retrieved_attrs.
1342 */
1343 void
deparseDirectUpdateSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,List * targetlist,List * targetAttrs,List * remote_conds,List ** params_list,List * returningList,List ** retrieved_attrs)1344 deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
1345 Index rtindex, Relation rel,
1346 List *targetlist,
1347 List *targetAttrs,
1348 List *remote_conds,
1349 List **params_list,
1350 List *returningList,
1351 List **retrieved_attrs)
1352 {
1353 RelOptInfo *baserel = root->simple_rel_array[rtindex];
1354 deparse_expr_cxt context;
1355 int nestlevel;
1356 bool first;
1357 ListCell *lc;
1358
1359 /* Set up context struct for recursion */
1360 context.root = root;
1361 context.foreignrel = baserel;
1362 context.buf = buf;
1363 context.params_list = params_list;
1364
1365 appendStringInfoString(buf, "UPDATE ");
1366 deparseRelation(buf, rel);
1367 appendStringInfoString(buf, " SET ");
1368
1369 /* Make sure any constants in the exprs are printed portably */
1370 nestlevel = set_transmission_modes();
1371
1372 first = true;
1373 foreach(lc, targetAttrs)
1374 {
1375 int attnum = lfirst_int(lc);
1376 TargetEntry *tle = get_tle_by_resno(targetlist, attnum);
1377
1378 if (!tle)
1379 elog(ERROR, "attribute number %d not found in UPDATE targetlist",
1380 attnum);
1381
1382 if (!first)
1383 appendStringInfoString(buf, ", ");
1384 first = false;
1385
1386 deparseColumnRef(buf, rtindex, attnum, root, false);
1387 appendStringInfoString(buf, " = ");
1388 deparseExpr((Expr *) tle->expr, &context);
1389 }
1390
1391 reset_transmission_modes(nestlevel);
1392
1393 if (remote_conds)
1394 {
1395 appendStringInfo(buf, " WHERE ");
1396 appendConditions(remote_conds, &context);
1397 }
1398
1399 deparseReturningList(buf, root, rtindex, rel, false,
1400 returningList, retrieved_attrs);
1401 }
1402
1403 /*
1404 * deparse remote DELETE statement
1405 *
1406 * The statement text is appended to buf, and we also create an integer List
1407 * of the columns being retrieved by RETURNING (if any), which is returned
1408 * to *retrieved_attrs.
1409 */
1410 void
deparseDeleteSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,List * returningList,List ** retrieved_attrs)1411 deparseDeleteSql(StringInfo buf, PlannerInfo *root,
1412 Index rtindex, Relation rel,
1413 List *returningList,
1414 List **retrieved_attrs)
1415 {
1416 appendStringInfoString(buf, "DELETE FROM ");
1417 deparseRelation(buf, rel);
1418 appendStringInfoString(buf, " WHERE ctid = $1");
1419
1420 deparseReturningList(buf, root, rtindex, rel,
1421 rel->trigdesc && rel->trigdesc->trig_delete_after_row,
1422 returningList, retrieved_attrs);
1423 }
1424
1425 /*
1426 * deparse remote DELETE statement
1427 *
1428 * The statement text is appended to buf, and we also create an integer List
1429 * of the columns being retrieved by RETURNING (if any), which is returned
1430 * to *retrieved_attrs.
1431 */
1432 void
deparseDirectDeleteSql(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,List * remote_conds,List ** params_list,List * returningList,List ** retrieved_attrs)1433 deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
1434 Index rtindex, Relation rel,
1435 List *remote_conds,
1436 List **params_list,
1437 List *returningList,
1438 List **retrieved_attrs)
1439 {
1440 RelOptInfo *baserel = root->simple_rel_array[rtindex];
1441 deparse_expr_cxt context;
1442
1443 /* Set up context struct for recursion */
1444 context.root = root;
1445 context.foreignrel = baserel;
1446 context.buf = buf;
1447 context.params_list = params_list;
1448
1449 appendStringInfoString(buf, "DELETE FROM ");
1450 deparseRelation(buf, rel);
1451
1452 if (remote_conds)
1453 {
1454 appendStringInfo(buf, " WHERE ");
1455 appendConditions(remote_conds, &context);
1456 }
1457
1458 deparseReturningList(buf, root, rtindex, rel, false,
1459 returningList, retrieved_attrs);
1460 }
1461
1462 /*
1463 * Add a RETURNING clause, if needed, to an INSERT/UPDATE/DELETE.
1464 */
1465 static void
deparseReturningList(StringInfo buf,PlannerInfo * root,Index rtindex,Relation rel,bool trig_after_row,List * returningList,List ** retrieved_attrs)1466 deparseReturningList(StringInfo buf, PlannerInfo *root,
1467 Index rtindex, Relation rel,
1468 bool trig_after_row,
1469 List *returningList,
1470 List **retrieved_attrs)
1471 {
1472 Bitmapset *attrs_used = NULL;
1473
1474 if (trig_after_row)
1475 {
1476 /* whole-row reference acquires all non-system columns */
1477 attrs_used =
1478 bms_make_singleton(0 - FirstLowInvalidHeapAttributeNumber);
1479 }
1480
1481 if (returningList != NIL)
1482 {
1483 /*
1484 * We need the attrs, non-system and system, mentioned in the local
1485 * query's RETURNING list.
1486 */
1487 pull_varattnos((Node *) returningList, rtindex,
1488 &attrs_used);
1489 }
1490
1491 if (attrs_used != NULL)
1492 deparseTargetList(buf, root, rtindex, rel, true, attrs_used, false,
1493 retrieved_attrs);
1494 else
1495 *retrieved_attrs = NIL;
1496 }
1497
1498 /*
1499 * Construct SELECT statement to acquire size in blocks of given relation.
1500 *
1501 * Note: we use local definition of block size, not remote definition.
1502 * This is perhaps debatable.
1503 *
1504 * Note: pg_relation_size() exists in 8.1 and later.
1505 */
1506 void
deparseAnalyzeSizeSql(StringInfo buf,Relation rel)1507 deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
1508 {
1509 StringInfoData relname;
1510
1511 /* We'll need the remote relation name as a literal. */
1512 initStringInfo(&relname);
1513 deparseRelation(&relname, rel);
1514
1515 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
1516 deparseStringLiteral(buf, relname.data);
1517 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
1518 }
1519
1520 /*
1521 * Construct SELECT statement to acquire sample rows of given relation.
1522 *
1523 * SELECT command is appended to buf, and list of columns retrieved
1524 * is returned to *retrieved_attrs.
1525 */
1526 void
deparseAnalyzeSql(StringInfo buf,Relation rel,List ** retrieved_attrs)1527 deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
1528 {
1529 Oid relid = RelationGetRelid(rel);
1530 TupleDesc tupdesc = RelationGetDescr(rel);
1531 int i;
1532 char *colname;
1533 List *options;
1534 ListCell *lc;
1535 bool first = true;
1536
1537 *retrieved_attrs = NIL;
1538
1539 appendStringInfoString(buf, "SELECT ");
1540 for (i = 0; i < tupdesc->natts; i++)
1541 {
1542 /* Ignore dropped columns. */
1543 if (tupdesc->attrs[i]->attisdropped)
1544 continue;
1545
1546 if (!first)
1547 appendStringInfoString(buf, ", ");
1548 first = false;
1549
1550 /* Use attribute name or column_name option. */
1551 colname = NameStr(tupdesc->attrs[i]->attname);
1552 options = GetForeignColumnOptions(relid, i + 1);
1553
1554 foreach(lc, options)
1555 {
1556 DefElem *def = (DefElem *) lfirst(lc);
1557
1558 if (strcmp(def->defname, "column_name") == 0)
1559 {
1560 colname = defGetString(def);
1561 break;
1562 }
1563 }
1564
1565 appendStringInfoString(buf, quote_identifier(colname));
1566
1567 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1568 }
1569
1570 /* Don't generate bad syntax for zero-column relation. */
1571 if (first)
1572 appendStringInfoString(buf, "NULL");
1573
1574 /*
1575 * Construct FROM clause
1576 */
1577 appendStringInfoString(buf, " FROM ");
1578 deparseRelation(buf, rel);
1579 }
1580
1581 /*
1582 * Construct name to use for given column, and emit it into buf.
1583 * If it has a column_name FDW option, use that instead of attribute name.
1584 *
1585 * If qualify_col is true, qualify column name with the alias of relation.
1586 */
1587 static void
deparseColumnRef(StringInfo buf,int varno,int varattno,PlannerInfo * root,bool qualify_col)1588 deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root,
1589 bool qualify_col)
1590 {
1591 RangeTblEntry *rte;
1592
1593 if (varattno == SelfItemPointerAttributeNumber)
1594 {
1595 /* We support fetching the remote side's CTID. */
1596 if (qualify_col)
1597 ADD_REL_QUALIFIER(buf, varno);
1598 appendStringInfoString(buf, "ctid");
1599 }
1600 else if (varattno < 0)
1601 {
1602 /*
1603 * All other system attributes are fetched as 0, except for table OID,
1604 * which is fetched as the local table OID. However, we must be
1605 * careful; the table could be beneath an outer join, in which case it
1606 * must go to NULL whenever the rest of the row does.
1607 */
1608 Oid fetchval = 0;
1609
1610 if (varattno == TableOidAttributeNumber)
1611 {
1612 rte = planner_rt_fetch(varno, root);
1613 fetchval = rte->relid;
1614 }
1615
1616 if (qualify_col)
1617 {
1618 appendStringInfoString(buf, "CASE WHEN (");
1619 ADD_REL_QUALIFIER(buf, varno);
1620 appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
1621 }
1622 else
1623 appendStringInfo(buf, "%u", fetchval);
1624 }
1625 else if (varattno == 0)
1626 {
1627 /* Whole row reference */
1628 Relation rel;
1629 Bitmapset *attrs_used;
1630
1631 /* Required only to be passed down to deparseTargetList(). */
1632 List *retrieved_attrs;
1633
1634 /* Get RangeTblEntry from array in PlannerInfo. */
1635 rte = planner_rt_fetch(varno, root);
1636
1637 /*
1638 * The lock on the relation will be held by upper callers, so it's
1639 * fine to open it with no lock here.
1640 */
1641 rel = heap_open(rte->relid, NoLock);
1642
1643 /*
1644 * The local name of the foreign table can not be recognized by the
1645 * foreign server and the table it references on foreign server might
1646 * have different column ordering or different columns than those
1647 * declared locally. Hence we have to deparse whole-row reference as
1648 * ROW(columns referenced locally). Construct this by deparsing a
1649 * "whole row" attribute.
1650 */
1651 attrs_used = bms_add_member(NULL,
1652 0 - FirstLowInvalidHeapAttributeNumber);
1653
1654 /*
1655 * In case the whole-row reference is under an outer join then it has
1656 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
1657 * query would always involve multiple relations, thus qualify_col
1658 * would be true.
1659 */
1660 if (qualify_col)
1661 {
1662 appendStringInfoString(buf, "CASE WHEN (");
1663 ADD_REL_QUALIFIER(buf, varno);
1664 appendStringInfo(buf, "*)::text IS NOT NULL THEN ");
1665 }
1666
1667 appendStringInfoString(buf, "ROW(");
1668 deparseTargetList(buf, root, varno, rel, false, attrs_used, qualify_col,
1669 &retrieved_attrs);
1670 appendStringInfoString(buf, ")");
1671
1672 /* Complete the CASE WHEN statement started above. */
1673 if (qualify_col)
1674 appendStringInfo(buf, " END");
1675
1676 heap_close(rel, NoLock);
1677 bms_free(attrs_used);
1678 }
1679 else
1680 {
1681 char *colname = NULL;
1682 List *options;
1683 ListCell *lc;
1684
1685 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
1686 Assert(!IS_SPECIAL_VARNO(varno));
1687
1688 /* Get RangeTblEntry from array in PlannerInfo. */
1689 rte = planner_rt_fetch(varno, root);
1690
1691 /*
1692 * If it's a column of a foreign table, and it has the column_name FDW
1693 * option, use that value.
1694 */
1695 options = GetForeignColumnOptions(rte->relid, varattno);
1696 foreach(lc, options)
1697 {
1698 DefElem *def = (DefElem *) lfirst(lc);
1699
1700 if (strcmp(def->defname, "column_name") == 0)
1701 {
1702 colname = defGetString(def);
1703 break;
1704 }
1705 }
1706
1707 /*
1708 * If it's a column of a regular table or it doesn't have column_name
1709 * FDW option, use attribute name.
1710 */
1711 if (colname == NULL)
1712 colname = get_relid_attribute_name(rte->relid, varattno);
1713
1714 if (qualify_col)
1715 ADD_REL_QUALIFIER(buf, varno);
1716
1717 appendStringInfoString(buf, quote_identifier(colname));
1718 }
1719 }
1720
1721 /*
1722 * Append remote name of specified foreign table to buf.
1723 * Use value of table_name FDW option (if any) instead of relation's name.
1724 * Similarly, schema_name FDW option overrides schema name.
1725 */
1726 static void
deparseRelation(StringInfo buf,Relation rel)1727 deparseRelation(StringInfo buf, Relation rel)
1728 {
1729 ForeignTable *table;
1730 const char *nspname = NULL;
1731 const char *relname = NULL;
1732 ListCell *lc;
1733
1734 /* obtain additional catalog information. */
1735 table = GetForeignTable(RelationGetRelid(rel));
1736
1737 /*
1738 * Use value of FDW options if any, instead of the name of object itself.
1739 */
1740 foreach(lc, table->options)
1741 {
1742 DefElem *def = (DefElem *) lfirst(lc);
1743
1744 if (strcmp(def->defname, "schema_name") == 0)
1745 nspname = defGetString(def);
1746 else if (strcmp(def->defname, "table_name") == 0)
1747 relname = defGetString(def);
1748 }
1749
1750 /*
1751 * Note: we could skip printing the schema name if it's pg_catalog, but
1752 * that doesn't seem worth the trouble.
1753 */
1754 if (nspname == NULL)
1755 nspname = get_namespace_name(RelationGetNamespace(rel));
1756 if (relname == NULL)
1757 relname = RelationGetRelationName(rel);
1758
1759 appendStringInfo(buf, "%s.%s",
1760 quote_identifier(nspname), quote_identifier(relname));
1761 }
1762
1763 /*
1764 * Append a SQL string literal representing "val" to buf.
1765 */
1766 void
deparseStringLiteral(StringInfo buf,const char * val)1767 deparseStringLiteral(StringInfo buf, const char *val)
1768 {
1769 const char *valptr;
1770
1771 /*
1772 * Rather than making assumptions about the remote server's value of
1773 * standard_conforming_strings, always use E'foo' syntax if there are any
1774 * backslashes. This will fail on remote servers before 8.1, but those
1775 * are long out of support.
1776 */
1777 if (strchr(val, '\\') != NULL)
1778 appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
1779 appendStringInfoChar(buf, '\'');
1780 for (valptr = val; *valptr; valptr++)
1781 {
1782 char ch = *valptr;
1783
1784 if (SQL_STR_DOUBLE(ch, true))
1785 appendStringInfoChar(buf, ch);
1786 appendStringInfoChar(buf, ch);
1787 }
1788 appendStringInfoChar(buf, '\'');
1789 }
1790
1791 /*
1792 * Deparse given expression into context->buf.
1793 *
1794 * This function must support all the same node types that foreign_expr_walker
1795 * accepts.
1796 *
1797 * Note: unlike ruleutils.c, we just use a simple hard-wired parenthesization
1798 * scheme: anything more complex than a Var, Const, function call or cast
1799 * should be self-parenthesized.
1800 */
1801 static void
deparseExpr(Expr * node,deparse_expr_cxt * context)1802 deparseExpr(Expr *node, deparse_expr_cxt *context)
1803 {
1804 if (node == NULL)
1805 return;
1806
1807 switch (nodeTag(node))
1808 {
1809 case T_Var:
1810 deparseVar((Var *) node, context);
1811 break;
1812 case T_Const:
1813 deparseConst((Const *) node, context);
1814 break;
1815 case T_Param:
1816 deparseParam((Param *) node, context);
1817 break;
1818 case T_ArrayRef:
1819 deparseArrayRef((ArrayRef *) node, context);
1820 break;
1821 case T_FuncExpr:
1822 deparseFuncExpr((FuncExpr *) node, context);
1823 break;
1824 case T_OpExpr:
1825 deparseOpExpr((OpExpr *) node, context);
1826 break;
1827 case T_DistinctExpr:
1828 deparseDistinctExpr((DistinctExpr *) node, context);
1829 break;
1830 case T_ScalarArrayOpExpr:
1831 deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
1832 break;
1833 case T_RelabelType:
1834 deparseRelabelType((RelabelType *) node, context);
1835 break;
1836 case T_BoolExpr:
1837 deparseBoolExpr((BoolExpr *) node, context);
1838 break;
1839 case T_NullTest:
1840 deparseNullTest((NullTest *) node, context);
1841 break;
1842 case T_ArrayExpr:
1843 deparseArrayExpr((ArrayExpr *) node, context);
1844 break;
1845 default:
1846 elog(ERROR, "unsupported expression type for deparse: %d",
1847 (int) nodeTag(node));
1848 break;
1849 }
1850 }
1851
1852 /*
1853 * Deparse given Var node into context->buf.
1854 *
1855 * If the Var belongs to the foreign relation, just print its remote name.
1856 * Otherwise, it's effectively a Param (and will in fact be a Param at
1857 * run time). Handle it the same way we handle plain Params --- see
1858 * deparseParam for comments.
1859 */
1860 static void
deparseVar(Var * node,deparse_expr_cxt * context)1861 deparseVar(Var *node, deparse_expr_cxt *context)
1862 {
1863 bool qualify_col = (context->foreignrel->reloptkind == RELOPT_JOINREL);
1864
1865 if (bms_is_member(node->varno, context->foreignrel->relids) &&
1866 node->varlevelsup == 0)
1867 deparseColumnRef(context->buf, node->varno, node->varattno,
1868 context->root, qualify_col);
1869 else
1870 {
1871 /* Treat like a Param */
1872 if (context->params_list)
1873 {
1874 int pindex = 0;
1875 ListCell *lc;
1876
1877 /* find its index in params_list */
1878 foreach(lc, *context->params_list)
1879 {
1880 pindex++;
1881 if (equal(node, (Node *) lfirst(lc)))
1882 break;
1883 }
1884 if (lc == NULL)
1885 {
1886 /* not in list, so add it */
1887 pindex++;
1888 *context->params_list = lappend(*context->params_list, node);
1889 }
1890
1891 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
1892 }
1893 else
1894 {
1895 printRemotePlaceholder(node->vartype, node->vartypmod, context);
1896 }
1897 }
1898 }
1899
1900 /*
1901 * Deparse given constant value into context->buf.
1902 *
1903 * This function has to be kept in sync with ruleutils.c's get_const_expr.
1904 */
1905 static void
deparseConst(Const * node,deparse_expr_cxt * context)1906 deparseConst(Const *node, deparse_expr_cxt *context)
1907 {
1908 StringInfo buf = context->buf;
1909 Oid typoutput;
1910 bool typIsVarlena;
1911 char *extval;
1912 bool isfloat = false;
1913 bool needlabel;
1914
1915 if (node->constisnull)
1916 {
1917 appendStringInfoString(buf, "NULL");
1918 appendStringInfo(buf, "::%s",
1919 deparse_type_name(node->consttype,
1920 node->consttypmod));
1921 return;
1922 }
1923
1924 getTypeOutputInfo(node->consttype,
1925 &typoutput, &typIsVarlena);
1926 extval = OidOutputFunctionCall(typoutput, node->constvalue);
1927
1928 switch (node->consttype)
1929 {
1930 case INT2OID:
1931 case INT4OID:
1932 case INT8OID:
1933 case OIDOID:
1934 case FLOAT4OID:
1935 case FLOAT8OID:
1936 case NUMERICOID:
1937 {
1938 /*
1939 * No need to quote unless it's a special value such as 'NaN'.
1940 * See comments in get_const_expr().
1941 */
1942 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
1943 {
1944 if (extval[0] == '+' || extval[0] == '-')
1945 appendStringInfo(buf, "(%s)", extval);
1946 else
1947 appendStringInfoString(buf, extval);
1948 if (strcspn(extval, "eE.") != strlen(extval))
1949 isfloat = true; /* it looks like a float */
1950 }
1951 else
1952 appendStringInfo(buf, "'%s'", extval);
1953 }
1954 break;
1955 case BITOID:
1956 case VARBITOID:
1957 appendStringInfo(buf, "B'%s'", extval);
1958 break;
1959 case BOOLOID:
1960 if (strcmp(extval, "t") == 0)
1961 appendStringInfoString(buf, "true");
1962 else
1963 appendStringInfoString(buf, "false");
1964 break;
1965 default:
1966 deparseStringLiteral(buf, extval);
1967 break;
1968 }
1969
1970 /*
1971 * Append ::typename unless the constant will be implicitly typed as the
1972 * right type when it is read in.
1973 *
1974 * XXX this code has to be kept in sync with the behavior of the parser,
1975 * especially make_const.
1976 */
1977 switch (node->consttype)
1978 {
1979 case BOOLOID:
1980 case INT4OID:
1981 case UNKNOWNOID:
1982 needlabel = false;
1983 break;
1984 case NUMERICOID:
1985 needlabel = !isfloat || (node->consttypmod >= 0);
1986 break;
1987 default:
1988 needlabel = true;
1989 break;
1990 }
1991 if (needlabel)
1992 appendStringInfo(buf, "::%s",
1993 deparse_type_name(node->consttype,
1994 node->consttypmod));
1995 }
1996
1997 /*
1998 * Deparse given Param node.
1999 *
2000 * If we're generating the query "for real", add the Param to
2001 * context->params_list if it's not already present, and then use its index
2002 * in that list as the remote parameter number. During EXPLAIN, there's
2003 * no need to identify a parameter number.
2004 */
2005 static void
deparseParam(Param * node,deparse_expr_cxt * context)2006 deparseParam(Param *node, deparse_expr_cxt *context)
2007 {
2008 if (context->params_list)
2009 {
2010 int pindex = 0;
2011 ListCell *lc;
2012
2013 /* find its index in params_list */
2014 foreach(lc, *context->params_list)
2015 {
2016 pindex++;
2017 if (equal(node, (Node *) lfirst(lc)))
2018 break;
2019 }
2020 if (lc == NULL)
2021 {
2022 /* not in list, so add it */
2023 pindex++;
2024 *context->params_list = lappend(*context->params_list, node);
2025 }
2026
2027 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
2028 }
2029 else
2030 {
2031 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
2032 }
2033 }
2034
2035 /*
2036 * Deparse an array subscript expression.
2037 */
2038 static void
deparseArrayRef(ArrayRef * node,deparse_expr_cxt * context)2039 deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context)
2040 {
2041 StringInfo buf = context->buf;
2042 ListCell *lowlist_item;
2043 ListCell *uplist_item;
2044
2045 /* Always parenthesize the expression. */
2046 appendStringInfoChar(buf, '(');
2047
2048 /*
2049 * Deparse referenced array expression first. If that expression includes
2050 * a cast, we have to parenthesize to prevent the array subscript from
2051 * being taken as typename decoration. We can avoid that in the typical
2052 * case of subscripting a Var, but otherwise do it.
2053 */
2054 if (IsA(node->refexpr, Var))
2055 deparseExpr(node->refexpr, context);
2056 else
2057 {
2058 appendStringInfoChar(buf, '(');
2059 deparseExpr(node->refexpr, context);
2060 appendStringInfoChar(buf, ')');
2061 }
2062
2063 /* Deparse subscript expressions. */
2064 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
2065 foreach(uplist_item, node->refupperindexpr)
2066 {
2067 appendStringInfoChar(buf, '[');
2068 if (lowlist_item)
2069 {
2070 deparseExpr(lfirst(lowlist_item), context);
2071 appendStringInfoChar(buf, ':');
2072 lowlist_item = lnext(lowlist_item);
2073 }
2074 deparseExpr(lfirst(uplist_item), context);
2075 appendStringInfoChar(buf, ']');
2076 }
2077
2078 appendStringInfoChar(buf, ')');
2079 }
2080
2081 /*
2082 * Deparse a function call.
2083 */
2084 static void
deparseFuncExpr(FuncExpr * node,deparse_expr_cxt * context)2085 deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
2086 {
2087 StringInfo buf = context->buf;
2088 HeapTuple proctup;
2089 Form_pg_proc procform;
2090 const char *proname;
2091 bool use_variadic;
2092 bool first;
2093 ListCell *arg;
2094
2095 /*
2096 * If the function call came from an implicit coercion, then just show the
2097 * first argument.
2098 */
2099 if (node->funcformat == COERCE_IMPLICIT_CAST)
2100 {
2101 deparseExpr((Expr *) linitial(node->args), context);
2102 return;
2103 }
2104
2105 /*
2106 * If the function call came from a cast, then show the first argument
2107 * plus an explicit cast operation.
2108 */
2109 if (node->funcformat == COERCE_EXPLICIT_CAST)
2110 {
2111 Oid rettype = node->funcresulttype;
2112 int32 coercedTypmod;
2113
2114 /* Get the typmod if this is a length-coercion function */
2115 (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
2116
2117 deparseExpr((Expr *) linitial(node->args), context);
2118 appendStringInfo(buf, "::%s",
2119 deparse_type_name(rettype, coercedTypmod));
2120 return;
2121 }
2122
2123 /*
2124 * Normal function: display as proname(args).
2125 */
2126 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(node->funcid));
2127 if (!HeapTupleIsValid(proctup))
2128 elog(ERROR, "cache lookup failed for function %u", node->funcid);
2129 procform = (Form_pg_proc) GETSTRUCT(proctup);
2130
2131 /* Check if need to print VARIADIC (cf. ruleutils.c) */
2132 use_variadic = node->funcvariadic;
2133
2134 /* Print schema name only if it's not pg_catalog */
2135 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
2136 {
2137 const char *schemaname;
2138
2139 schemaname = get_namespace_name(procform->pronamespace);
2140 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
2141 }
2142
2143 /* Deparse the function name ... */
2144 proname = NameStr(procform->proname);
2145 appendStringInfo(buf, "%s(", quote_identifier(proname));
2146 /* ... and all the arguments */
2147 first = true;
2148 foreach(arg, node->args)
2149 {
2150 if (!first)
2151 appendStringInfoString(buf, ", ");
2152 if (use_variadic && lnext(arg) == NULL)
2153 appendStringInfoString(buf, "VARIADIC ");
2154 deparseExpr((Expr *) lfirst(arg), context);
2155 first = false;
2156 }
2157 appendStringInfoChar(buf, ')');
2158
2159 ReleaseSysCache(proctup);
2160 }
2161
2162 /*
2163 * Deparse given operator expression. To avoid problems around
2164 * priority of operations, we always parenthesize the arguments.
2165 */
2166 static void
deparseOpExpr(OpExpr * node,deparse_expr_cxt * context)2167 deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
2168 {
2169 StringInfo buf = context->buf;
2170 HeapTuple tuple;
2171 Form_pg_operator form;
2172 char oprkind;
2173 ListCell *arg;
2174
2175 /* Retrieve information about the operator from system catalog. */
2176 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
2177 if (!HeapTupleIsValid(tuple))
2178 elog(ERROR, "cache lookup failed for operator %u", node->opno);
2179 form = (Form_pg_operator) GETSTRUCT(tuple);
2180 oprkind = form->oprkind;
2181
2182 /* Sanity check. */
2183 Assert((oprkind == 'r' && list_length(node->args) == 1) ||
2184 (oprkind == 'l' && list_length(node->args) == 1) ||
2185 (oprkind == 'b' && list_length(node->args) == 2));
2186
2187 /* Always parenthesize the expression. */
2188 appendStringInfoChar(buf, '(');
2189
2190 /* Deparse left operand. */
2191 if (oprkind == 'r' || oprkind == 'b')
2192 {
2193 arg = list_head(node->args);
2194 deparseExpr(lfirst(arg), context);
2195 appendStringInfoChar(buf, ' ');
2196 }
2197
2198 /* Deparse operator name. */
2199 deparseOperatorName(buf, form);
2200
2201 /* Deparse right operand. */
2202 if (oprkind == 'l' || oprkind == 'b')
2203 {
2204 arg = list_tail(node->args);
2205 appendStringInfoChar(buf, ' ');
2206 deparseExpr(lfirst(arg), context);
2207 }
2208
2209 appendStringInfoChar(buf, ')');
2210
2211 ReleaseSysCache(tuple);
2212 }
2213
2214 /*
2215 * Print the name of an operator.
2216 */
2217 static void
deparseOperatorName(StringInfo buf,Form_pg_operator opform)2218 deparseOperatorName(StringInfo buf, Form_pg_operator opform)
2219 {
2220 char *opname;
2221
2222 /* opname is not a SQL identifier, so we should not quote it. */
2223 opname = NameStr(opform->oprname);
2224
2225 /* Print schema name only if it's not pg_catalog */
2226 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
2227 {
2228 const char *opnspname;
2229
2230 opnspname = get_namespace_name(opform->oprnamespace);
2231 /* Print fully qualified operator name. */
2232 appendStringInfo(buf, "OPERATOR(%s.%s)",
2233 quote_identifier(opnspname), opname);
2234 }
2235 else
2236 {
2237 /* Just print operator name. */
2238 appendStringInfoString(buf, opname);
2239 }
2240 }
2241
2242 /*
2243 * Deparse IS DISTINCT FROM.
2244 */
2245 static void
deparseDistinctExpr(DistinctExpr * node,deparse_expr_cxt * context)2246 deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
2247 {
2248 StringInfo buf = context->buf;
2249
2250 Assert(list_length(node->args) == 2);
2251
2252 appendStringInfoChar(buf, '(');
2253 deparseExpr(linitial(node->args), context);
2254 appendStringInfoString(buf, " IS DISTINCT FROM ");
2255 deparseExpr(lsecond(node->args), context);
2256 appendStringInfoChar(buf, ')');
2257 }
2258
2259 /*
2260 * Deparse given ScalarArrayOpExpr expression. To avoid problems
2261 * around priority of operations, we always parenthesize the arguments.
2262 */
2263 static void
deparseScalarArrayOpExpr(ScalarArrayOpExpr * node,deparse_expr_cxt * context)2264 deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
2265 {
2266 StringInfo buf = context->buf;
2267 HeapTuple tuple;
2268 Form_pg_operator form;
2269 Expr *arg1;
2270 Expr *arg2;
2271
2272 /* Retrieve information about the operator from system catalog. */
2273 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
2274 if (!HeapTupleIsValid(tuple))
2275 elog(ERROR, "cache lookup failed for operator %u", node->opno);
2276 form = (Form_pg_operator) GETSTRUCT(tuple);
2277
2278 /* Sanity check. */
2279 Assert(list_length(node->args) == 2);
2280
2281 /* Always parenthesize the expression. */
2282 appendStringInfoChar(buf, '(');
2283
2284 /* Deparse left operand. */
2285 arg1 = linitial(node->args);
2286 deparseExpr(arg1, context);
2287 appendStringInfoChar(buf, ' ');
2288
2289 /* Deparse operator name plus decoration. */
2290 deparseOperatorName(buf, form);
2291 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
2292
2293 /* Deparse right operand. */
2294 arg2 = lsecond(node->args);
2295 deparseExpr(arg2, context);
2296
2297 appendStringInfoChar(buf, ')');
2298
2299 /* Always parenthesize the expression. */
2300 appendStringInfoChar(buf, ')');
2301
2302 ReleaseSysCache(tuple);
2303 }
2304
2305 /*
2306 * Deparse a RelabelType (binary-compatible cast) node.
2307 */
2308 static void
deparseRelabelType(RelabelType * node,deparse_expr_cxt * context)2309 deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
2310 {
2311 deparseExpr(node->arg, context);
2312 if (node->relabelformat != COERCE_IMPLICIT_CAST)
2313 appendStringInfo(context->buf, "::%s",
2314 deparse_type_name(node->resulttype,
2315 node->resulttypmod));
2316 }
2317
2318 /*
2319 * Deparse a BoolExpr node.
2320 */
2321 static void
deparseBoolExpr(BoolExpr * node,deparse_expr_cxt * context)2322 deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
2323 {
2324 StringInfo buf = context->buf;
2325 const char *op = NULL; /* keep compiler quiet */
2326 bool first;
2327 ListCell *lc;
2328
2329 switch (node->boolop)
2330 {
2331 case AND_EXPR:
2332 op = "AND";
2333 break;
2334 case OR_EXPR:
2335 op = "OR";
2336 break;
2337 case NOT_EXPR:
2338 appendStringInfoString(buf, "(NOT ");
2339 deparseExpr(linitial(node->args), context);
2340 appendStringInfoChar(buf, ')');
2341 return;
2342 }
2343
2344 appendStringInfoChar(buf, '(');
2345 first = true;
2346 foreach(lc, node->args)
2347 {
2348 if (!first)
2349 appendStringInfo(buf, " %s ", op);
2350 deparseExpr((Expr *) lfirst(lc), context);
2351 first = false;
2352 }
2353 appendStringInfoChar(buf, ')');
2354 }
2355
2356 /*
2357 * Deparse IS [NOT] NULL expression.
2358 */
2359 static void
deparseNullTest(NullTest * node,deparse_expr_cxt * context)2360 deparseNullTest(NullTest *node, deparse_expr_cxt *context)
2361 {
2362 StringInfo buf = context->buf;
2363
2364 appendStringInfoChar(buf, '(');
2365 deparseExpr(node->arg, context);
2366
2367 /*
2368 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
2369 * shorter and traditional. If it's a rowtype input but we're applying a
2370 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
2371 * correct.
2372 */
2373 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
2374 {
2375 if (node->nulltesttype == IS_NULL)
2376 appendStringInfoString(buf, " IS NULL)");
2377 else
2378 appendStringInfoString(buf, " IS NOT NULL)");
2379 }
2380 else
2381 {
2382 if (node->nulltesttype == IS_NULL)
2383 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
2384 else
2385 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
2386 }
2387 }
2388
2389 /*
2390 * Deparse ARRAY[...] construct.
2391 */
2392 static void
deparseArrayExpr(ArrayExpr * node,deparse_expr_cxt * context)2393 deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
2394 {
2395 StringInfo buf = context->buf;
2396 bool first = true;
2397 ListCell *lc;
2398
2399 appendStringInfoString(buf, "ARRAY[");
2400 foreach(lc, node->elements)
2401 {
2402 if (!first)
2403 appendStringInfoString(buf, ", ");
2404 deparseExpr(lfirst(lc), context);
2405 first = false;
2406 }
2407 appendStringInfoChar(buf, ']');
2408
2409 /* If the array is empty, we need an explicit cast to the array type. */
2410 if (node->elements == NIL)
2411 appendStringInfo(buf, "::%s",
2412 deparse_type_name(node->array_typeid, -1));
2413 }
2414
2415 /*
2416 * Print the representation of a parameter to be sent to the remote side.
2417 *
2418 * Note: we always label the Param's type explicitly rather than relying on
2419 * transmitting a numeric type OID in PQexecParams(). This allows us to
2420 * avoid assuming that types have the same OIDs on the remote side as they
2421 * do locally --- they need only have the same names.
2422 */
2423 static void
printRemoteParam(int paramindex,Oid paramtype,int32 paramtypmod,deparse_expr_cxt * context)2424 printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
2425 deparse_expr_cxt *context)
2426 {
2427 StringInfo buf = context->buf;
2428 char *ptypename = deparse_type_name(paramtype, paramtypmod);
2429
2430 appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
2431 }
2432
2433 /*
2434 * Print the representation of a placeholder for a parameter that will be
2435 * sent to the remote side at execution time.
2436 *
2437 * This is used when we're just trying to EXPLAIN the remote query.
2438 * We don't have the actual value of the runtime parameter yet, and we don't
2439 * want the remote planner to generate a plan that depends on such a value
2440 * anyway. Thus, we can't do something simple like "$1::paramtype".
2441 * Instead, we emit "((SELECT null::paramtype)::paramtype)".
2442 * In all extant versions of Postgres, the planner will see that as an unknown
2443 * constant value, which is what we want. This might need adjustment if we
2444 * ever make the planner flatten scalar subqueries. Note: the reason for the
2445 * apparently useless outer cast is to ensure that the representation as a
2446 * whole will be parsed as an a_expr and not a select_with_parens; the latter
2447 * would do the wrong thing in the context "x = ANY(...)".
2448 */
2449 static void
printRemotePlaceholder(Oid paramtype,int32 paramtypmod,deparse_expr_cxt * context)2450 printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
2451 deparse_expr_cxt *context)
2452 {
2453 StringInfo buf = context->buf;
2454 char *ptypename = deparse_type_name(paramtype, paramtypmod);
2455
2456 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
2457 }
2458
2459 /*
2460 * Deparse ORDER BY clause according to the given pathkeys for given base
2461 * relation. From given pathkeys expressions belonging entirely to the given
2462 * base relation are obtained and deparsed.
2463 */
2464 static void
appendOrderByClause(List * pathkeys,deparse_expr_cxt * context)2465 appendOrderByClause(List *pathkeys, deparse_expr_cxt *context)
2466 {
2467 ListCell *lcell;
2468 int nestlevel;
2469 char *delim = " ";
2470 RelOptInfo *baserel = context->foreignrel;
2471 StringInfo buf = context->buf;
2472
2473 /* Make sure any constants in the exprs are printed portably */
2474 nestlevel = set_transmission_modes();
2475
2476 appendStringInfo(buf, " ORDER BY");
2477 foreach(lcell, pathkeys)
2478 {
2479 PathKey *pathkey = lfirst(lcell);
2480 Expr *em_expr;
2481
2482 em_expr = find_em_expr_for_rel(pathkey->pk_eclass, baserel);
2483 Assert(em_expr != NULL);
2484
2485 appendStringInfoString(buf, delim);
2486 deparseExpr(em_expr, context);
2487 if (pathkey->pk_strategy == BTLessStrategyNumber)
2488 appendStringInfoString(buf, " ASC");
2489 else
2490 appendStringInfoString(buf, " DESC");
2491
2492 if (pathkey->pk_nulls_first)
2493 appendStringInfoString(buf, " NULLS FIRST");
2494 else
2495 appendStringInfoString(buf, " NULLS LAST");
2496
2497 delim = ", ";
2498 }
2499 reset_transmission_modes(nestlevel);
2500 }
2501