PostgreSQL Source Code git master
Loading...
Searching...
No Matches
deparse.c
Go to the documentation of this file.
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-2026, PostgreSQL Global Development Group
28 *
29 * IDENTIFICATION
30 * contrib/postgres_fdw/deparse.c
31 *
32 *-------------------------------------------------------------------------
33 */
34#include "postgres.h"
35
36#include "access/htup_details.h"
37#include "access/sysattr.h"
38#include "access/table.h"
40#include "catalog/pg_authid.h"
42#include "catalog/pg_database.h"
44#include "catalog/pg_operator.h"
45#include "catalog/pg_opfamily.h"
46#include "catalog/pg_proc.h"
48#include "catalog/pg_ts_dict.h"
49#include "catalog/pg_type.h"
50#include "commands/defrem.h"
51#include "nodes/nodeFuncs.h"
52#include "nodes/plannodes.h"
53#include "optimizer/optimizer.h"
54#include "optimizer/prep.h"
55#include "optimizer/tlist.h"
56#include "parser/parsetree.h"
57#include "postgres_fdw.h"
58#include "utils/builtins.h"
59#include "utils/lsyscache.h"
60#include "utils/rel.h"
61#include "utils/syscache.h"
62#include "utils/typcache.h"
63
64/*
65 * Global context for foreign_expr_walker's search of an expression tree.
66 */
67typedef struct foreign_glob_cxt
68{
69 PlannerInfo *root; /* global planner state */
70 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
71 Relids relids; /* relids of base relations in the underlying
72 * scan */
74
75/*
76 * Local (per-tree-level) context for foreign_expr_walker's search.
77 * This is concerned with identifying collations used in the expression.
78 */
79typedef enum
80{
81 FDW_COLLATE_NONE, /* expression is of a noncollatable type, or
82 * it has default collation that is not
83 * traceable to a foreign Var */
84 FDW_COLLATE_SAFE, /* collation derives from a foreign Var */
85 FDW_COLLATE_UNSAFE, /* collation is non-default and derives from
86 * something other than a foreign Var */
88
89typedef struct foreign_loc_cxt
90{
91 Oid collation; /* OID of current collation, if any */
92 FDWCollateState state; /* state of current collation choice */
94
95/*
96 * Context for deparseExpr
97 */
98typedef struct deparse_expr_cxt
99{
100 PlannerInfo *root; /* global planner state */
101 RelOptInfo *foreignrel; /* the foreign relation we are planning for */
102 RelOptInfo *scanrel; /* the underlying scan relation. Same as
103 * foreignrel, when that represents a join or
104 * a base relation. */
105 StringInfo buf; /* output buffer to append to */
106 List **params_list; /* exprs that will become remote Params */
108
109#define REL_ALIAS_PREFIX "r"
110/* Handy macro to add relation name qualification */
111#define ADD_REL_QUALIFIER(buf, varno) \
112 appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
113#define SUBQUERY_REL_ALIAS_PREFIX "s"
114#define SUBQUERY_COL_ALIAS_PREFIX "c"
115
116/*
117 * Functions to determine whether an expression can be evaluated safely on
118 * remote server.
119 */
120static bool foreign_expr_walker(Node *node,
124static char *deparse_type_name(Oid type_oid, int32 typemod);
125
126/*
127 * Functions to construct string representation of a node tree.
128 */
131 Index rtindex,
132 Relation rel,
133 bool is_returning,
134 Bitmapset *attrs_used,
135 bool qualify_col,
136 List **retrieved_attrs);
137static void deparseExplicitTargetList(List *tlist,
138 bool is_returning,
139 List **retrieved_attrs,
140 deparse_expr_cxt *context);
141static void deparseSubqueryTargetList(deparse_expr_cxt *context);
143 Index rtindex, Relation rel,
144 bool trig_after_row,
146 List *returningList,
147 List **retrieved_attrs);
148static void deparseColumnRef(StringInfo buf, int varno, int varattno,
150static void deparseRelation(StringInfo buf, Relation rel);
151static void deparseExpr(Expr *node, deparse_expr_cxt *context);
152static void deparseVar(Var *node, deparse_expr_cxt *context);
153static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype);
154static void deparseParam(Param *node, deparse_expr_cxt *context);
155static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context);
156static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
157static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
158static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context);
160static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context);
162 deparse_expr_cxt *context);
163static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
164static void deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context);
165static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context);
166static void deparseNullTest(NullTest *node, deparse_expr_cxt *context);
167static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context);
168static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context);
169static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
170 deparse_expr_cxt *context);
171static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
172 deparse_expr_cxt *context);
173static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
174 deparse_expr_cxt *context);
175static void deparseLockingClause(deparse_expr_cxt *context);
176static void appendOrderByClause(List *pathkeys, bool has_final_sort,
177 deparse_expr_cxt *context);
178static void appendLimitClause(deparse_expr_cxt *context);
179static void appendConditions(List *exprs, deparse_expr_cxt *context);
181 RelOptInfo *foreignrel, bool use_alias,
184 List **params_list);
185static void appendWhereClause(List *exprs, List *additional_conds,
186 deparse_expr_cxt *context);
187static void deparseFromExpr(List *quals, deparse_expr_cxt *context);
189 RelOptInfo *foreignrel, bool make_subquery,
191 List **additional_conds, List **params_list);
192static void deparseAggref(Aggref *node, deparse_expr_cxt *context);
193static void appendGroupByClause(List *tlist, deparse_expr_cxt *context);
194static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first,
195 deparse_expr_cxt *context);
196static void appendAggOrderBy(List *orderList, List *targetList,
197 deparse_expr_cxt *context);
198static void appendFunctionName(Oid funcid, deparse_expr_cxt *context);
200 deparse_expr_cxt *context);
201
202/*
203 * Helper functions
204 */
205static bool is_subquery_var(Var *node, RelOptInfo *foreignrel,
206 int *relno, int *colno);
207static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
208 int *relno, int *colno);
209
210
211/*
212 * Examine each qual clause in input_conds, and classify them into two groups,
213 * which are returned as two lists:
214 * - remote_conds contains expressions that can be evaluated remotely
215 * - local_conds contains expressions that can't be evaluated remotely
216 */
217void
221 List **remote_conds,
222 List **local_conds)
223{
224 ListCell *lc;
225
226 *remote_conds = NIL;
227 *local_conds = NIL;
228
229 foreach(lc, input_conds)
230 {
232
233 if (is_foreign_expr(root, baserel, ri->clause))
234 *remote_conds = lappend(*remote_conds, ri);
235 else
236 *local_conds = lappend(*local_conds, ri);
237 }
238}
239
240/*
241 * Returns true if given expr is safe to evaluate on the foreign server.
242 */
243bool
246 Expr *expr)
247{
251
252 /*
253 * Check that the expression consists of nodes that are safe to execute
254 * remotely.
255 */
256 glob_cxt.root = root;
257 glob_cxt.foreignrel = baserel;
258
259 /*
260 * For an upper relation, use relids from its underneath scan relation,
261 * because the upperrel's own relids currently aren't set to anything
262 * meaningful by the core code. For other relation, use their own relids.
263 */
265 glob_cxt.relids = fpinfo->outerrel->relids;
266 else
267 glob_cxt.relids = baserel->relids;
268 loc_cxt.collation = InvalidOid;
270 if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt, NULL))
271 return false;
272
273 /*
274 * If the expression has a valid collation that does not arise from a
275 * foreign var, the expression can not be sent over.
276 */
277 if (loc_cxt.state == FDW_COLLATE_UNSAFE)
278 return false;
279
280 /*
281 * An expression which includes any mutable functions can't be sent over
282 * because its result is not stable. For example, sending now() remote
283 * side could cause confusion from clock offsets. Future versions might
284 * be able to make this choice with more granularity. (We check this last
285 * because it requires a lot of expensive catalog lookups.)
286 */
287 if (contain_mutable_functions((Node *) expr))
288 return false;
289
290 /* OK to evaluate on the remote server */
291 return true;
292}
293
294/*
295 * Check if expression is safe to execute remotely, and return true if so.
296 *
297 * In addition, *outer_cxt is updated with collation information.
298 *
299 * case_arg_cxt is NULL if this subexpression is not inside a CASE-with-arg.
300 * Otherwise, it points to the collation info derived from the arg expression,
301 * which must be consulted by any CaseTestExpr.
302 *
303 * We must check that the expression contains only node types we can deparse,
304 * that all types/functions/operators are safe to send (they are "shippable"),
305 * and that all collations used in the expression derive from Vars of the
306 * foreign table. Because of the latter, the logic is pretty close to
307 * assign_collations_walker() in parse_collate.c, though we can assume here
308 * that the given expression is valid. Note function mutability is not
309 * currently considered here.
310 */
311static bool
316{
317 bool check_type = true;
320 Oid collation;
322
323 /* Need do nothing for empty subexpressions */
324 if (node == NULL)
325 return true;
326
327 /* May need server info from baserel's fdw_private struct */
328 fpinfo = (PgFdwRelationInfo *) (glob_cxt->foreignrel->fdw_private);
329
330 /* Set up inner_cxt for possible recursion to child nodes */
331 inner_cxt.collation = InvalidOid;
333
334 switch (nodeTag(node))
335 {
336 case T_Var:
337 {
338 Var *var = (Var *) node;
339
340 /*
341 * If the Var is from the foreign table, we consider its
342 * collation (if any) safe to use. If it is from another
343 * table, we treat its collation the same way as we would a
344 * Param's collation, ie it's not safe for it to have a
345 * non-default collation.
346 */
347 if (bms_is_member(var->varno, glob_cxt->relids) &&
348 var->varlevelsup == 0)
349 {
350 /* Var belongs to foreign table */
351
352 /*
353 * System columns other than ctid should not be sent to
354 * the remote, since we don't make any effort to ensure
355 * that local and remote values match (tableoid, in
356 * particular, almost certainly doesn't match).
357 */
358 if (var->varattno < 0 &&
360 return false;
361
362 /* Else check the collation */
363 collation = var->varcollid;
365 }
366 else
367 {
368 /* Var belongs to some other table */
369 collation = var->varcollid;
370 if (collation == InvalidOid ||
371 collation == DEFAULT_COLLATION_OID)
372 {
373 /*
374 * It's noncollatable, or it's safe to combine with a
375 * collatable foreign Var, so set state to NONE.
376 */
378 }
379 else
380 {
381 /*
382 * Do not fail right away, since the Var might appear
383 * in a collation-insensitive context.
384 */
386 }
387 }
388 }
389 break;
390 case T_Const:
391 {
392 Const *c = (Const *) node;
393
394 /*
395 * Constants of regproc and related types can't be shipped
396 * unless the referenced object is shippable. But NULL's ok.
397 * (See also the related code in dependency.c.)
398 */
399 if (!c->constisnull)
400 {
401 switch (c->consttype)
402 {
403 case REGPROCOID:
404 case REGPROCEDUREOID:
405 if (!is_shippable(DatumGetObjectId(c->constvalue),
407 return false;
408 break;
409 case REGOPEROID:
410 case REGOPERATOROID:
411 if (!is_shippable(DatumGetObjectId(c->constvalue),
413 return false;
414 break;
415 case REGCLASSOID:
416 if (!is_shippable(DatumGetObjectId(c->constvalue),
418 return false;
419 break;
420 case REGTYPEOID:
421 if (!is_shippable(DatumGetObjectId(c->constvalue),
423 return false;
424 break;
425 case REGCOLLATIONOID:
426 if (!is_shippable(DatumGetObjectId(c->constvalue),
428 return false;
429 break;
430 case REGCONFIGOID:
431
432 /*
433 * For text search objects only, we weaken the
434 * normal shippability criterion to allow all OIDs
435 * below FirstNormalObjectId. Without this, none
436 * of the initdb-installed TS configurations would
437 * be shippable, which would be quite annoying.
438 */
439 if (DatumGetObjectId(c->constvalue) >= FirstNormalObjectId &&
440 !is_shippable(DatumGetObjectId(c->constvalue),
442 return false;
443 break;
444 case REGDICTIONARYOID:
445 if (DatumGetObjectId(c->constvalue) >= FirstNormalObjectId &&
446 !is_shippable(DatumGetObjectId(c->constvalue),
448 return false;
449 break;
450 case REGNAMESPACEOID:
451 if (!is_shippable(DatumGetObjectId(c->constvalue),
453 return false;
454 break;
455 case REGROLEOID:
456 if (!is_shippable(DatumGetObjectId(c->constvalue),
458 return false;
459 break;
460 case REGDATABASEOID:
461 if (!is_shippable(DatumGetObjectId(c->constvalue),
463 return false;
464 break;
465 }
466 }
467
468 /*
469 * If the constant has nondefault collation, either it's of a
470 * non-builtin type, or it reflects folding of a CollateExpr.
471 * It's unsafe to send to the remote unless it's used in a
472 * non-collation-sensitive context.
473 */
474 collation = c->constcollid;
475 if (collation == InvalidOid ||
476 collation == DEFAULT_COLLATION_OID)
478 else
480 }
481 break;
482 case T_Param:
483 {
484 Param *p = (Param *) node;
485
486 /*
487 * If it's a MULTIEXPR Param, punt. We can't tell from here
488 * whether the referenced sublink/subplan contains any remote
489 * Vars; if it does, handling that is too complicated to
490 * consider supporting at present. Fortunately, MULTIEXPR
491 * Params are not reduced to plain PARAM_EXEC until the end of
492 * planning, so we can easily detect this case. (Normal
493 * PARAM_EXEC Params are safe to ship because their values
494 * come from somewhere else in the plan tree; but a MULTIEXPR
495 * references a sub-select elsewhere in the same targetlist,
496 * so we'd be on the hook to evaluate it somehow if we wanted
497 * to handle such cases as direct foreign updates.)
498 */
499 if (p->paramkind == PARAM_MULTIEXPR)
500 return false;
501
502 /*
503 * Collation rule is same as for Consts and non-foreign Vars.
504 */
505 collation = p->paramcollid;
506 if (collation == InvalidOid ||
507 collation == DEFAULT_COLLATION_OID)
509 else
511 }
512 break;
514 {
516
517 /* Assignment should not be in restrictions. */
518 if (sr->refassgnexpr != NULL)
519 return false;
520
521 /*
522 * Recurse into the remaining subexpressions. The container
523 * subscripts will not affect collation of the SubscriptingRef
524 * result, so do those first and reset inner_cxt afterwards.
525 */
526 if (!foreign_expr_walker((Node *) sr->refupperindexpr,
528 return false;
529 inner_cxt.collation = InvalidOid;
531 if (!foreign_expr_walker((Node *) sr->reflowerindexpr,
533 return false;
534 inner_cxt.collation = InvalidOid;
536 if (!foreign_expr_walker((Node *) sr->refexpr,
538 return false;
539
540 /*
541 * Container subscripting typically yields same collation as
542 * refexpr's, but in case it doesn't, use same logic as for
543 * function nodes.
544 */
545 collation = sr->refcollid;
546 if (collation == InvalidOid)
548 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
549 collation == inner_cxt.collation)
551 else if (collation == DEFAULT_COLLATION_OID)
553 else
555 }
556 break;
557 case T_FuncExpr:
558 {
559 FuncExpr *fe = (FuncExpr *) node;
560
561 /*
562 * If function used by the expression is not shippable, it
563 * can't be sent to remote because it might have incompatible
564 * semantics on remote side.
565 */
567 return false;
568
569 /*
570 * Recurse to input subexpressions.
571 */
572 if (!foreign_expr_walker((Node *) fe->args,
574 return false;
575
576 /*
577 * If function's input collation is not derived from a foreign
578 * Var, it can't be sent to remote.
579 */
580 if (fe->inputcollid == InvalidOid)
581 /* OK, inputs are all noncollatable */ ;
582 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
583 fe->inputcollid != inner_cxt.collation)
584 return false;
585
586 /*
587 * Detect whether node is introducing a collation not derived
588 * from a foreign Var. (If so, we just mark it unsafe for now
589 * rather than immediately returning false, since the parent
590 * node might not care.)
591 */
592 collation = fe->funccollid;
593 if (collation == InvalidOid)
595 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
596 collation == inner_cxt.collation)
598 else if (collation == DEFAULT_COLLATION_OID)
600 else
602 }
603 break;
604 case T_OpExpr:
605 case T_DistinctExpr: /* struct-equivalent to OpExpr */
606 {
607 OpExpr *oe = (OpExpr *) node;
608
609 /*
610 * Similarly, only shippable operators can be sent to remote.
611 * (If the operator is shippable, we assume its underlying
612 * function is too.)
613 */
615 return false;
616
617 /*
618 * Recurse to input subexpressions.
619 */
620 if (!foreign_expr_walker((Node *) oe->args,
622 return false;
623
624 /*
625 * If operator's input collation is not derived from a foreign
626 * Var, it can't be sent to remote.
627 */
628 if (oe->inputcollid == InvalidOid)
629 /* OK, inputs are all noncollatable */ ;
630 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
631 oe->inputcollid != inner_cxt.collation)
632 return false;
633
634 /* Result-collation handling is same as for functions */
635 collation = oe->opcollid;
636 if (collation == InvalidOid)
638 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
639 collation == inner_cxt.collation)
641 else if (collation == DEFAULT_COLLATION_OID)
643 else
645 }
646 break;
648 {
650
651 /*
652 * Again, only shippable operators can be sent to remote.
653 */
655 return false;
656
657 /*
658 * Recurse to input subexpressions.
659 */
660 if (!foreign_expr_walker((Node *) oe->args,
662 return false;
663
664 /*
665 * If operator's input collation is not derived from a foreign
666 * Var, it can't be sent to remote.
667 */
668 if (oe->inputcollid == InvalidOid)
669 /* OK, inputs are all noncollatable */ ;
670 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
671 oe->inputcollid != inner_cxt.collation)
672 return false;
673
674 /* Output is always boolean and so noncollatable. */
675 collation = InvalidOid;
677 }
678 break;
679 case T_RelabelType:
680 {
681 RelabelType *r = (RelabelType *) node;
682
683 /*
684 * Recurse to input subexpression.
685 */
686 if (!foreign_expr_walker((Node *) r->arg,
688 return false;
689
690 /*
691 * RelabelType must not introduce a collation not derived from
692 * an input foreign Var (same logic as for a real function).
693 */
694 collation = r->resultcollid;
695 if (collation == InvalidOid)
697 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
698 collation == inner_cxt.collation)
700 else if (collation == DEFAULT_COLLATION_OID)
702 else
704 }
705 break;
707 {
709
710 /*
711 * Push down only when the per-element coercion is a plain
712 * relabeling, that is, elemexpr is a RelabelType or a bare
713 * CaseTestExpr. Any other element coercion -- a cast
714 * function, an I/O conversion (CoerceViaIO), or a domain
715 * coercion -- is kept local. We ship only a bare
716 * "arg::resulttype" cast (nothing at all for an
717 * implicit-format coercion), so a non-relabeling conversion
718 * would be re-resolved against the remote server's catalogs
719 * and session state and could silently change the result.
720 * This matches the handling of the scalar coercions for the
721 * I/O and domain cases (never shipped); an element cast
722 * function is kept local too, which is more conservative than
723 * the scalar case (a scalar cast function is shipped when it
724 * is shippable).
725 */
726 if (!IsA(e->elemexpr, RelabelType) &&
727 !IsA(e->elemexpr, CaseTestExpr))
728 return false;
729
730 /*
731 * Recurse to input subexpression.
732 */
733 if (!foreign_expr_walker((Node *) e->arg,
735 return false;
736
737 /*
738 * T_ArrayCoerceExpr must not introduce a collation not
739 * derived from an input foreign Var (same logic as for a
740 * function).
741 */
742 collation = e->resultcollid;
743 if (collation == InvalidOid)
745 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
746 collation == inner_cxt.collation)
748 else if (collation == DEFAULT_COLLATION_OID)
750 else
752 }
753 break;
754 case T_BoolExpr:
755 {
756 BoolExpr *b = (BoolExpr *) node;
757
758 /*
759 * Recurse to input subexpressions.
760 */
761 if (!foreign_expr_walker((Node *) b->args,
763 return false;
764
765 /* Output is always boolean and so noncollatable. */
766 collation = InvalidOid;
768 }
769 break;
770 case T_NullTest:
771 {
772 NullTest *nt = (NullTest *) node;
773
774 /*
775 * Recurse to input subexpressions.
776 */
777 if (!foreign_expr_walker((Node *) nt->arg,
779 return false;
780
781 /* Output is always boolean and so noncollatable. */
782 collation = InvalidOid;
784 }
785 break;
786 case T_CaseExpr:
787 {
788 CaseExpr *ce = (CaseExpr *) node;
790 foreign_loc_cxt tmp_cxt;
791 ListCell *lc;
792
793 /*
794 * Recurse to CASE's arg expression, if any. Its collation
795 * has to be saved aside for use while examining CaseTestExprs
796 * within the WHEN expressions.
797 */
798 arg_cxt.collation = InvalidOid;
800 if (ce->arg)
801 {
802 if (!foreign_expr_walker((Node *) ce->arg,
804 return false;
805 }
806
807 /* Examine the CaseWhen subexpressions. */
808 foreach(lc, ce->args)
809 {
811
812 if (ce->arg)
813 {
814 /*
815 * In a CASE-with-arg, the parser should have produced
816 * WHEN clauses of the form "CaseTestExpr = RHS",
817 * possibly with an implicit coercion inserted above
818 * the CaseTestExpr. However in an expression that's
819 * been through the optimizer, the WHEN clause could
820 * be almost anything (since the equality operator
821 * could have been expanded into an inline function).
822 * In such cases forbid pushdown, because
823 * deparseCaseExpr can't handle it.
824 */
825 Node *whenExpr = (Node *) cw->expr;
826 List *opArgs;
827
828 if (!IsA(whenExpr, OpExpr))
829 return false;
830
831 opArgs = ((OpExpr *) whenExpr)->args;
832 if (list_length(opArgs) != 2 ||
835 return false;
836 }
837
838 /*
839 * Recurse to WHEN expression, passing down the arg info.
840 * Its collation doesn't affect the result (really, it
841 * should be boolean and thus not have a collation).
842 */
843 tmp_cxt.collation = InvalidOid;
844 tmp_cxt.state = FDW_COLLATE_NONE;
845 if (!foreign_expr_walker((Node *) cw->expr,
846 glob_cxt, &tmp_cxt, &arg_cxt))
847 return false;
848
849 /* Recurse to THEN expression. */
850 if (!foreign_expr_walker((Node *) cw->result,
852 return false;
853 }
854
855 /* Recurse to ELSE expression. */
856 if (!foreign_expr_walker((Node *) ce->defresult,
858 return false;
859
860 /*
861 * Detect whether node is introducing a collation not derived
862 * from a foreign Var. (If so, we just mark it unsafe for now
863 * rather than immediately returning false, since the parent
864 * node might not care.) This is the same as for function
865 * nodes, except that the input collation is derived from only
866 * the THEN and ELSE subexpressions.
867 */
868 collation = ce->casecollid;
869 if (collation == InvalidOid)
871 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
872 collation == inner_cxt.collation)
874 else if (collation == DEFAULT_COLLATION_OID)
876 else
878 }
879 break;
880 case T_CaseTestExpr:
881 {
882 CaseTestExpr *c = (CaseTestExpr *) node;
883
884 /* Punt if we seem not to be inside a CASE arg WHEN. */
885 if (!case_arg_cxt)
886 return false;
887
888 /*
889 * Otherwise, any nondefault collation attached to the
890 * CaseTestExpr node must be derived from foreign Var(s) in
891 * the CASE arg.
892 */
893 collation = c->collation;
894 if (collation == InvalidOid)
896 else if (case_arg_cxt->state == FDW_COLLATE_SAFE &&
897 collation == case_arg_cxt->collation)
899 else if (collation == DEFAULT_COLLATION_OID)
901 else
903 }
904 break;
905 case T_ArrayExpr:
906 {
907 ArrayExpr *a = (ArrayExpr *) node;
908
909 /*
910 * Recurse to input subexpressions.
911 */
912 if (!foreign_expr_walker((Node *) a->elements,
914 return false;
915
916 /*
917 * ArrayExpr must not introduce a collation not derived from
918 * an input foreign Var (same logic as for a function).
919 */
920 collation = a->array_collid;
921 if (collation == InvalidOid)
923 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
924 collation == inner_cxt.collation)
926 else if (collation == DEFAULT_COLLATION_OID)
928 else
930 }
931 break;
932 case T_List:
933 {
934 List *l = (List *) node;
935 ListCell *lc;
936
937 /*
938 * Recurse to component subexpressions.
939 */
940 foreach(lc, l)
941 {
944 return false;
945 }
946
947 /*
948 * When processing a list, collation state just bubbles up
949 * from the list elements.
950 */
951 collation = inner_cxt.collation;
952 state = inner_cxt.state;
953
954 /* Don't apply exprType() to the list. */
955 check_type = false;
956 }
957 break;
958 case T_Aggref:
959 {
960 Aggref *agg = (Aggref *) node;
961 ListCell *lc;
962
963 /* Not safe to pushdown when not in grouping context */
964 if (!IS_UPPER_REL(glob_cxt->foreignrel))
965 return false;
966
967 /* Only non-split aggregates are pushable. */
968 if (agg->aggsplit != AGGSPLIT_SIMPLE)
969 return false;
970
971 /* As usual, it must be shippable. */
972 if (!is_shippable(agg->aggfnoid, ProcedureRelationId, fpinfo))
973 return false;
974
975 /*
976 * Recurse to input args. aggdirectargs, aggorder and
977 * aggdistinct are all present in args, so no need to check
978 * their shippability explicitly.
979 */
980 foreach(lc, agg->args)
981 {
982 Node *n = (Node *) lfirst(lc);
983
984 /* If TargetEntry, extract the expression from it */
985 if (IsA(n, TargetEntry))
986 {
987 TargetEntry *tle = (TargetEntry *) n;
988
989 n = (Node *) tle->expr;
990 }
991
992 if (!foreign_expr_walker(n,
994 return false;
995 }
996
997 /*
998 * For aggorder elements, check whether the sort operator, if
999 * specified, is shippable or not.
1000 */
1001 if (agg->aggorder)
1002 {
1003 foreach(lc, agg->aggorder)
1004 {
1007 TypeCacheEntry *typentry;
1009
1010 tle = get_sortgroupref_tle(srt->tleSortGroupRef,
1011 agg->args);
1012 sortcoltype = exprType((Node *) tle->expr);
1013 typentry = lookup_type_cache(sortcoltype,
1015 /* Check shippability of non-default sort operator. */
1016 if (srt->sortop != typentry->lt_opr &&
1017 srt->sortop != typentry->gt_opr &&
1019 fpinfo))
1020 return false;
1021 }
1022 }
1023
1024 /* Check aggregate filter */
1025 if (!foreign_expr_walker((Node *) agg->aggfilter,
1027 return false;
1028
1029 /*
1030 * If aggregate's input collation is not derived from a
1031 * foreign Var, it can't be sent to remote.
1032 */
1033 if (agg->inputcollid == InvalidOid)
1034 /* OK, inputs are all noncollatable */ ;
1035 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
1036 agg->inputcollid != inner_cxt.collation)
1037 return false;
1038
1039 /*
1040 * Detect whether node is introducing a collation not derived
1041 * from a foreign Var. (If so, we just mark it unsafe for now
1042 * rather than immediately returning false, since the parent
1043 * node might not care.)
1044 */
1045 collation = agg->aggcollid;
1046 if (collation == InvalidOid)
1048 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
1049 collation == inner_cxt.collation)
1051 else if (collation == DEFAULT_COLLATION_OID)
1053 else
1055 }
1056 break;
1057 default:
1058
1059 /*
1060 * If it's anything else, assume it's unsafe. This list can be
1061 * expanded later, but don't forget to add deparse support below.
1062 */
1063 return false;
1064 }
1065
1066 /*
1067 * If result type of given expression is not shippable, it can't be sent
1068 * to remote because it might have incompatible semantics on remote side.
1069 */
1071 return false;
1072
1073 /*
1074 * Now, merge my collation information into my parent's state.
1075 */
1076 if (state > outer_cxt->state)
1077 {
1078 /* Override previous parent state */
1079 outer_cxt->collation = collation;
1080 outer_cxt->state = state;
1081 }
1082 else if (state == outer_cxt->state)
1083 {
1084 /* Merge, or detect error if there's a collation conflict */
1085 switch (state)
1086 {
1087 case FDW_COLLATE_NONE:
1088 /* Nothing + nothing is still nothing */
1089 break;
1090 case FDW_COLLATE_SAFE:
1091 if (collation != outer_cxt->collation)
1092 {
1093 /*
1094 * Non-default collation always beats default.
1095 */
1096 if (outer_cxt->collation == DEFAULT_COLLATION_OID)
1097 {
1098 /* Override previous parent state */
1099 outer_cxt->collation = collation;
1100 }
1101 else if (collation != DEFAULT_COLLATION_OID)
1102 {
1103 /*
1104 * Conflict; show state as indeterminate. We don't
1105 * want to "return false" right away, since parent
1106 * node might not care about collation.
1107 */
1109 }
1110 }
1111 break;
1112 case FDW_COLLATE_UNSAFE:
1113 /* We're still conflicted ... */
1114 break;
1115 }
1116 }
1117
1118 /* It looks OK */
1119 return true;
1120}
1121
1122/*
1123 * Returns true if given expr is something we'd have to send the value of
1124 * to the foreign server.
1125 *
1126 * This should return true when the expression is a shippable node that
1127 * deparseExpr would add to context->params_list. Note that we don't care
1128 * if the expression *contains* such a node, only whether one appears at top
1129 * level. We need this to detect cases where setrefs.c would recognize a
1130 * false match between an fdw_exprs item (which came from the params_list)
1131 * and an entry in fdw_scan_tlist (which we're considering putting the given
1132 * expression into).
1133 */
1134bool
1137 Expr *expr)
1138{
1139 if (expr == NULL)
1140 return false;
1141
1142 switch (nodeTag(expr))
1143 {
1144 case T_Var:
1145 {
1146 /* It would have to be sent unless it's a foreign Var */
1147 Var *var = (Var *) expr;
1148 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
1149 Relids relids;
1150
1151 if (IS_UPPER_REL(baserel))
1152 relids = fpinfo->outerrel->relids;
1153 else
1154 relids = baserel->relids;
1155
1156 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
1157 return false; /* foreign Var, so not a param */
1158 else
1159 return true; /* it'd have to be a param */
1160 break;
1161 }
1162 case T_Param:
1163 /* Params always have to be sent to the foreign server */
1164 return true;
1165 default:
1166 break;
1167 }
1168 return false;
1169}
1170
1171/*
1172 * Returns true if it's safe to push down the sort expression described by
1173 * 'pathkey' to the foreign server.
1174 */
1175bool
1179{
1180 EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
1182
1183 /*
1184 * is_foreign_expr would detect volatile expressions as well, but checking
1185 * ec_has_volatile here saves some cycles.
1186 */
1187 if (pathkey_ec->ec_has_volatile)
1188 return false;
1189
1190 /* can't push down the sort if the pathkey's opfamily is not shippable */
1192 return false;
1193
1194 /* can push if a suitable EC member exists */
1196}
1197
1198/*
1199 * Convert type OID + typmod info into a type name we can ship to the remote
1200 * server. Someplace else had better have verified that this type name is
1201 * expected to be known on the remote end.
1202 *
1203 * This is almost just format_type_with_typemod(), except that if left to its
1204 * own devices, that function will make schema-qualification decisions based
1205 * on the local search_path, which is wrong. We must schema-qualify all
1206 * type names that are not in pg_catalog. We assume here that built-in types
1207 * are all in pg_catalog and need not be qualified; otherwise, qualify.
1208 */
1209static char *
1211{
1213
1214 if (!is_builtin(type_oid))
1216
1217 return format_type_extended(type_oid, typemod, flags);
1218}
1219
1220/*
1221 * Build the targetlist for given relation to be deparsed as SELECT clause.
1222 *
1223 * The output targetlist contains the columns that need to be fetched from the
1224 * foreign server for the given relation. If foreignrel is an upper relation,
1225 * then the output targetlist can also contain expressions to be evaluated on
1226 * foreign server.
1227 */
1228List *
1230{
1231 List *tlist = NIL;
1232 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1233 ListCell *lc;
1234
1235 /*
1236 * For an upper relation, we have already built the target list while
1237 * checking shippability, so just return that.
1238 */
1239 if (IS_UPPER_REL(foreignrel))
1240 return fpinfo->grouped_tlist;
1241
1242 /*
1243 * We require columns specified in foreignrel->reltarget->exprs and those
1244 * required for evaluating the local conditions.
1245 */
1246 tlist = add_to_flat_tlist(tlist,
1247 pull_var_clause((Node *) foreignrel->reltarget->exprs,
1249 foreach(lc, fpinfo->local_conds)
1250 {
1252
1253 tlist = add_to_flat_tlist(tlist,
1254 pull_var_clause((Node *) rinfo->clause,
1256 }
1257
1258 return tlist;
1259}
1260
1261/*
1262 * Deparse SELECT statement for given relation into buf.
1263 *
1264 * tlist contains the list of desired columns to be fetched from foreign server.
1265 * For a base relation fpinfo->attrs_used is used to construct SELECT clause,
1266 * hence the tlist is ignored for a base relation.
1267 *
1268 * remote_conds is the list of conditions to be deparsed into the WHERE clause
1269 * (or, in the case of upper relations, into the HAVING clause).
1270 *
1271 * If params_list is not NULL, it receives a list of Params and other-relation
1272 * Vars used in the clauses; these values must be transmitted to the remote
1273 * server as parameter values.
1274 *
1275 * If params_list is NULL, we're generating the query for EXPLAIN purposes,
1276 * so Params and other-relation Vars should be replaced by dummy values.
1277 *
1278 * pathkeys is the list of pathkeys to order the result by.
1279 *
1280 * is_subquery is the flag to indicate whether to deparse the specified
1281 * relation as a subquery.
1282 *
1283 * List of columns selected is returned in retrieved_attrs.
1284 */
1285void
1287 List *tlist, List *remote_conds, List *pathkeys,
1288 bool has_final_sort, bool has_limit, bool is_subquery,
1289 List **retrieved_attrs, List **params_list)
1290{
1291 deparse_expr_cxt context;
1292 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1293 List *quals;
1294
1295 /*
1296 * We handle relations for foreign tables, joins between those and upper
1297 * relations.
1298 */
1299 Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1300
1301 /* Fill portions of context common to upper, join and base relation */
1302 context.buf = buf;
1303 context.root = root;
1304 context.foreignrel = rel;
1305 context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1306 context.params_list = params_list;
1307
1308 /* Construct SELECT clause */
1309 deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1310
1311 /*
1312 * For upper relations, the WHERE clause is built from the remote
1313 * conditions of the underlying scan relation; otherwise, we can use the
1314 * supplied list of remote conditions directly.
1315 */
1316 if (IS_UPPER_REL(rel))
1317 {
1319
1320 ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1321 quals = ofpinfo->remote_conds;
1322 }
1323 else
1324 quals = remote_conds;
1325
1326 /* Construct FROM and WHERE clauses */
1327 deparseFromExpr(quals, &context);
1328
1329 if (IS_UPPER_REL(rel))
1330 {
1331 /* Append GROUP BY clause */
1332 appendGroupByClause(tlist, &context);
1333
1334 /* Append HAVING clause */
1335 if (remote_conds)
1336 {
1337 appendStringInfoString(buf, " HAVING ");
1338 appendConditions(remote_conds, &context);
1339 }
1340 }
1341
1342 /* Add ORDER BY clause if we found any useful pathkeys */
1343 if (pathkeys)
1344 appendOrderByClause(pathkeys, has_final_sort, &context);
1345
1346 /* Add LIMIT clause if necessary */
1347 if (has_limit)
1348 appendLimitClause(&context);
1349
1350 /* Add any necessary FOR UPDATE/SHARE. */
1351 deparseLockingClause(&context);
1352}
1353
1354/*
1355 * Construct a simple SELECT statement that retrieves desired columns
1356 * of the specified foreign table, and append it to "buf". The output
1357 * contains just "SELECT ... ".
1358 *
1359 * We also create an integer List of the columns being retrieved, which is
1360 * returned to *retrieved_attrs, unless we deparse the specified relation
1361 * as a subquery.
1362 *
1363 * tlist is the list of desired columns. is_subquery is the flag to
1364 * indicate whether to deparse the specified relation as a subquery.
1365 * Read prologue of deparseSelectStmtForRel() for details.
1366 */
1367static void
1368deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
1369 deparse_expr_cxt *context)
1370{
1371 StringInfo buf = context->buf;
1372 RelOptInfo *foreignrel = context->foreignrel;
1373 PlannerInfo *root = context->root;
1374 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1375
1376 /*
1377 * Construct SELECT list
1378 */
1379 appendStringInfoString(buf, "SELECT ");
1380
1381 if (is_subquery)
1382 {
1383 /*
1384 * For a relation that is deparsed as a subquery, emit expressions
1385 * specified in the relation's reltarget. Note that since this is for
1386 * the subquery, no need to care about *retrieved_attrs.
1387 */
1389 }
1390 else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1391 {
1392 /*
1393 * For a join or upper relation the input tlist gives the list of
1394 * columns required to be fetched from the foreign server.
1395 */
1396 deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1397 }
1398 else
1399 {
1400 /*
1401 * For a base relation fpinfo->attrs_used gives the list of columns
1402 * required to be fetched from the foreign server.
1403 */
1404 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1405
1406 /*
1407 * Core code already has some lock on each rel being planned, so we
1408 * can use NoLock here.
1409 */
1410 Relation rel = table_open(rte->relid, NoLock);
1411
1412 deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1413 fpinfo->attrs_used, false, retrieved_attrs);
1414 table_close(rel, NoLock);
1415 }
1416}
1417
1418/*
1419 * Construct a FROM clause and, if needed, a WHERE clause, and append those to
1420 * "buf".
1421 *
1422 * quals is the list of clauses to be included in the WHERE clause.
1423 * (These may or may not include RestrictInfo decoration.)
1424 */
1425static void
1427{
1428 StringInfo buf = context->buf;
1429 RelOptInfo *scanrel = context->scanrel;
1431
1432 /* For upper relations, scanrel must be either a joinrel or a baserel */
1433 Assert(!IS_UPPER_REL(context->foreignrel) ||
1434 IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1435
1436 /* Construct FROM clause */
1437 appendStringInfoString(buf, " FROM ");
1438 deparseFromExprForRel(buf, context->root, scanrel,
1439 (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1441 context->params_list);
1442 appendWhereClause(quals, additional_conds, context);
1443 if (additional_conds != NIL)
1445}
1446
1447/*
1448 * Emit a target list that retrieves the columns specified in attrs_used.
1449 * This is used for both SELECT and RETURNING targetlists; the is_returning
1450 * parameter is true only for a RETURNING targetlist.
1451 *
1452 * The tlist text is appended to buf, and we also create an integer List
1453 * of the columns being retrieved, which is returned to *retrieved_attrs.
1454 *
1455 * If qualify_col is true, add relation alias before the column name.
1456 */
1457static void
1460 Index rtindex,
1461 Relation rel,
1462 bool is_returning,
1463 Bitmapset *attrs_used,
1464 bool qualify_col,
1465 List **retrieved_attrs)
1466{
1467 TupleDesc tupdesc = RelationGetDescr(rel);
1468 bool have_wholerow;
1469 bool first;
1470 int i;
1471
1472 *retrieved_attrs = NIL;
1473
1474 /* If there's a whole-row reference, we'll need all the columns. */
1476 attrs_used);
1477
1478 first = true;
1479 for (i = 1; i <= tupdesc->natts; i++)
1480 {
1481 /* Ignore dropped attributes. */
1482 if (TupleDescCompactAttr(tupdesc, i - 1)->attisdropped)
1483 continue;
1484
1485 if (have_wholerow ||
1487 attrs_used))
1488 {
1489 if (!first)
1491 else if (is_returning)
1492 appendStringInfoString(buf, " RETURNING ");
1493 first = false;
1494
1495 deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1496
1497 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1498 }
1499 }
1500
1501 /*
1502 * Add ctid if needed. We currently don't support retrieving any other
1503 * system columns.
1504 */
1506 attrs_used))
1507 {
1508 if (!first)
1510 else if (is_returning)
1511 appendStringInfoString(buf, " RETURNING ");
1512 first = false;
1513
1514 if (qualify_col)
1515 ADD_REL_QUALIFIER(buf, rtindex);
1516 appendStringInfoString(buf, "ctid");
1517
1518 *retrieved_attrs = lappend_int(*retrieved_attrs,
1520 }
1521
1522 /* Don't generate bad syntax if no undropped columns */
1523 if (first && !is_returning)
1524 appendStringInfoString(buf, "NULL");
1525}
1526
1527/*
1528 * Deparse the appropriate locking clause (FOR UPDATE or FOR SHARE) for a
1529 * given relation (context->scanrel).
1530 */
1531static void
1533{
1534 StringInfo buf = context->buf;
1535 PlannerInfo *root = context->root;
1536 RelOptInfo *rel = context->scanrel;
1537 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1538 int relid = -1;
1539
1540 while ((relid = bms_next_member(rel->relids, relid)) >= 0)
1541 {
1542 /*
1543 * Ignore relation if it appears in a lower subquery. Locking clause
1544 * for such a relation is included in the subquery if necessary.
1545 */
1546 if (bms_is_member(relid, fpinfo->lower_subquery_rels))
1547 continue;
1548
1549 /*
1550 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1551 * initial row fetch, rather than later on as is done for local
1552 * tables. The extra roundtrips involved in trying to duplicate the
1553 * local semantics exactly don't seem worthwhile (see also comments
1554 * for RowMarkType).
1555 *
1556 * Note: because we actually run the query as a cursor, this assumes
1557 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1558 * before 8.3.
1559 */
1560 if (bms_is_member(relid, root->all_result_relids) &&
1561 (root->parse->commandType == CMD_UPDATE ||
1562 root->parse->commandType == CMD_DELETE))
1563 {
1564 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1565 appendStringInfoString(buf, " FOR UPDATE");
1566
1567 /* Add the relation alias if we are here for a join relation */
1568 if (IS_JOIN_REL(rel))
1569 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1570 }
1571 else
1572 {
1573 PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
1574
1575 if (rc)
1576 {
1577 /*
1578 * Relation is specified as a FOR UPDATE/SHARE target, so
1579 * handle that. (But we could also see LCS_NONE, meaning this
1580 * isn't a target relation after all.)
1581 *
1582 * For now, just ignore any [NO] KEY specification, since (a)
1583 * it's not clear what that means for a remote table that we
1584 * don't have complete information about, and (b) it wouldn't
1585 * work anyway on older remote servers. Likewise, we don't
1586 * worry about NOWAIT.
1587 */
1588 switch (rc->strength)
1589 {
1590 case LCS_NONE:
1591 /* No locking needed */
1592 break;
1593 case LCS_FORKEYSHARE:
1594 case LCS_FORSHARE:
1595 appendStringInfoString(buf, " FOR SHARE");
1596 break;
1597 case LCS_FORNOKEYUPDATE:
1598 case LCS_FORUPDATE:
1599 appendStringInfoString(buf, " FOR UPDATE");
1600 break;
1601 }
1602
1603 /* Add the relation alias if we are here for a join relation */
1604 if (bms_membership(rel->relids) == BMS_MULTIPLE &&
1605 rc->strength != LCS_NONE)
1606 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1607 }
1608 }
1609 }
1610}
1611
1612/*
1613 * Deparse conditions from the provided list and append them to buf.
1614 *
1615 * The conditions in the list are assumed to be ANDed. This function is used to
1616 * deparse WHERE clauses, JOIN .. ON clauses and HAVING clauses.
1617 *
1618 * Depending on the caller, the list elements might be either RestrictInfos
1619 * or bare clauses.
1620 */
1621static void
1623{
1624 int nestlevel;
1625 ListCell *lc;
1626 bool is_first = true;
1627 StringInfo buf = context->buf;
1628
1629 /* Make sure any constants in the exprs are printed portably */
1631
1632 foreach(lc, exprs)
1633 {
1634 Expr *expr = (Expr *) lfirst(lc);
1635
1636 /* Extract clause from RestrictInfo, if required */
1637 if (IsA(expr, RestrictInfo))
1638 expr = ((RestrictInfo *) expr)->clause;
1639
1640 /* Connect expressions with "AND" and parenthesize each condition. */
1641 if (!is_first)
1642 appendStringInfoString(buf, " AND ");
1643
1645 deparseExpr(expr, context);
1647
1648 is_first = false;
1649 }
1650
1652}
1653
1654/*
1655 * Append WHERE clause, containing conditions from exprs and additional_conds,
1656 * to context->buf.
1657 */
1658static void
1660{
1661 StringInfo buf = context->buf;
1662 bool need_and = false;
1663 ListCell *lc;
1664
1665 if (exprs != NIL || additional_conds != NIL)
1666 appendStringInfoString(buf, " WHERE ");
1667
1668 /*
1669 * If there are some filters, append them.
1670 */
1671 if (exprs != NIL)
1672 {
1673 appendConditions(exprs, context);
1674 need_and = true;
1675 }
1676
1677 /*
1678 * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1679 * them.
1680 */
1681 foreach(lc, additional_conds)
1682 {
1683 if (need_and)
1684 appendStringInfoString(buf, " AND ");
1685 appendStringInfoString(buf, (char *) lfirst(lc));
1686 need_and = true;
1687 }
1688}
1689
1690/* Output join name for given join type */
1691const char *
1693{
1694 switch (jointype)
1695 {
1696 case JOIN_INNER:
1697 return "INNER";
1698
1699 case JOIN_LEFT:
1700 return "LEFT";
1701
1702 case JOIN_RIGHT:
1703 return "RIGHT";
1704
1705 case JOIN_FULL:
1706 return "FULL";
1707
1708 case JOIN_SEMI:
1709 return "SEMI";
1710
1711 default:
1712 /* Shouldn't come here, but protect from buggy code. */
1713 elog(ERROR, "unsupported join type %d", jointype);
1714 }
1715
1716 /* Keep compiler happy */
1717 return NULL;
1718}
1719
1720/*
1721 * Deparse given targetlist and append it to context->buf.
1722 *
1723 * tlist is list of TargetEntry's which in turn contain Var nodes.
1724 *
1725 * retrieved_attrs is the list of continuously increasing integers starting
1726 * from 1. It has same number of entries as tlist.
1727 *
1728 * This is used for both SELECT and RETURNING targetlists; the is_returning
1729 * parameter is true only for a RETURNING targetlist.
1730 */
1731static void
1733 bool is_returning,
1734 List **retrieved_attrs,
1735 deparse_expr_cxt *context)
1736{
1737 ListCell *lc;
1738 StringInfo buf = context->buf;
1739 int i = 0;
1740
1741 *retrieved_attrs = NIL;
1742
1743 foreach(lc, tlist)
1744 {
1746
1747 if (i > 0)
1749 else if (is_returning)
1750 appendStringInfoString(buf, " RETURNING ");
1751
1752 deparseExpr((Expr *) tle->expr, context);
1753
1754 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1755 i++;
1756 }
1757
1758 if (i == 0 && !is_returning)
1759 appendStringInfoString(buf, "NULL");
1760}
1761
1762/*
1763 * Emit expressions specified in the given relation's reltarget.
1764 *
1765 * This is used for deparsing the given relation as a subquery.
1766 */
1767static void
1769{
1770 StringInfo buf = context->buf;
1771 RelOptInfo *foreignrel = context->foreignrel;
1772 bool first;
1773 ListCell *lc;
1774
1775 /* Should only be called in these cases. */
1776 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1777
1778 first = true;
1779 foreach(lc, foreignrel->reltarget->exprs)
1780 {
1781 Node *node = (Node *) lfirst(lc);
1782
1783 if (!first)
1785 first = false;
1786
1787 deparseExpr((Expr *) node, context);
1788 }
1789
1790 /* Don't generate bad syntax if no expressions */
1791 if (first)
1792 appendStringInfoString(buf, "NULL");
1793}
1794
1795/*
1796 * Construct FROM clause for given relation
1797 *
1798 * The function constructs ... JOIN ... ON ... for join relation. For a base
1799 * relation it just returns schema-qualified tablename, with the appropriate
1800 * alias if so requested.
1801 *
1802 * 'ignore_rel' is either zero or the RT index of a target relation. In the
1803 * latter case the function constructs FROM clause of UPDATE or USING clause
1804 * of DELETE; it deparses the join relation as if the relation never contained
1805 * the target relation, and creates a List of conditions to be deparsed into
1806 * the top-level WHERE clause, which is returned to *ignore_conds.
1807 *
1808 * 'additional_conds' is a pointer to a list of strings to be appended to
1809 * the WHERE clause, coming from lower-level SEMI-JOINs.
1810 */
1811static void
1814 List **additional_conds, List **params_list)
1815{
1816 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1817
1818 if (IS_JOIN_REL(foreignrel))
1819 {
1822 RelOptInfo *outerrel = fpinfo->outerrel;
1823 RelOptInfo *innerrel = fpinfo->innerrel;
1824 bool outerrel_is_target = false;
1825 bool innerrel_is_target = false;
1828
1829 if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1830 {
1831 /*
1832 * If this is an inner join, add joinclauses to *ignore_conds and
1833 * set it to empty so that those can be deparsed into the WHERE
1834 * clause. Note that since the target relation can never be
1835 * within the nullable side of an outer join, those could safely
1836 * be pulled up into the WHERE clause (see foreign_join_ok()).
1837 * Note also that since the target relation is only inner-joined
1838 * to any other relation in the query, all conditions in the join
1839 * tree mentioning the target relation could be deparsed into the
1840 * WHERE clause by doing this recursively.
1841 */
1842 if (fpinfo->jointype == JOIN_INNER)
1843 {
1845 fpinfo->joinclauses);
1846 fpinfo->joinclauses = NIL;
1847 }
1848
1849 /*
1850 * Check if either of the input relations is the target relation.
1851 */
1852 if (outerrel->relid == ignore_rel)
1853 outerrel_is_target = true;
1854 else if (innerrel->relid == ignore_rel)
1855 innerrel_is_target = true;
1856 }
1857
1858 /* Deparse outer relation if not the target relation. */
1859 if (!outerrel_is_target)
1860 {
1863 fpinfo->make_outerrel_subquery,
1865 params_list);
1866
1867 /*
1868 * If inner relation is the target relation, skip deparsing it.
1869 * Note that since the join of the target relation with any other
1870 * relation in the query is an inner join and can never be within
1871 * the nullable side of an outer join, the join could be
1872 * interchanged with higher-level joins (cf. identity 1 on outer
1873 * join reordering shown in src/backend/optimizer/README), which
1874 * means it's safe to skip the target-relation deparsing here.
1875 */
1877 {
1878 Assert(fpinfo->jointype == JOIN_INNER);
1879 Assert(fpinfo->joinclauses == NIL);
1881 /* Pass EXISTS conditions to upper level */
1882 if (additional_conds_o != NIL)
1883 {
1886 }
1887 return;
1888 }
1889 }
1890
1891 /* Deparse inner relation if not the target relation. */
1892 if (!innerrel_is_target)
1893 {
1896 fpinfo->make_innerrel_subquery,
1898 params_list);
1899
1900 /*
1901 * SEMI-JOIN is deparsed as the EXISTS subquery. It references
1902 * outer and inner relations, so it should be evaluated as the
1903 * condition in the upper-level WHERE clause. We deparse the
1904 * condition and pass it to upper level callers as an
1905 * additional_conds list. Upper level callers are responsible for
1906 * inserting conditions from the list where appropriate.
1907 */
1908 if (fpinfo->jointype == JOIN_SEMI)
1909 {
1910 deparse_expr_cxt context;
1912
1913 /* Construct deparsed condition from this SEMI-JOIN */
1915 appendStringInfo(&str, "EXISTS (SELECT NULL FROM %s",
1916 join_sql_i.data);
1917
1918 context.buf = &str;
1919 context.foreignrel = foreignrel;
1920 context.scanrel = foreignrel;
1921 context.root = root;
1922 context.params_list = params_list;
1923
1924 /*
1925 * Append SEMI-JOIN clauses and EXISTS conditions from lower
1926 * levels to the current EXISTS subquery
1927 */
1928 appendWhereClause(fpinfo->joinclauses, additional_conds_i, &context);
1929
1930 /*
1931 * EXISTS conditions, coming from lower join levels, have just
1932 * been processed.
1933 */
1934 if (additional_conds_i != NIL)
1935 {
1938 }
1939
1940 /* Close parentheses for EXISTS subquery */
1942
1944 }
1945
1946 /*
1947 * If outer relation is the target relation, skip deparsing it.
1948 * See the above note about safety.
1949 */
1951 {
1952 Assert(fpinfo->jointype == JOIN_INNER);
1953 Assert(fpinfo->joinclauses == NIL);
1955 /* Pass EXISTS conditions to the upper call */
1956 if (additional_conds_i != NIL)
1957 {
1960 }
1961 return;
1962 }
1963 }
1964
1965 /* Neither of the relations is the target relation. */
1967
1968 /*
1969 * For semijoin FROM clause is deparsed as an outer relation. An inner
1970 * relation and join clauses are converted to EXISTS condition and
1971 * passed to the upper level.
1972 */
1973 if (fpinfo->jointype == JOIN_SEMI)
1974 {
1976 }
1977 else
1978 {
1979 /*
1980 * For a join relation FROM clause, entry is deparsed as
1981 *
1982 * ((outer relation) <join type> (inner relation) ON
1983 * (joinclauses))
1984 */
1985 appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1986 get_jointype_name(fpinfo->jointype), join_sql_i.data);
1987
1988 /* Append join clause; (TRUE) if no join clause */
1989 if (fpinfo->joinclauses)
1990 {
1991 deparse_expr_cxt context;
1992
1993 context.buf = buf;
1994 context.foreignrel = foreignrel;
1995 context.scanrel = foreignrel;
1996 context.root = root;
1997 context.params_list = params_list;
1998
2000 appendConditions(fpinfo->joinclauses, &context);
2002 }
2003 else
2004 appendStringInfoString(buf, "(TRUE)");
2005
2006 /* End the FROM clause entry. */
2008 }
2009
2010 /*
2011 * Construct additional_conds to be passed to the upper caller from
2012 * current level additional_conds and additional_conds, coming from
2013 * inner and outer rels.
2014 */
2015 if (additional_conds_o != NIL)
2016 {
2020 }
2021
2022 if (additional_conds_i != NIL)
2023 {
2027 }
2028 }
2029 else
2030 {
2031 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
2032
2033 /*
2034 * Core code already has some lock on each rel being planned, so we
2035 * can use NoLock here.
2036 */
2037 Relation rel = table_open(rte->relid, NoLock);
2038
2039 deparseRelation(buf, rel);
2040
2041 /*
2042 * Add a unique alias to avoid any conflict in relation names due to
2043 * pulled up subqueries in the query being built for a pushed down
2044 * join.
2045 */
2046 if (use_alias)
2047 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
2048
2049 table_close(rel, NoLock);
2050 }
2051}
2052
2053/*
2054 * Append FROM clause entry for the given relation into buf.
2055 * Conditions from lower-level SEMI-JOINs are appended to additional_conds
2056 * and should be added to upper level WHERE clause.
2057 */
2058static void
2061 List **additional_conds, List **params_list)
2062{
2063 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
2064
2065 /* Should only be called in these cases. */
2066 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
2067
2068 Assert(fpinfo->local_conds == NIL);
2069
2070 /* If make_subquery is true, deparse the relation as a subquery. */
2071 if (make_subquery)
2072 {
2073 List *retrieved_attrs;
2074 int ncols;
2075
2076 /*
2077 * The given relation shouldn't contain the target relation, because
2078 * this should only happen for input relations for a full join, and
2079 * such relations can never contain an UPDATE/DELETE target.
2080 */
2081 Assert(ignore_rel == 0 ||
2082 !bms_is_member(ignore_rel, foreignrel->relids));
2083
2084 /* Deparse the subquery representing the relation. */
2086 deparseSelectStmtForRel(buf, root, foreignrel, NIL,
2087 fpinfo->remote_conds, NIL,
2088 false, false, true,
2089 &retrieved_attrs, params_list);
2091
2092 /* Append the relation alias. */
2094 fpinfo->relation_index);
2095
2096 /*
2097 * Append the column aliases if needed. Note that the subquery emits
2098 * expressions specified in the relation's reltarget (see
2099 * deparseSubqueryTargetList).
2100 */
2101 ncols = list_length(foreignrel->reltarget->exprs);
2102 if (ncols > 0)
2103 {
2104 int i;
2105
2107 for (i = 1; i <= ncols; i++)
2108 {
2109 if (i > 1)
2111
2113 }
2115 }
2116 }
2117 else
2118 deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
2120 params_list);
2121}
2122
2123/*
2124 * deparse remote INSERT statement
2125 *
2126 * The statement text is appended to buf, and we also create an integer List
2127 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
2128 * which is returned to *retrieved_attrs.
2129 *
2130 * This also stores end position of the VALUES clause, so that we can rebuild
2131 * an INSERT for a batch of rows later.
2132 */
2133void
2135 Index rtindex, Relation rel,
2136 List *targetAttrs, bool doNothing,
2137 List *withCheckOptionList, List *returningList,
2138 List **retrieved_attrs, int *values_end_len)
2139{
2140 TupleDesc tupdesc = RelationGetDescr(rel);
2142 bool first;
2143 ListCell *lc;
2144
2145 appendStringInfoString(buf, "INSERT INTO ");
2146 deparseRelation(buf, rel);
2147
2148 if (targetAttrs)
2149 {
2151
2152 first = true;
2153 foreach(lc, targetAttrs)
2154 {
2155 int attnum = lfirst_int(lc);
2156
2157 if (!first)
2159 first = false;
2160
2161 deparseColumnRef(buf, rtindex, attnum, rte, false);
2162 }
2163
2164 appendStringInfoString(buf, ") VALUES (");
2165
2166 pindex = 1;
2167 first = true;
2168 foreach(lc, targetAttrs)
2169 {
2170 int attnum = lfirst_int(lc);
2171 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2172
2173 if (!first)
2175 first = false;
2176
2177 if (attr->attgenerated)
2178 appendStringInfoString(buf, "DEFAULT");
2179 else
2180 {
2181 appendStringInfo(buf, "$%d", pindex);
2182 pindex++;
2183 }
2184 }
2185
2187 }
2188 else
2189 appendStringInfoString(buf, " DEFAULT VALUES");
2190 *values_end_len = buf->len;
2191
2192 if (doNothing)
2193 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2194
2195 deparseReturningList(buf, rte, rtindex, rel,
2197 withCheckOptionList, returningList, retrieved_attrs);
2198}
2199
2200/*
2201 * rebuild remote INSERT statement
2202 *
2203 * Provided a number of rows in a batch, builds INSERT statement with the
2204 * right number of parameters.
2205 */
2206void
2208 char *orig_query, List *target_attrs,
2209 int values_end_len, int num_params,
2210 int num_rows)
2211{
2212 TupleDesc tupdesc = RelationGetDescr(rel);
2213 int i;
2214 int pindex;
2215 bool first;
2216 ListCell *lc;
2217
2218 /* Make sure the values_end_len is sensible */
2219 Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
2220
2221 /* Copy up to the end of the first record from the original query */
2223
2224 /*
2225 * Add records to VALUES clause (we already have parameters for the first
2226 * row, so start at the right offset).
2227 */
2228 pindex = num_params + 1;
2229 for (i = 0; i < num_rows; i++)
2230 {
2232
2233 first = true;
2234 foreach(lc, target_attrs)
2235 {
2236 int attnum = lfirst_int(lc);
2237 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2238
2239 if (!first)
2241 first = false;
2242
2243 if (attr->attgenerated)
2244 appendStringInfoString(buf, "DEFAULT");
2245 else
2246 {
2247 appendStringInfo(buf, "$%d", pindex);
2248 pindex++;
2249 }
2250 }
2251
2253 }
2254
2255 /* Copy stuff after VALUES clause from the original query */
2257}
2258
2259/*
2260 * deparse remote UPDATE statement
2261 *
2262 * The statement text is appended to buf, and we also create an integer List
2263 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
2264 * which is returned to *retrieved_attrs.
2265 */
2266void
2268 Index rtindex, Relation rel,
2270 List *withCheckOptionList, List *returningList,
2271 List **retrieved_attrs)
2272{
2273 TupleDesc tupdesc = RelationGetDescr(rel);
2275 bool first;
2276 ListCell *lc;
2277
2278 appendStringInfoString(buf, "UPDATE ");
2279 deparseRelation(buf, rel);
2280 appendStringInfoString(buf, " SET ");
2281
2282 pindex = 2; /* ctid is always the first param */
2283 first = true;
2284 foreach(lc, targetAttrs)
2285 {
2286 int attnum = lfirst_int(lc);
2287 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2288
2289 if (!first)
2291 first = false;
2292
2293 deparseColumnRef(buf, rtindex, attnum, rte, false);
2294 if (attr->attgenerated)
2295 appendStringInfoString(buf, " = DEFAULT");
2296 else
2297 {
2298 appendStringInfo(buf, " = $%d", pindex);
2299 pindex++;
2300 }
2301 }
2302 appendStringInfoString(buf, " WHERE ctid = $1");
2303
2304 deparseReturningList(buf, rte, rtindex, rel,
2306 withCheckOptionList, returningList, retrieved_attrs);
2307}
2308
2309/*
2310 * deparse remote UPDATE statement
2311 *
2312 * 'buf' is the output buffer to append the statement to
2313 * 'rtindex' is the RT index of the associated target relation
2314 * 'rel' is the relation descriptor for the target relation
2315 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
2316 * containing all base relations in the query
2317 * 'targetlist' is the tlist of the underlying foreign-scan plan node
2318 * (note that this only contains new-value expressions and junk attrs)
2319 * 'targetAttrs' is the target columns of the UPDATE
2320 * 'remote_conds' is the qual clauses that must be evaluated remotely
2321 * '*params_list' is an output list of exprs that will become remote Params
2322 * 'returningList' is the RETURNING targetlist
2323 * '*retrieved_attrs' is an output list of integers of columns being retrieved
2324 * by RETURNING (if any)
2325 */
2326void
2328 Index rtindex, Relation rel,
2329 RelOptInfo *foreignrel,
2330 List *targetlist,
2332 List *remote_conds,
2333 List **params_list,
2334 List *returningList,
2335 List **retrieved_attrs)
2336{
2337 deparse_expr_cxt context;
2338 int nestlevel;
2339 bool first;
2341 ListCell *lc,
2342 *lc2;
2344
2345 /* Set up context struct for recursion */
2346 context.root = root;
2347 context.foreignrel = foreignrel;
2348 context.scanrel = foreignrel;
2349 context.buf = buf;
2350 context.params_list = params_list;
2351
2352 appendStringInfoString(buf, "UPDATE ");
2353 deparseRelation(buf, rel);
2354 if (foreignrel->reloptkind == RELOPT_JOINREL)
2355 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2356 appendStringInfoString(buf, " SET ");
2357
2358 /* Make sure any constants in the exprs are printed portably */
2360
2361 first = true;
2362 forboth(lc, targetlist, lc2, targetAttrs)
2363 {
2365 int attnum = lfirst_int(lc2);
2366
2367 /* update's new-value expressions shouldn't be resjunk */
2368 Assert(!tle->resjunk);
2369
2370 if (!first)
2372 first = false;
2373
2374 deparseColumnRef(buf, rtindex, attnum, rte, false);
2376 deparseExpr((Expr *) tle->expr, &context);
2377 }
2378
2380
2381 if (foreignrel->reloptkind == RELOPT_JOINREL)
2382 {
2384
2385
2386 appendStringInfoString(buf, " FROM ");
2387 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2388 &ignore_conds, &additional_conds, params_list);
2389 remote_conds = list_concat(remote_conds, ignore_conds);
2390 }
2391
2392 appendWhereClause(remote_conds, additional_conds, &context);
2393
2394 if (additional_conds != NIL)
2396
2397 if (foreignrel->reloptkind == RELOPT_JOINREL)
2398 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2399 &context);
2400 else
2401 deparseReturningList(buf, rte, rtindex, rel, false,
2402 NIL, returningList, retrieved_attrs);
2403}
2404
2405/*
2406 * deparse remote DELETE statement
2407 *
2408 * The statement text is appended to buf, and we also create an integer List
2409 * of the columns being retrieved by RETURNING (if any), which is returned
2410 * to *retrieved_attrs.
2411 */
2412void
2414 Index rtindex, Relation rel,
2415 List *returningList,
2416 List **retrieved_attrs)
2417{
2418 appendStringInfoString(buf, "DELETE FROM ");
2419 deparseRelation(buf, rel);
2420 appendStringInfoString(buf, " WHERE ctid = $1");
2421
2422 deparseReturningList(buf, rte, rtindex, rel,
2424 NIL, returningList, retrieved_attrs);
2425}
2426
2427/*
2428 * deparse remote DELETE statement
2429 *
2430 * 'buf' is the output buffer to append the statement to
2431 * 'rtindex' is the RT index of the associated target relation
2432 * 'rel' is the relation descriptor for the target relation
2433 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
2434 * containing all base relations in the query
2435 * 'remote_conds' is the qual clauses that must be evaluated remotely
2436 * '*params_list' is an output list of exprs that will become remote Params
2437 * 'returningList' is the RETURNING targetlist
2438 * '*retrieved_attrs' is an output list of integers of columns being retrieved
2439 * by RETURNING (if any)
2440 */
2441void
2443 Index rtindex, Relation rel,
2444 RelOptInfo *foreignrel,
2445 List *remote_conds,
2446 List **params_list,
2447 List *returningList,
2448 List **retrieved_attrs)
2449{
2450 deparse_expr_cxt context;
2452
2453 /* Set up context struct for recursion */
2454 context.root = root;
2455 context.foreignrel = foreignrel;
2456 context.scanrel = foreignrel;
2457 context.buf = buf;
2458 context.params_list = params_list;
2459
2460 appendStringInfoString(buf, "DELETE FROM ");
2461 deparseRelation(buf, rel);
2462 if (foreignrel->reloptkind == RELOPT_JOINREL)
2463 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2464
2465 if (foreignrel->reloptkind == RELOPT_JOINREL)
2466 {
2468
2469 appendStringInfoString(buf, " USING ");
2470 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2471 &ignore_conds, &additional_conds, params_list);
2472 remote_conds = list_concat(remote_conds, ignore_conds);
2473 }
2474
2475 appendWhereClause(remote_conds, additional_conds, &context);
2476
2477 if (additional_conds != NIL)
2479
2480 if (foreignrel->reloptkind == RELOPT_JOINREL)
2481 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2482 &context);
2483 else
2485 rtindex, rel, false,
2486 NIL, returningList, retrieved_attrs);
2487}
2488
2489/*
2490 * Add a RETURNING clause, if needed, to an INSERT/UPDATE/DELETE.
2491 */
2492static void
2494 Index rtindex, Relation rel,
2495 bool trig_after_row,
2497 List *returningList,
2498 List **retrieved_attrs)
2499{
2500 Bitmapset *attrs_used = NULL;
2501
2502 if (trig_after_row)
2503 {
2504 /* whole-row reference acquires all non-system columns */
2505 attrs_used =
2507 }
2508
2509 if (withCheckOptionList != NIL)
2510 {
2511 /*
2512 * We need the attrs, non-system and system, mentioned in the local
2513 * query's WITH CHECK OPTION list.
2514 *
2515 * Note: we do this to ensure that WCO constraints will be evaluated
2516 * on the data actually inserted/updated on the remote side, which
2517 * might differ from the data supplied by the core code, for example
2518 * as a result of remote triggers.
2519 */
2521 &attrs_used);
2522 }
2523
2524 if (returningList != NIL)
2525 {
2526 /*
2527 * We need the attrs, non-system and system, mentioned in the local
2528 * query's RETURNING list.
2529 */
2530 pull_varattnos((Node *) returningList, rtindex,
2531 &attrs_used);
2532 }
2533
2534 if (attrs_used != NULL)
2535 deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2536 retrieved_attrs);
2537 else
2538 *retrieved_attrs = NIL;
2539}
2540
2541/*
2542 * Construct SELECT statement to acquire size in blocks of given relation.
2543 *
2544 * Note: we use local definition of block size, not remote definition.
2545 * This is perhaps debatable.
2546 *
2547 * Note: pg_relation_size() exists in 8.1 and later.
2548 */
2549void
2551{
2553
2554 /* We'll need the remote relation name as a literal. */
2556 deparseRelation(&relname, rel);
2557
2558 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2560 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2561}
2562
2563/*
2564 * Construct SELECT statement to acquire the number of pages, the number of
2565 * rows, and the relkind of a relation.
2566 *
2567 * Note: we just return the remote server's reltuples value, which might
2568 * be off a good deal, but it doesn't seem worth working harder. See
2569 * comments in postgresAcquireSampleRowsFunc.
2570 */
2571void
2573{
2575
2576 /* We'll need the remote relation name as a literal. */
2578 deparseRelation(&relname, rel);
2579
2580 appendStringInfoString(buf, "SELECT relpages, reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2582 appendStringInfoString(buf, "::pg_catalog.regclass");
2583}
2584
2585/*
2586 * Construct SELECT statement to acquire sample rows of given relation.
2587 *
2588 * SELECT command is appended to buf, and list of columns retrieved
2589 * is returned to *retrieved_attrs.
2590 *
2591 * We only support sampling methods we can decide based on server version.
2592 * Allowing custom TSM modules (like tsm_system_rows) might be useful, but it
2593 * would require detecting which extensions are installed, to allow automatic
2594 * fall-back. Moreover, the methods may use different parameters like number
2595 * of rows (and not sampling rate). So we leave this for future improvements.
2596 *
2597 * Using random() to sample rows on the remote server has the advantage that
2598 * this works on all PostgreSQL versions (unlike TABLESAMPLE), and that it
2599 * does the sampling on the remote side (without transferring everything and
2600 * then discarding most rows).
2601 *
2602 * The disadvantage is that we still have to read all rows and evaluate the
2603 * random(), while TABLESAMPLE (at least with the "system" method) may skip.
2604 * It's not that different from the "bernoulli" method, though.
2605 *
2606 * We could also do "ORDER BY random() LIMIT x", which would always pick
2607 * the expected number of rows, but it requires sorting so it may be much
2608 * more expensive (particularly on large tables, which is what the
2609 * remote sampling is meant to improve).
2610 */
2611void
2614 List **retrieved_attrs)
2615{
2616 Oid relid = RelationGetRelid(rel);
2617 TupleDesc tupdesc = RelationGetDescr(rel);
2618 int i;
2619 char *colname;
2620 List *options;
2621 ListCell *lc;
2622 bool first = true;
2623
2624 *retrieved_attrs = NIL;
2625
2626 appendStringInfoString(buf, "SELECT ");
2627 for (i = 0; i < tupdesc->natts; i++)
2628 {
2629 /* Ignore dropped columns. */
2630 if (TupleDescAttr(tupdesc, i)->attisdropped)
2631 continue;
2632
2633 if (!first)
2635 first = false;
2636
2637 /* Use attribute name or column_name option. */
2638 colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2639 options = GetForeignColumnOptions(relid, i + 1);
2640
2641 foreach(lc, options)
2642 {
2643 DefElem *def = (DefElem *) lfirst(lc);
2644
2645 if (strcmp(def->defname, "column_name") == 0)
2646 {
2647 colname = defGetString(def);
2648 break;
2649 }
2650 }
2651
2653
2654 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2655 }
2656
2657 /* Don't generate bad syntax for zero-column relation. */
2658 if (first)
2659 appendStringInfoString(buf, "NULL");
2660
2661 /*
2662 * Construct FROM clause, and perhaps WHERE clause too, depending on the
2663 * selected sampling method.
2664 */
2665 appendStringInfoString(buf, " FROM ");
2666 deparseRelation(buf, rel);
2667
2668 switch (sample_method)
2669 {
2670 case ANALYZE_SAMPLE_OFF:
2671 /* nothing to do here */
2672 break;
2673
2675 appendStringInfo(buf, " WHERE pg_catalog.random() < %f", sample_frac);
2676 break;
2677
2679 appendStringInfo(buf, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac));
2680 break;
2681
2683 appendStringInfo(buf, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac));
2684 break;
2685
2687 /* should have been resolved into actual method */
2688 elog(ERROR, "unexpected sampling method");
2689 break;
2690 }
2691}
2692
2693/*
2694 * Construct a simple "TRUNCATE rel" statement
2695 */
2696void
2698 List *rels,
2699 DropBehavior behavior,
2700 bool restart_seqs)
2701{
2702 ListCell *cell;
2703
2704 appendStringInfoString(buf, "TRUNCATE ");
2705
2706 foreach(cell, rels)
2707 {
2708 Relation rel = lfirst(cell);
2709
2710 if (cell != list_head(rels))
2712
2713 deparseRelation(buf, rel);
2714 }
2715
2716 appendStringInfo(buf, " %s IDENTITY",
2717 restart_seqs ? "RESTART" : "CONTINUE");
2718
2719 if (behavior == DROP_RESTRICT)
2720 appendStringInfoString(buf, " RESTRICT");
2721 else if (behavior == DROP_CASCADE)
2722 appendStringInfoString(buf, " CASCADE");
2723}
2724
2725/*
2726 * Construct name to use for given column, and emit it into buf.
2727 * If it has a column_name FDW option, use that instead of attribute name.
2728 *
2729 * If qualify_col is true, qualify column name with the alias of relation.
2730 */
2731static void
2733 bool qualify_col)
2734{
2735 /* We support fetching the remote side's CTID and OID. */
2736 if (varattno == SelfItemPointerAttributeNumber)
2737 {
2738 if (qualify_col)
2739 ADD_REL_QUALIFIER(buf, varno);
2740 appendStringInfoString(buf, "ctid");
2741 }
2742 else if (varattno < 0)
2743 {
2744 /*
2745 * All other system attributes are fetched as 0, except for table OID,
2746 * which is fetched as the local table OID. However, we must be
2747 * careful; the table could be beneath an outer join, in which case it
2748 * must go to NULL whenever the rest of the row does.
2749 */
2750 Oid fetchval = 0;
2751
2752 if (varattno == TableOidAttributeNumber)
2753 fetchval = rte->relid;
2754
2755 if (qualify_col)
2756 {
2757 appendStringInfoString(buf, "CASE WHEN (");
2758 ADD_REL_QUALIFIER(buf, varno);
2759 appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2760 }
2761 else
2763 }
2764 else if (varattno == 0)
2765 {
2766 /* Whole row reference */
2767 Relation rel;
2768 Bitmapset *attrs_used;
2769
2770 /* Required only to be passed down to deparseTargetList(). */
2771 List *retrieved_attrs;
2772
2773 /*
2774 * The lock on the relation will be held by upper callers, so it's
2775 * fine to open it with no lock here.
2776 */
2777 rel = table_open(rte->relid, NoLock);
2778
2779 /*
2780 * The local name of the foreign table can not be recognized by the
2781 * foreign server and the table it references on foreign server might
2782 * have different column ordering or different columns than those
2783 * declared locally. Hence we have to deparse whole-row reference as
2784 * ROW(columns referenced locally). Construct this by deparsing a
2785 * "whole row" attribute.
2786 */
2787 attrs_used = bms_add_member(NULL,
2789
2790 /*
2791 * In case the whole-row reference is under an outer join then it has
2792 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2793 * query would always involve multiple relations, thus qualify_col
2794 * would be true.
2795 */
2796 if (qualify_col)
2797 {
2798 appendStringInfoString(buf, "CASE WHEN (");
2799 ADD_REL_QUALIFIER(buf, varno);
2800 appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2801 }
2802
2803 appendStringInfoString(buf, "ROW(");
2804 deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2805 &retrieved_attrs);
2807
2808 /* Complete the CASE WHEN statement started above. */
2809 if (qualify_col)
2810 appendStringInfoString(buf, " END");
2811
2812 table_close(rel, NoLock);
2813 bms_free(attrs_used);
2814 }
2815 else
2816 {
2817 char *colname = NULL;
2818 List *options;
2819 ListCell *lc;
2820
2821 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2822 Assert(!IS_SPECIAL_VARNO(varno));
2823
2824 /*
2825 * If it's a column of a foreign table, and it has the column_name FDW
2826 * option, use that value.
2827 */
2828 options = GetForeignColumnOptions(rte->relid, varattno);
2829 foreach(lc, options)
2830 {
2831 DefElem *def = (DefElem *) lfirst(lc);
2832
2833 if (strcmp(def->defname, "column_name") == 0)
2834 {
2835 colname = defGetString(def);
2836 break;
2837 }
2838 }
2839
2840 /*
2841 * If it's a column of a regular table or it doesn't have column_name
2842 * FDW option, use attribute name.
2843 */
2844 if (colname == NULL)
2845 colname = get_attname(rte->relid, varattno, false);
2846
2847 if (qualify_col)
2848 ADD_REL_QUALIFIER(buf, varno);
2849
2851 }
2852}
2853
2854/*
2855 * Append remote name of specified foreign table to buf.
2856 * Use value of table_name FDW option (if any) instead of relation's name.
2857 * Similarly, schema_name FDW option overrides schema name.
2858 */
2859static void
2861{
2863 const char *nspname = NULL;
2864 const char *relname = NULL;
2865 ListCell *lc;
2866
2867 /* obtain additional catalog information. */
2869
2870 /*
2871 * Use value of FDW options if any, instead of the name of object itself.
2872 */
2873 foreach(lc, table->options)
2874 {
2875 DefElem *def = (DefElem *) lfirst(lc);
2876
2877 if (strcmp(def->defname, "schema_name") == 0)
2878 nspname = defGetString(def);
2879 else if (strcmp(def->defname, "table_name") == 0)
2880 relname = defGetString(def);
2881 }
2882
2883 /*
2884 * Note: we could skip printing the schema name if it's pg_catalog, but
2885 * that doesn't seem worth the trouble.
2886 */
2887 if (nspname == NULL)
2889 if (relname == NULL)
2891
2892 appendStringInfo(buf, "%s.%s",
2894}
2895
2896/*
2897 * Append a SQL string literal representing "val" to buf.
2898 */
2899void
2901{
2902 const char *valptr;
2903
2904 /*
2905 * Rather than making assumptions about the remote server's value of
2906 * standard_conforming_strings, always use E'foo' syntax if there are any
2907 * backslashes. This will fail on remote servers before 8.1, but those
2908 * are long out of support.
2909 */
2910 if (strchr(val, '\\') != NULL)
2913 for (valptr = val; *valptr; valptr++)
2914 {
2915 char ch = *valptr;
2916
2917 if (SQL_STR_DOUBLE(ch, true))
2920 }
2922}
2923
2924/*
2925 * Deparse given expression into context->buf.
2926 *
2927 * This function must support all the same node types that foreign_expr_walker
2928 * accepts.
2929 *
2930 * Note: unlike ruleutils.c, we just use a simple hard-wired parenthesization
2931 * scheme: anything more complex than a Var, Const, function call or cast
2932 * should be self-parenthesized.
2933 */
2934static void
2936{
2937 if (node == NULL)
2938 return;
2939
2940 switch (nodeTag(node))
2941 {
2942 case T_Var:
2943 deparseVar((Var *) node, context);
2944 break;
2945 case T_Const:
2946 deparseConst((Const *) node, context, 0);
2947 break;
2948 case T_Param:
2949 deparseParam((Param *) node, context);
2950 break;
2951 case T_SubscriptingRef:
2952 deparseSubscriptingRef((SubscriptingRef *) node, context);
2953 break;
2954 case T_FuncExpr:
2955 deparseFuncExpr((FuncExpr *) node, context);
2956 break;
2957 case T_OpExpr:
2958 deparseOpExpr((OpExpr *) node, context);
2959 break;
2960 case T_DistinctExpr:
2961 deparseDistinctExpr((DistinctExpr *) node, context);
2962 break;
2965 break;
2966 case T_RelabelType:
2967 deparseRelabelType((RelabelType *) node, context);
2968 break;
2969 case T_ArrayCoerceExpr:
2970 deparseArrayCoerceExpr((ArrayCoerceExpr *) node, context);
2971 break;
2972 case T_BoolExpr:
2973 deparseBoolExpr((BoolExpr *) node, context);
2974 break;
2975 case T_NullTest:
2976 deparseNullTest((NullTest *) node, context);
2977 break;
2978 case T_CaseExpr:
2979 deparseCaseExpr((CaseExpr *) node, context);
2980 break;
2981 case T_ArrayExpr:
2982 deparseArrayExpr((ArrayExpr *) node, context);
2983 break;
2984 case T_Aggref:
2985 deparseAggref((Aggref *) node, context);
2986 break;
2987 default:
2988 elog(ERROR, "unsupported expression type for deparse: %d",
2989 (int) nodeTag(node));
2990 break;
2991 }
2992}
2993
2994/*
2995 * Deparse given Var node into context->buf.
2996 *
2997 * If the Var belongs to the foreign relation, just print its remote name.
2998 * Otherwise, it's effectively a Param (and will in fact be a Param at
2999 * run time). Handle it the same way we handle plain Params --- see
3000 * deparseParam for comments.
3001 */
3002static void
3004{
3005 Relids relids = context->scanrel->relids;
3006 int relno;
3007 int colno;
3008
3009 /* Qualify columns when multiple relations are involved. */
3010 bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
3011
3012 /*
3013 * If the Var belongs to the foreign relation that is deparsed as a
3014 * subquery, use the relation and column alias to the Var provided by the
3015 * subquery, instead of the remote name.
3016 */
3017 if (is_subquery_var(node, context->scanrel, &relno, &colno))
3018 {
3019 appendStringInfo(context->buf, "%s%d.%s%d",
3022 return;
3023 }
3024
3025 if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
3026 deparseColumnRef(context->buf, node->varno, node->varattno,
3027 planner_rt_fetch(node->varno, context->root),
3028 qualify_col);
3029 else
3030 {
3031 /* Treat like a Param */
3032 if (context->params_list)
3033 {
3034 int pindex = 0;
3035 ListCell *lc;
3036
3037 /* find its index in params_list */
3038 foreach(lc, *context->params_list)
3039 {
3040 pindex++;
3041 if (equal(node, (Node *) lfirst(lc)))
3042 break;
3043 }
3044 if (lc == NULL)
3045 {
3046 /* not in list, so add it */
3047 pindex++;
3048 *context->params_list = lappend(*context->params_list, node);
3049 }
3050
3051 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
3052 }
3053 else
3054 {
3055 printRemotePlaceholder(node->vartype, node->vartypmod, context);
3056 }
3057 }
3058}
3059
3060/*
3061 * Deparse given constant value into context->buf.
3062 *
3063 * This function has to be kept in sync with ruleutils.c's get_const_expr.
3064 *
3065 * As in that function, showtype can be -1 to never show "::typename"
3066 * decoration, +1 to always show it, or 0 to show it only if the constant
3067 * wouldn't be assumed to be the right type by default.
3068 *
3069 * In addition, this code allows showtype to be -2 to indicate that we should
3070 * not show "::typename" decoration if the constant is printed as an untyped
3071 * literal or NULL (while in other cases, behaving as for showtype == 0).
3072 */
3073static void
3075{
3076 StringInfo buf = context->buf;
3077 Oid typoutput;
3078 bool typIsVarlena;
3079 char *extval;
3080 bool isfloat = false;
3081 bool isstring = false;
3082 bool needlabel;
3083
3084 if (node->constisnull)
3085 {
3086 appendStringInfoString(buf, "NULL");
3087 if (showtype >= 0)
3088 appendStringInfo(buf, "::%s",
3090 node->consttypmod));
3091 return;
3092 }
3093
3095 &typoutput, &typIsVarlena);
3096 extval = OidOutputFunctionCall(typoutput, node->constvalue);
3097
3098 switch (node->consttype)
3099 {
3100 case INT2OID:
3101 case INT4OID:
3102 case INT8OID:
3103 case OIDOID:
3104 case FLOAT4OID:
3105 case FLOAT8OID:
3106 case NUMERICOID:
3107 {
3108 /*
3109 * No need to quote unless it's a special value such as 'NaN'.
3110 * See comments in get_const_expr().
3111 */
3112 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
3113 {
3114 if (extval[0] == '+' || extval[0] == '-')
3115 appendStringInfo(buf, "(%s)", extval);
3116 else
3118 if (strcspn(extval, "eE.") != strlen(extval))
3119 isfloat = true; /* it looks like a float */
3120 }
3121 else
3122 appendStringInfo(buf, "'%s'", extval);
3123 }
3124 break;
3125 case BITOID:
3126 case VARBITOID:
3127 appendStringInfo(buf, "B'%s'", extval);
3128 break;
3129 case BOOLOID:
3130 if (strcmp(extval, "t") == 0)
3131 appendStringInfoString(buf, "true");
3132 else
3133 appendStringInfoString(buf, "false");
3134 break;
3135 default:
3137 isstring = true;
3138 break;
3139 }
3140
3141 pfree(extval);
3142
3143 if (showtype == -1)
3144 return; /* never print type label */
3145
3146 /*
3147 * For showtype == 0, append ::typename unless the constant will be
3148 * implicitly typed as the right type when it is read in.
3149 *
3150 * XXX this code has to be kept in sync with the behavior of the parser,
3151 * especially make_const.
3152 */
3153 switch (node->consttype)
3154 {
3155 case BOOLOID:
3156 case INT4OID:
3157 case UNKNOWNOID:
3158 needlabel = false;
3159 break;
3160 case NUMERICOID:
3161 needlabel = !isfloat || (node->consttypmod >= 0);
3162 break;
3163 default:
3164 if (showtype == -2)
3165 {
3166 /* label unless we printed it as an untyped string */
3168 }
3169 else
3170 needlabel = true;
3171 break;
3172 }
3173 if (needlabel || showtype > 0)
3174 appendStringInfo(buf, "::%s",
3176 node->consttypmod));
3177}
3178
3179/*
3180 * Deparse given Param node.
3181 *
3182 * If we're generating the query "for real", add the Param to
3183 * context->params_list if it's not already present, and then use its index
3184 * in that list as the remote parameter number. During EXPLAIN, there's
3185 * no need to identify a parameter number.
3186 */
3187static void
3189{
3190 if (context->params_list)
3191 {
3192 int pindex = 0;
3193 ListCell *lc;
3194
3195 /* find its index in params_list */
3196 foreach(lc, *context->params_list)
3197 {
3198 pindex++;
3199 if (equal(node, (Node *) lfirst(lc)))
3200 break;
3201 }
3202 if (lc == NULL)
3203 {
3204 /* not in list, so add it */
3205 pindex++;
3206 *context->params_list = lappend(*context->params_list, node);
3207 }
3208
3209 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
3210 }
3211 else
3212 {
3213 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
3214 }
3215}
3216
3217/*
3218 * Deparse a container subscript expression.
3219 */
3220static void
3222{
3223 StringInfo buf = context->buf;
3226
3227 /* Always parenthesize the expression. */
3229
3230 /*
3231 * Deparse referenced array expression first. If that expression includes
3232 * a cast, we have to parenthesize to prevent the array subscript from
3233 * being taken as typename decoration. We can avoid that in the typical
3234 * case of subscripting a Var, but otherwise do it.
3235 */
3236 if (IsA(node->refexpr, Var))
3237 deparseExpr(node->refexpr, context);
3238 else
3239 {
3241 deparseExpr(node->refexpr, context);
3243 }
3244
3245 /* Deparse subscript expressions. */
3246 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
3247 foreach(uplist_item, node->refupperindexpr)
3248 {
3250 if (lowlist_item)
3251 {
3252 deparseExpr(lfirst(lowlist_item), context);
3255 }
3256 deparseExpr(lfirst(uplist_item), context);
3258 }
3259
3261}
3262
3263/*
3264 * Deparse a function call.
3265 */
3266static void
3268{
3269 StringInfo buf = context->buf;
3270 bool use_variadic;
3271 bool first;
3272 ListCell *arg;
3273
3274 /*
3275 * If the function call came from an implicit coercion, then just show the
3276 * first argument.
3277 */
3278 if (node->funcformat == COERCE_IMPLICIT_CAST)
3279 {
3280 deparseExpr((Expr *) linitial(node->args), context);
3281 return;
3282 }
3283
3284 /*
3285 * If the function call came from a cast, then show the first argument
3286 * plus an explicit cast operation.
3287 */
3288 if (node->funcformat == COERCE_EXPLICIT_CAST)
3289 {
3290 Oid rettype = node->funcresulttype;
3292
3293 /* Get the typmod if this is a length-coercion function */
3295
3296 deparseExpr((Expr *) linitial(node->args), context);
3297 appendStringInfo(buf, "::%s",
3299 return;
3300 }
3301
3302 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3303 use_variadic = node->funcvariadic;
3304
3305 /*
3306 * Normal function: display as proname(args).
3307 */
3308 appendFunctionName(node->funcid, context);
3310
3311 /* ... and all the arguments */
3312 first = true;
3313 foreach(arg, node->args)
3314 {
3315 if (!first)
3317 if (use_variadic && lnext(node->args, arg) == NULL)
3318 appendStringInfoString(buf, "VARIADIC ");
3319 deparseExpr((Expr *) lfirst(arg), context);
3320 first = false;
3321 }
3323}
3324
3325/*
3326 * Deparse given operator expression. To avoid problems around
3327 * priority of operations, we always parenthesize the arguments.
3328 */
3329static void
3331{
3332 StringInfo buf = context->buf;
3333 HeapTuple tuple;
3335 Expr *right;
3336 bool canSuppressRightConstCast = false;
3337 char oprkind;
3338
3339 /* Retrieve information about the operator from system catalog. */
3341 if (!HeapTupleIsValid(tuple))
3342 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3343 form = (Form_pg_operator) GETSTRUCT(tuple);
3344 oprkind = form->oprkind;
3345
3346 /* Sanity check. */
3347 Assert((oprkind == 'l' && list_length(node->args) == 1) ||
3348 (oprkind == 'b' && list_length(node->args) == 2));
3349
3350 right = llast(node->args);
3351
3352 /* Always parenthesize the expression. */
3354
3355 /* Deparse left operand, if any. */
3356 if (oprkind == 'b')
3357 {
3358 Expr *left = linitial(node->args);
3359 Oid leftType = exprType((Node *) left);
3360 Oid rightType = exprType((Node *) right);
3361 bool canSuppressLeftConstCast = false;
3362
3363 /*
3364 * When considering a binary operator, if one operand is a Const that
3365 * can be printed as a bare string literal or NULL (i.e., it will look
3366 * like type UNKNOWN to the remote parser), the Const normally
3367 * receives an explicit cast to the operator's input type. However,
3368 * in Const-to-Var comparisons where both operands are of the same
3369 * type, we prefer to suppress the explicit cast, leaving the Const's
3370 * type resolution up to the remote parser. The remote's resolution
3371 * heuristic will assume that an unknown input type being compared to
3372 * a known input type is of that known type as well.
3373 *
3374 * This hack allows some cases to succeed where a remote column is
3375 * declared with a different type in the local (foreign) table. By
3376 * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3377 * like, we allow the remote parser to pick an "=" operator that's
3378 * compatible with whatever type the remote column really is, such as
3379 * an enum.
3380 *
3381 * We allow cast suppression to happen only when the other operand is
3382 * a plain foreign Var. Although the remote's unknown-type heuristic
3383 * would apply to other cases just as well, we would be taking a
3384 * bigger risk that the inferred type is something unexpected. With
3385 * this restriction, if anything goes wrong it's the user's fault for
3386 * not declaring the local column with the same type as the remote
3387 * column.
3388 */
3389 if (leftType == rightType)
3390 {
3391 if (IsA(left, Const))
3393 else if (IsA(right, Const))
3395 }
3396
3398 deparseConst((Const *) left, context, -2);
3399 else
3400 deparseExpr(left, context);
3401
3403 }
3404
3405 /* Deparse operator name. */
3407
3408 /* Deparse right operand. */
3410
3412 deparseConst((Const *) right, context, -2);
3413 else
3414 deparseExpr(right, context);
3415
3417
3418 ReleaseSysCache(tuple);
3419}
3420
3421/*
3422 * Will "node" deparse as a plain foreign Var?
3423 */
3424static bool
3426{
3427 /*
3428 * We allow the foreign Var to have an implicit RelabelType, mainly so
3429 * that this'll work with varchar columns. Note that deparseRelabelType
3430 * will not print such a cast, so we're not breaking the restriction that
3431 * the expression print as a plain Var. We won't risk it for an implicit
3432 * cast that requires a function, nor for non-implicit RelabelType; such
3433 * cases seem too likely to involve semantics changes compared to what
3434 * would happen on the remote side.
3435 */
3436 if (IsA(node, RelabelType) &&
3438 node = ((RelabelType *) node)->arg;
3439
3440 if (IsA(node, Var))
3441 {
3442 /*
3443 * The Var must be one that'll deparse as a foreign column reference
3444 * (cf. deparseVar).
3445 */
3446 Var *var = (Var *) node;
3447 Relids relids = context->scanrel->relids;
3448
3449 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3450 return true;
3451 }
3452
3453 return false;
3454}
3455
3456/*
3457 * Print the name of an operator.
3458 */
3459static void
3461{
3462 char *opname;
3463
3464 /* opname is not a SQL identifier, so we should not quote it. */
3465 opname = NameStr(opform->oprname);
3466
3467 /* Print schema name only if it's not pg_catalog */
3468 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3469 {
3470 const char *opnspname;
3471
3472 opnspname = get_namespace_name(opform->oprnamespace);
3473 /* Print fully qualified operator name. */
3474 appendStringInfo(buf, "OPERATOR(%s.%s)",
3476 }
3477 else
3478 {
3479 /* Just print operator name. */
3481 }
3482}
3483
3484/*
3485 * Deparse IS DISTINCT FROM.
3486 */
3487static void
3489{
3490 StringInfo buf = context->buf;
3491
3492 Assert(list_length(node->args) == 2);
3493
3495 deparseExpr(linitial(node->args), context);
3496 appendStringInfoString(buf, " IS DISTINCT FROM ");
3497 deparseExpr(lsecond(node->args), context);
3499}
3500
3501/*
3502 * Deparse given ScalarArrayOpExpr expression. To avoid problems
3503 * around priority of operations, we always parenthesize the arguments.
3504 */
3505static void
3507{
3508 StringInfo buf = context->buf;
3509 HeapTuple tuple;
3511 Expr *arg1;
3512 Expr *arg2;
3513
3514 /* Retrieve information about the operator from system catalog. */
3516 if (!HeapTupleIsValid(tuple))
3517 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3518 form = (Form_pg_operator) GETSTRUCT(tuple);
3519
3520 /* Sanity check. */
3521 Assert(list_length(node->args) == 2);
3522
3523 /* Always parenthesize the expression. */
3525
3526 /* Deparse left operand. */
3527 arg1 = linitial(node->args);
3528 deparseExpr(arg1, context);
3530
3531 /* Deparse operator name plus decoration. */
3533 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3534
3535 /* Deparse right operand. */
3536 arg2 = lsecond(node->args);
3537 deparseExpr(arg2, context);
3538
3540
3541 /* Always parenthesize the expression. */
3543
3544 ReleaseSysCache(tuple);
3545}
3546
3547/*
3548 * Deparse a RelabelType (binary-compatible cast) node.
3549 */
3550static void
3552{
3553 deparseExpr(node->arg, context);
3554 if (node->relabelformat != COERCE_IMPLICIT_CAST)
3555 appendStringInfo(context->buf, "::%s",
3557 node->resulttypmod));
3558}
3559
3560/*
3561 * Deparse an ArrayCoerceExpr (array-type conversion) node.
3562 */
3563static void
3565{
3566 deparseExpr(node->arg, context);
3567
3568 /*
3569 * No difference how to deparse explicit cast, but if we omit implicit
3570 * cast in the query, it'll be more user-friendly
3571 */
3572 if (node->coerceformat != COERCE_IMPLICIT_CAST)
3573 appendStringInfo(context->buf, "::%s",
3575 node->resulttypmod));
3576}
3577
3578/*
3579 * Deparse a BoolExpr node.
3580 */
3581static void
3583{
3584 StringInfo buf = context->buf;
3585 const char *op = NULL; /* keep compiler quiet */
3586 bool first;
3587 ListCell *lc;
3588
3589 switch (node->boolop)
3590 {
3591 case AND_EXPR:
3592 op = "AND";
3593 break;
3594 case OR_EXPR:
3595 op = "OR";
3596 break;
3597 case NOT_EXPR:
3598 appendStringInfoString(buf, "(NOT ");
3599 deparseExpr(linitial(node->args), context);
3601 return;
3602 }
3603
3605 first = true;
3606 foreach(lc, node->args)
3607 {
3608 if (!first)
3609 appendStringInfo(buf, " %s ", op);
3610 deparseExpr((Expr *) lfirst(lc), context);
3611 first = false;
3612 }
3614}
3615
3616/*
3617 * Deparse IS [NOT] NULL expression.
3618 */
3619static void
3621{
3622 StringInfo buf = context->buf;
3623
3625 deparseExpr(node->arg, context);
3626
3627 /*
3628 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3629 * shorter and traditional. If it's a rowtype input but we're applying a
3630 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3631 * correct.
3632 */
3633 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3634 {
3635 if (node->nulltesttype == IS_NULL)
3636 appendStringInfoString(buf, " IS NULL)");
3637 else
3638 appendStringInfoString(buf, " IS NOT NULL)");
3639 }
3640 else
3641 {
3642 if (node->nulltesttype == IS_NULL)
3643 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3644 else
3645 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3646 }
3647}
3648
3649/*
3650 * Deparse CASE expression
3651 */
3652static void
3654{
3655 StringInfo buf = context->buf;
3656 ListCell *lc;
3657
3658 appendStringInfoString(buf, "(CASE");
3659
3660 /* If this is a CASE arg WHEN then emit the arg expression */
3661 if (node->arg != NULL)
3662 {
3664 deparseExpr(node->arg, context);
3665 }
3666
3667 /* Add each condition/result of the CASE clause */
3668 foreach(lc, node->args)
3669 {
3670 CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3671
3672 /* WHEN */
3673 appendStringInfoString(buf, " WHEN ");
3674 if (node->arg == NULL) /* CASE WHEN */
3675 deparseExpr(whenclause->expr, context);
3676 else /* CASE arg WHEN */
3677 {
3678 /* Ignore the CaseTestExpr and equality operator. */
3679 deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3680 context);
3681 }
3682
3683 /* THEN */
3684 appendStringInfoString(buf, " THEN ");
3685 deparseExpr(whenclause->result, context);
3686 }
3687
3688 /* add ELSE if present */
3689 if (node->defresult != NULL)
3690 {
3691 appendStringInfoString(buf, " ELSE ");
3692 deparseExpr(node->defresult, context);
3693 }
3694
3695 /* append END */
3696 appendStringInfoString(buf, " END)");
3697}
3698
3699/*
3700 * Deparse ARRAY[...] construct.
3701 */
3702static void
3704{
3705 StringInfo buf = context->buf;
3706 bool first = true;
3707 ListCell *lc;
3708
3709 appendStringInfoString(buf, "ARRAY[");
3710 foreach(lc, node->elements)
3711 {
3712 if (!first)
3714 deparseExpr(lfirst(lc), context);
3715 first = false;
3716 }
3718
3719 /* If the array is empty, we need an explicit cast to the array type. */
3720 if (node->elements == NIL)
3721 appendStringInfo(buf, "::%s",
3722 deparse_type_name(node->array_typeid, -1));
3723}
3724
3725/*
3726 * Deparse an Aggref node.
3727 */
3728static void
3730{
3731 StringInfo buf = context->buf;
3732 bool use_variadic;
3733
3734 /* Only basic, non-split aggregation accepted. */
3735 Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3736
3737 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3738 use_variadic = node->aggvariadic;
3739
3740 /* Find aggregate name from aggfnoid which is a pg_proc entry */
3741 appendFunctionName(node->aggfnoid, context);
3743
3744 /* Add DISTINCT */
3745 appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3746
3747 if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3748 {
3749 /* Add WITHIN GROUP (ORDER BY ..) */
3750 ListCell *arg;
3751 bool first = true;
3752
3753 Assert(!node->aggvariadic);
3754 Assert(node->aggorder != NIL);
3755
3756 foreach(arg, node->aggdirectargs)
3757 {
3758 if (!first)
3760 first = false;
3761
3762 deparseExpr((Expr *) lfirst(arg), context);
3763 }
3764
3765 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3766 appendAggOrderBy(node->aggorder, node->args, context);
3767 }
3768 else
3769 {
3770 /* aggstar can be set only in zero-argument aggregates */
3771 if (node->aggstar)
3773 else
3774 {
3775 ListCell *arg;
3776 bool first = true;
3777
3778 /* Add all the arguments */
3779 foreach(arg, node->args)
3780 {
3782 Node *n = (Node *) tle->expr;
3783
3784 if (tle->resjunk)
3785 continue;
3786
3787 if (!first)
3789 first = false;
3790
3791 /* Add VARIADIC */
3792 if (use_variadic && lnext(node->args, arg) == NULL)
3793 appendStringInfoString(buf, "VARIADIC ");
3794
3795 deparseExpr((Expr *) n, context);
3796 }
3797 }
3798
3799 /* Add ORDER BY */
3800 if (node->aggorder != NIL)
3801 {
3802 appendStringInfoString(buf, " ORDER BY ");
3803 appendAggOrderBy(node->aggorder, node->args, context);
3804 }
3805 }
3806
3807 /* Add FILTER (WHERE ..) */
3808 if (node->aggfilter != NULL)
3809 {
3810 appendStringInfoString(buf, ") FILTER (WHERE ");
3811 deparseExpr((Expr *) node->aggfilter, context);
3812 }
3813
3815}
3816
3817/*
3818 * Append ORDER BY within aggregate function.
3819 */
3820static void
3822{
3823 StringInfo buf = context->buf;
3824 ListCell *lc;
3825 bool first = true;
3826
3827 foreach(lc, orderList)
3828 {
3830 Node *sortexpr;
3831
3832 if (!first)
3834 first = false;
3835
3836 /* Deparse the sort expression proper. */
3837 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3838 false, context);
3839 /* Add decoration as needed. */
3840 appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3841 context);
3842 }
3843}
3844
3845/*
3846 * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
3847 * of an ORDER BY clause.
3848 */
3849static void
3850appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first,
3851 deparse_expr_cxt *context)
3852{
3853 StringInfo buf = context->buf;
3854 TypeCacheEntry *typentry;
3855
3856 /* See whether operator is default < or > for sort expr's datatype. */
3857 typentry = lookup_type_cache(sortcoltype,
3859
3860 if (sortop == typentry->lt_opr)
3861 appendStringInfoString(buf, " ASC");
3862 else if (sortop == typentry->gt_opr)
3863 appendStringInfoString(buf, " DESC");
3864 else
3865 {
3868
3869 appendStringInfoString(buf, " USING ");
3870
3871 /* Append operator name. */
3874 elog(ERROR, "cache lookup failed for operator %u", sortop);
3878 }
3879
3880 if (nulls_first)
3881 appendStringInfoString(buf, " NULLS FIRST");
3882 else
3883 appendStringInfoString(buf, " NULLS LAST");
3884}
3885
3886/*
3887 * Print the representation of a parameter to be sent to the remote side.
3888 *
3889 * Note: we always label the Param's type explicitly rather than relying on
3890 * transmitting a numeric type OID in PQsendQueryParams(). This allows us to
3891 * avoid assuming that types have the same OIDs on the remote side as they
3892 * do locally --- they need only have the same names.
3893 */
3894static void
3895printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
3896 deparse_expr_cxt *context)
3897{
3898 StringInfo buf = context->buf;
3899 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3900
3902}
3903
3904/*
3905 * Print the representation of a placeholder for a parameter that will be
3906 * sent to the remote side at execution time.
3907 *
3908 * This is used when we're just trying to EXPLAIN the remote query.
3909 * We don't have the actual value of the runtime parameter yet, and we don't
3910 * want the remote planner to generate a plan that depends on such a value
3911 * anyway. Thus, we can't do something simple like "$1::paramtype".
3912 * Instead, we emit "((SELECT null::paramtype)::paramtype)".
3913 * In all extant versions of Postgres, the planner will see that as an unknown
3914 * constant value, which is what we want. This might need adjustment if we
3915 * ever make the planner flatten scalar subqueries. Note: the reason for the
3916 * apparently useless outer cast is to ensure that the representation as a
3917 * whole will be parsed as an a_expr and not a select_with_parens; the latter
3918 * would do the wrong thing in the context "x = ANY(...)".
3919 */
3920static void
3921printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
3922 deparse_expr_cxt *context)
3923{
3924 StringInfo buf = context->buf;
3925 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3926
3927 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3928}
3929
3930/*
3931 * Deparse GROUP BY clause.
3932 */
3933static void
3935{
3936 StringInfo buf = context->buf;
3937 Query *query = context->root->parse;
3938 ListCell *lc;
3939 bool first = true;
3940
3941 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3942 if (!query->groupClause)
3943 return;
3944
3945 appendStringInfoString(buf, " GROUP BY ");
3946
3947 /*
3948 * Queries with grouping sets are not pushed down, so we don't expect
3949 * grouping sets here.
3950 */
3951 Assert(!query->groupingSets);
3952
3953 /*
3954 * We intentionally print query->groupClause not processed_groupClause,
3955 * leaving it to the remote planner to get rid of any redundant GROUP BY
3956 * items again. This is necessary in case processed_groupClause reduced
3957 * to empty, and in any case the redundancy situation on the remote might
3958 * be different than what we think here.
3959 */
3960 foreach(lc, query->groupClause)
3961 {
3963
3964 if (!first)
3966 first = false;
3967
3968 deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3969 }
3970}
3971
3972/*
3973 * Deparse ORDER BY clause defined by the given pathkeys.
3974 *
3975 * The clause should use Vars from context->scanrel if !has_final_sort,
3976 * or from context->foreignrel's targetlist if has_final_sort.
3977 *
3978 * We find a suitable pathkey expression (some earlier step
3979 * should have verified that there is one) and deparse it.
3980 */
3981static void
3982appendOrderByClause(List *pathkeys, bool has_final_sort,
3983 deparse_expr_cxt *context)
3984{
3985 ListCell *lcell;
3986 int nestlevel;
3987 StringInfo buf = context->buf;
3988 bool gotone = false;
3989
3990 /* Make sure any constants in the exprs are printed portably */
3992
3993 foreach(lcell, pathkeys)
3994 {
3997 Expr *em_expr;
3998 Oid oprid;
3999
4000 if (has_final_sort)
4001 {
4002 /*
4003 * By construction, context->foreignrel is the input relation to
4004 * the final sort.
4005 */
4006 em = find_em_for_rel_target(context->root,
4007 pathkey->pk_eclass,
4008 context->foreignrel);
4009 }
4010 else
4011 em = find_em_for_rel(context->root,
4012 pathkey->pk_eclass,
4013 context->scanrel);
4014
4015 /*
4016 * We don't expect any error here; it would mean that shippability
4017 * wasn't verified earlier. For the same reason, we don't recheck
4018 * shippability of the sort operator.
4019 */
4020 if (em == NULL)
4021 elog(ERROR, "could not find pathkey item to sort");
4022
4023 em_expr = em->em_expr;
4024
4025 /*
4026 * If the member is a Const expression then we needn't add it to the
4027 * ORDER BY clause. This can happen in UNION ALL queries where the
4028 * union child targetlist has a Const. Adding these would be
4029 * wasteful, but also, for INT columns, an integer literal would be
4030 * seen as an ordinal column position rather than a value to sort by.
4031 * deparseConst() does have code to handle this, but it seems less
4032 * effort on all accounts just to skip these for ORDER BY clauses.
4033 */
4034 if (IsA(em_expr, Const))
4035 continue;
4036
4037 if (!gotone)
4038 {
4039 appendStringInfoString(buf, " ORDER BY ");
4040 gotone = true;
4041 }
4042 else
4044
4045 /*
4046 * Lookup the operator corresponding to the compare type in the
4047 * opclass. The datatype used by the opfamily is not necessarily the
4048 * same as the expression type (for array types for example).
4049 */
4051 em->em_datatype,
4052 em->em_datatype,
4053 pathkey->pk_cmptype);
4054 if (!OidIsValid(oprid))
4055 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
4056 pathkey->pk_cmptype, em->em_datatype, em->em_datatype,
4057 pathkey->pk_opfamily);
4058
4059 deparseExpr(em_expr, context);
4060
4061 /*
4062 * Here we need to use the expression's actual type to discover
4063 * whether the desired operator will be the default or not.
4064 */
4065 appendOrderBySuffix(oprid, exprType((Node *) em_expr),
4066 pathkey->pk_nulls_first, context);
4067
4068 }
4070}
4071
4072/*
4073 * Deparse LIMIT/OFFSET clause.
4074 */
4075static void
4077{
4078 PlannerInfo *root = context->root;
4079 StringInfo buf = context->buf;
4080 int nestlevel;
4081
4082 /* Make sure any constants in the exprs are printed portably */
4084
4085 if (root->parse->limitCount)
4086 {
4087 appendStringInfoString(buf, " LIMIT ");
4088 deparseExpr((Expr *) root->parse->limitCount, context);
4089 }
4090 if (root->parse->limitOffset)
4091 {
4092 appendStringInfoString(buf, " OFFSET ");
4093 deparseExpr((Expr *) root->parse->limitOffset, context);
4094 }
4095
4097}
4098
4099/*
4100 * appendFunctionName
4101 * Deparses function name from given function oid.
4102 */
4103static void
4105{
4106 StringInfo buf = context->buf;
4109 const char *proname;
4110
4113 elog(ERROR, "cache lookup failed for function %u", funcid);
4115
4116 /* Print schema name only if it's not pg_catalog */
4117 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
4118 {
4119 const char *schemaname;
4120
4121 schemaname = get_namespace_name(procform->pronamespace);
4122 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
4123 }
4124
4125 /* Always print the function name */
4126 proname = NameStr(procform->proname);
4128
4130}
4131
4132/*
4133 * Appends a sort or group clause.
4134 *
4135 * Like get_rule_sortgroupclause(), returns the expression tree, so caller
4136 * need not find it again.
4137 */
4138static Node *
4140 deparse_expr_cxt *context)
4141{
4142 StringInfo buf = context->buf;
4144 Expr *expr;
4145
4146 tle = get_sortgroupref_tle(ref, tlist);
4147 expr = tle->expr;
4148
4149 if (force_colno)
4150 {
4151 /* Use column-number form when requested by caller. */
4152 Assert(!tle->resjunk);
4153 appendStringInfo(buf, "%d", tle->resno);
4154 }
4155 else if (expr && IsA(expr, Const))
4156 {
4157 /*
4158 * Force a typecast here so that we don't emit something like "GROUP
4159 * BY 2", which will be misconstrued as a column position rather than
4160 * a constant.
4161 */
4162 deparseConst((Const *) expr, context, 1);
4163 }
4164 else if (!expr || IsA(expr, Var))
4165 deparseExpr(expr, context);
4166 else
4167 {
4168 /* Always parenthesize the expression. */
4170 deparseExpr(expr, context);
4172 }
4173
4174 return (Node *) expr;
4175}
4176
4177
4178/*
4179 * Returns true if given Var is deparsed as a subquery output column, in
4180 * which case, *relno and *colno are set to the IDs for the relation and
4181 * column alias to the Var provided by the subquery.
4182 */
4183static bool
4184is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
4185{
4186 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4187 RelOptInfo *outerrel = fpinfo->outerrel;
4188 RelOptInfo *innerrel = fpinfo->innerrel;
4189
4190 /* Should only be called in these cases. */
4191 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
4192
4193 /*
4194 * If the given relation isn't a join relation, it doesn't have any lower
4195 * subqueries, so the Var isn't a subquery output column.
4196 */
4197 if (!IS_JOIN_REL(foreignrel))
4198 return false;
4199
4200 /*
4201 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
4202 * output column.
4203 */
4204 if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
4205 return false;
4206
4207 if (bms_is_member(node->varno, outerrel->relids))
4208 {
4209 /*
4210 * If outer relation is deparsed as a subquery, the Var is an output
4211 * column of the subquery; get the IDs for the relation/column alias.
4212 */
4213 if (fpinfo->make_outerrel_subquery)
4214 {
4215 get_relation_column_alias_ids(node, outerrel, relno, colno);
4216 return true;
4217 }
4218
4219 /* Otherwise, recurse into the outer relation. */
4220 return is_subquery_var(node, outerrel, relno, colno);
4221 }
4222 else
4223 {
4224 Assert(bms_is_member(node->varno, innerrel->relids));
4225
4226 /*
4227 * If inner relation is deparsed as a subquery, the Var is an output
4228 * column of the subquery; get the IDs for the relation/column alias.
4229 */
4230 if (fpinfo->make_innerrel_subquery)
4231 {
4232 get_relation_column_alias_ids(node, innerrel, relno, colno);
4233 return true;
4234 }
4235
4236 /* Otherwise, recurse into the inner relation. */
4237 return is_subquery_var(node, innerrel, relno, colno);
4238 }
4239}
4240
4241/*
4242 * Get the IDs for the relation and column alias to given Var belonging to
4243 * given relation, which are returned into *relno and *colno.
4244 */
4245static void
4247 int *relno, int *colno)
4248{
4249 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4250 int i;
4251 ListCell *lc;
4252
4253 /* Get the relation alias ID */
4254 *relno = fpinfo->relation_index;
4255
4256 /* Get the column alias ID */
4257 i = 1;
4258 foreach(lc, foreignrel->reltarget->exprs)
4259 {
4260 Var *tlvar = (Var *) lfirst(lc);
4261
4262 /*
4263 * Match reltarget entries only on varno/varattno. Ideally there
4264 * would be some cross-check on varnullingrels, but it's unclear what
4265 * to do exactly; we don't have enough context to know what that value
4266 * should be.
4267 */
4268 if (IsA(tlvar, Var) &&
4269 tlvar->varno == node->varno &&
4270 tlvar->varattno == node->varattno)
4271 {
4272 *colno = i;
4273 return;
4274 }
4275 i++;
4276 }
4277
4278 /* Shouldn't get here */
4279 elog(ERROR, "unexpected expression in subquery output");
4280}
int16 AttrNumber
Definition attnum.h:21
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:217
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
void bms_free(Bitmapset *a)
Definition bitmapset.c:240
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:900
@ BMS_MULTIPLE
Definition bitmapset.h:73
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition builtins.h:125
#define FORMAT_TYPE_FORCE_QUALIFY
Definition builtins.h:127
#define NameStr(name)
Definition c.h:894
#define Assert(condition)
Definition c.h:1002
#define ESCAPE_STRING_SYNTAX
Definition c.h:1295
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1292
int32_t int32
Definition c.h:679
uint16_t uint16
Definition c.h:682
unsigned int Index
Definition c.h:757
#define OidIsValid(objectId)
Definition c.h:917
bool contain_mutable_functions(Node *clause)
Definition clauses.c:399
char * defGetString(DefElem *def)
Definition define.c:34
static void deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3564
static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
Definition deparse.c:2059
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3653
void deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
Definition deparse.c:2550
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3582
static void appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Definition deparse.c:3934
static void deparseTargetList(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool is_returning, Bitmapset *attrs_used, bool qualify_col, List **retrieved_attrs)
Definition deparse.c:1458
#define SUBQUERY_REL_ALIAS_PREFIX
Definition deparse.c:113
static void deparseFromExpr(List *quals, deparse_expr_cxt *context)
Definition deparse.c:1426
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition deparse.c:4139
static void deparseLockingClause(deparse_expr_cxt *context)
Definition deparse.c:1532
const char * get_jointype_name(JoinType jointype)
Definition deparse.c:1692
void deparseAnalyzeInfoSql(StringInfo buf, Relation rel)
Definition deparse.c:2572
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition deparse.c:3729
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition deparse.c:3850
void deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, RelOptInfo *foreignrel, List *remote_conds, List **params_list, List *returningList, List **retrieved_attrs)
Definition deparse.c:2442
#define REL_ALIAS_PREFIX
Definition deparse.c:109
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)
Definition deparse.c:2327
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition deparse.c:4246
FDWCollateState
Definition deparse.c:80
@ FDW_COLLATE_SAFE
Definition deparse.c:84
@ FDW_COLLATE_UNSAFE
Definition deparse.c:85
@ FDW_COLLATE_NONE
Definition deparse.c:81
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition deparse.c:3895
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition deparse.c:4184
bool is_foreign_param(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition deparse.c:1135
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition deparse.c:3921
static void appendOrderByClause(List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
Definition deparse.c:3982
static bool foreign_expr_walker(Node *node, foreign_glob_cxt *glob_cxt, foreign_loc_cxt *outer_cxt, foreign_loc_cxt *case_arg_cxt)
Definition deparse.c:312
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition deparse.c:2732
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition deparse.c:3551
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition deparse.c:3620
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition deparse.c:3460
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3330
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition deparse.c:3074
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition deparse.c:3425
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3488
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)
Definition deparse.c:1286
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3267
void deparseStringLiteral(StringInfo buf, const char *val)
Definition deparse.c:2900
void rebuildInsertSql(StringInfo buf, Relation rel, char *orig_query, List *target_attrs, int values_end_len, int num_params, int num_rows)
Definition deparse.c:2207
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3703
void deparseInsertSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing, List *withCheckOptionList, List *returningList, List **retrieved_attrs, int *values_end_len)
Definition deparse.c:2134
static void deparseReturningList(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool trig_after_row, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
Definition deparse.c:2493
void deparseUpdateSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
Definition deparse.c:2267
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition deparse.c:3003
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition deparse.c:4104
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition deparse.c:1622
void deparseDeleteSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *returningList, List **retrieved_attrs)
Definition deparse.c:2413
void deparseAnalyzeSql(StringInfo buf, Relation rel, PgFdwSamplingMethod sample_method, double sample_frac, List **retrieved_attrs)
Definition deparse.c:2612
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition deparse.c:3221
static void deparseRelation(StringInfo buf, Relation rel)
Definition deparse.c:2860
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition deparse.c:1732
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition deparse.c:1210
#define ADD_REL_QUALIFIER(buf, varno)
Definition deparse.c:111
static void appendLimitClause(deparse_expr_cxt *context)
Definition deparse.c:4076
static void deparseExpr(Expr *node, deparse_expr_cxt *context)
Definition deparse.c:2935
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition deparse.c:244
static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
Definition deparse.c:1812
#define SUBQUERY_COL_ALIAS_PREFIX
Definition deparse.c:114
void classifyConditions(PlannerInfo *root, RelOptInfo *baserel, List *input_conds, List **remote_conds, List **local_conds)
Definition deparse.c:218
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3506
static void appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
Definition deparse.c:1659
void deparseTruncateSql(StringInfo buf, List *rels, DropBehavior behavior, bool restart_seqs)
Definition deparse.c:2697
static void deparseSubqueryTargetList(deparse_expr_cxt *context)
Definition deparse.c:1768
bool is_foreign_pathkey(PlannerInfo *root, RelOptInfo *baserel, PathKey *pathkey)
Definition deparse.c:1176
static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
Definition deparse.c:1368
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition deparse.c:3188
List * build_tlist_to_deparse(RelOptInfo *foreignrel)
Definition deparse.c:1229
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition deparse.c:3821
Datum arg
Definition elog.c:1323
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
ForeignTable * GetForeignTable(Oid relid)
Definition foreign.c:286
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition foreign.c:324
char * format_type_extended(Oid type_oid, int32 typemod, uint16 flags)
const char * str
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
long val
Definition informix.c:689
int b
Definition isn.c:74
int a
Definition isn.c:73
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_concat(List *list1, const List *list2)
Definition list.c:561
List * lappend_int(List *list, int datum)
Definition list.c:357
void list_free(List *list)
Definition list.c:1546
void list_free_deep(List *list)
Definition list.c:1560
#define NoLock
Definition lockdefs.h:34
@ LCS_FORUPDATE
Definition lockoptions.h:28
@ LCS_NONE
Definition lockoptions.h:23
@ LCS_FORSHARE
Definition lockoptions.h:26
@ LCS_FORKEYSHARE
Definition lockoptions.h:25
@ LCS_FORNOKEYUPDATE
Definition lockoptions.h:27
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2971
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:199
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3223
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1053
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
void pfree(void *pointer)
Definition mcxt.c:1619
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition nodeFuncs.c:562
Node * strip_implicit_coercions(Node *node)
Definition nodeFuncs.c:710
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define nodeTag(nodeptr)
Definition nodes.h:137
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
@ AGGSPLIT_SIMPLE
Definition nodes.h:385
#define castNode(_type_, nodeptr)
Definition nodes.h:180
JoinType
Definition nodes.h:296
@ JOIN_SEMI
Definition nodes.h:315
@ JOIN_FULL
Definition nodes.h:303
@ JOIN_INNER
Definition nodes.h:301
@ JOIN_RIGHT
Definition nodes.h:304
@ JOIN_LEFT
Definition nodes.h:302
#define PVC_RECURSE_PLACEHOLDERS
Definition optimizer.h:202
Oid oprid(Operator op)
Definition parse_oper.c:241
DropBehavior
@ DROP_CASCADE
@ DROP_RESTRICT
#define IS_SIMPLE_REL(rel)
Definition pathnodes.h:989
#define IS_JOIN_REL(rel)
Definition pathnodes.h:994
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:704
@ RELOPT_JOINREL
Definition pathnodes.h:978
#define IS_UPPER_REL(rel)
Definition pathnodes.h:999
NameData attname
int16 attnum
NameData relname
Definition pg_class.h:40
#define lfirst(lc)
Definition pg_list.h:172
#define llast(l)
Definition pg_list.h:198
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
#define lfirst_int(lc)
Definition pg_list.h:173
#define linitial(l)
Definition pg_list.h:178
#define lsecond(l)
Definition pg_list.h:183
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:375
static const struct lconv_member_info table[]
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
NameData proname
Definition pg_proc.h:37
static char buf[DEFAULT_XLOG_SEG_SIZE]
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define InvalidOid
unsigned int Oid
void reset_transmission_modes(int nestlevel)
int set_transmission_modes(void)
EquivalenceMember * find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
EquivalenceMember * find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
bool is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition shippable.c:163
bool is_builtin(Oid objectId)
Definition shippable.c:153
PgFdwSamplingMethod
@ ANALYZE_SAMPLE_AUTO
@ ANALYZE_SAMPLE_OFF
@ ANALYZE_SAMPLE_BERNOULLI
@ ANALYZE_SAMPLE_SYSTEM
@ ANALYZE_SAMPLE_RANDOM
char * c
e
static int fb(int x)
static int fe(enum e x)
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition preptlist.c:528
@ AND_EXPR
Definition primnodes.h:945
@ OR_EXPR
Definition primnodes.h:945
@ NOT_EXPR
Definition primnodes.h:945
@ PARAM_MULTIEXPR
Definition primnodes.h:388
#define IS_SPECIAL_VARNO(varno)
Definition primnodes.h:248
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:759
@ COERCE_EXPLICIT_CAST
Definition primnodes.h:758
@ IS_NULL
Definition primnodes.h:1975
tree ctl root
Definition radixtree.h:1857
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
const char * quote_identifier(const char *ident)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Oid aggfnoid
Definition primnodes.h:461
List * aggdistinct
Definition primnodes.h:491
List * aggdirectargs
Definition primnodes.h:482
List * args
Definition primnodes.h:485
Expr * aggfilter
Definition primnodes.h:494
List * aggorder
Definition primnodes.h:488
BoolExprType boolop
Definition primnodes.h:953
List * args
Definition primnodes.h:954
Expr * arg
Definition primnodes.h:1329
Expr * defresult
Definition primnodes.h:1331
List * args
Definition primnodes.h:1330
Expr * result
Definition primnodes.h:1342
Expr * expr
Definition primnodes.h:1341
bool attgenerated
Definition tupdesc.h:79
Oid consttype
Definition primnodes.h:333
char * defname
Definition parsenodes.h:862
Oid funcid
Definition primnodes.h:770
List * args
Definition primnodes.h:788
Definition pg_list.h:54
Definition nodes.h:133
NullTestType nulltesttype
Definition primnodes.h:1982
Expr * arg
Definition primnodes.h:1981
Oid opno
Definition primnodes.h:835
List * args
Definition primnodes.h:853
int32 paramtypmod
Definition primnodes.h:400
Oid paramtype
Definition primnodes.h:398
ParamKind paramkind
Definition primnodes.h:396
Oid paramcollid
Definition primnodes.h:402
List * exprs
Definition pathnodes.h:1878
RelOptInfo * outerrel
LockClauseStrength strength
Definition plannodes.h:1623
Query * parse
Definition pathnodes.h:309
List * groupClause
Definition parsenodes.h:221
List * groupingSets
Definition parsenodes.h:224
Relids relids
Definition pathnodes.h:1021
struct PathTarget * reltarget
Definition pathnodes.h:1045
Index relid
Definition pathnodes.h:1069
RelOptKind reloptkind
Definition pathnodes.h:1015
TriggerDesc * trigdesc
Definition rel.h:117
Expr * clause
Definition pathnodes.h:2901
List * refupperindexpr
Definition primnodes.h:716
List * reflowerindexpr
Definition primnodes.h:722
bool trig_update_after_row
Definition reltrigger.h:62
bool trig_insert_after_row
Definition reltrigger.h:57
bool trig_delete_after_row
Definition reltrigger.h:67
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
Index varlevelsup
Definition primnodes.h:295
PlannerInfo * root
Definition deparse.c:100
List ** params_list
Definition deparse.c:106
RelOptInfo * foreignrel
Definition deparse.c:101
StringInfo buf
Definition deparse.c:105
RelOptInfo * scanrel
Definition deparse.c:102
RelOptInfo * foreignrel
Definition deparse.c:70
Relids relids
Definition deparse.c:71
PlannerInfo * root
Definition deparse.c:69
FDWCollateState state
Definition deparse.c:92
char data[NAMEDATALEN]
Definition c.h:890
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
#define TableOidAttributeNumber
Definition sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition sysattr.h:21
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition tlist.c:354
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition tlist.c:141
#define FirstNormalObjectId
Definition transam.h:197
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:195
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_GT_OPR
Definition typcache.h:140
#define TYPECACHE_LT_OPR
Definition typcache.h:139
List * pull_var_clause(Node *node, int flags)
Definition var.c:653
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition var.c:296