1 /*-------------------------------------------------------------------------
4 * Query deparser for postgres_fdw
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.
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.
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.
27 * Portions Copyright (c) 2012-2025, PostgreSQL Global Development Group
30 * contrib/postgres_fdw/deparse.c
32 *-------------------------------------------------------------------------
36 #include "access/htup_details.h"
37 #include "access/sysattr.h"
38 #include "access/table.h"
39 #include "catalog/pg_aggregate.h"
40 #include "catalog/pg_authid.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_namespace.h"
43 #include "catalog/pg_operator.h"
44 #include "catalog/pg_opfamily.h"
45 #include "catalog/pg_proc.h"
46 #include "catalog/pg_ts_config.h"
47 #include "catalog/pg_ts_dict.h"
48 #include "catalog/pg_type.h"
49 #include "commands/defrem.h"
50 #include "nodes/nodeFuncs.h"
51 #include "nodes/plannodes.h"
52 #include "optimizer/optimizer.h"
53 #include "optimizer/prep.h"
54 #include "optimizer/tlist.h"
55 #include "parser/parsetree.h"
56 #include "postgres_fdw.h"
57 #include "utils/builtins.h"
58 #include "utils/lsyscache.h"
59 #include "utils/rel.h"
60 #include "utils/syscache.h"
61 #include "utils/typcache.h"
64 * Global context for foreign_expr_walker's search of an expression tree.
66 typedef struct foreign_glob_cxt
68 PlannerInfo
*root
; /* global planner state */
69 RelOptInfo
*foreignrel
; /* the foreign relation we are planning for */
70 Relids relids
; /* relids of base relations in the underlying
75 * Local (per-tree-level) context for foreign_expr_walker's search.
76 * This is concerned with identifying collations used in the expression.
80 FDW_COLLATE_NONE
, /* expression is of a noncollatable type, or
81 * it has default collation that is not
82 * traceable to a foreign Var */
83 FDW_COLLATE_SAFE
, /* collation derives from a foreign Var */
84 FDW_COLLATE_UNSAFE
, /* collation is non-default and derives from
85 * something other than a foreign Var */
88 typedef struct foreign_loc_cxt
90 Oid collation
; /* OID of current collation, if any */
91 FDWCollateState state
; /* state of current collation choice */
95 * Context for deparseExpr
97 typedef struct deparse_expr_cxt
99 PlannerInfo
*root
; /* global planner state */
100 RelOptInfo
*foreignrel
; /* the foreign relation we are planning for */
101 RelOptInfo
*scanrel
; /* the underlying scan relation. Same as
102 * foreignrel, when that represents a join or
103 * a base relation. */
104 StringInfo buf
; /* output buffer to append to */
105 List
**params_list
; /* exprs that will become remote Params */
108 #define REL_ALIAS_PREFIX "r"
109 /* Handy macro to add relation name qualification */
110 #define ADD_REL_QUALIFIER(buf, varno) \
111 appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
112 #define SUBQUERY_REL_ALIAS_PREFIX "s"
113 #define SUBQUERY_COL_ALIAS_PREFIX "c"
116 * Functions to determine whether an expression can be evaluated safely on
119 static bool foreign_expr_walker(Node
*node
,
120 foreign_glob_cxt
*glob_cxt
,
121 foreign_loc_cxt
*outer_cxt
,
122 foreign_loc_cxt
*case_arg_cxt
);
123 static char *deparse_type_name(Oid type_oid
, int32 typemod
);
126 * Functions to construct string representation of a node tree.
128 static void deparseTargetList(StringInfo buf
,
133 Bitmapset
*attrs_used
,
135 List
**retrieved_attrs
);
136 static void deparseExplicitTargetList(List
*tlist
,
138 List
**retrieved_attrs
,
139 deparse_expr_cxt
*context
);
140 static void deparseSubqueryTargetList(deparse_expr_cxt
*context
);
141 static void deparseReturningList(StringInfo buf
, RangeTblEntry
*rte
,
142 Index rtindex
, Relation rel
,
144 List
*withCheckOptionList
,
146 List
**retrieved_attrs
);
147 static void deparseColumnRef(StringInfo buf
, int varno
, int varattno
,
148 RangeTblEntry
*rte
, bool qualify_col
);
149 static void deparseRelation(StringInfo buf
, Relation rel
);
150 static void deparseExpr(Expr
*node
, deparse_expr_cxt
*context
);
151 static void deparseVar(Var
*node
, deparse_expr_cxt
*context
);
152 static void deparseConst(Const
*node
, deparse_expr_cxt
*context
, int showtype
);
153 static void deparseParam(Param
*node
, deparse_expr_cxt
*context
);
154 static void deparseSubscriptingRef(SubscriptingRef
*node
, deparse_expr_cxt
*context
);
155 static void deparseFuncExpr(FuncExpr
*node
, deparse_expr_cxt
*context
);
156 static void deparseOpExpr(OpExpr
*node
, deparse_expr_cxt
*context
);
157 static bool isPlainForeignVar(Expr
*node
, deparse_expr_cxt
*context
);
158 static void deparseOperatorName(StringInfo buf
, Form_pg_operator opform
);
159 static void deparseDistinctExpr(DistinctExpr
*node
, deparse_expr_cxt
*context
);
160 static void deparseScalarArrayOpExpr(ScalarArrayOpExpr
*node
,
161 deparse_expr_cxt
*context
);
162 static void deparseRelabelType(RelabelType
*node
, deparse_expr_cxt
*context
);
163 static void deparseBoolExpr(BoolExpr
*node
, deparse_expr_cxt
*context
);
164 static void deparseNullTest(NullTest
*node
, deparse_expr_cxt
*context
);
165 static void deparseCaseExpr(CaseExpr
*node
, deparse_expr_cxt
*context
);
166 static void deparseArrayExpr(ArrayExpr
*node
, deparse_expr_cxt
*context
);
167 static void printRemoteParam(int paramindex
, Oid paramtype
, int32 paramtypmod
,
168 deparse_expr_cxt
*context
);
169 static void printRemotePlaceholder(Oid paramtype
, int32 paramtypmod
,
170 deparse_expr_cxt
*context
);
171 static void deparseSelectSql(List
*tlist
, bool is_subquery
, List
**retrieved_attrs
,
172 deparse_expr_cxt
*context
);
173 static void deparseLockingClause(deparse_expr_cxt
*context
);
174 static void appendOrderByClause(List
*pathkeys
, bool has_final_sort
,
175 deparse_expr_cxt
*context
);
176 static void appendLimitClause(deparse_expr_cxt
*context
);
177 static void appendConditions(List
*exprs
, deparse_expr_cxt
*context
);
178 static void deparseFromExprForRel(StringInfo buf
, PlannerInfo
*root
,
179 RelOptInfo
*foreignrel
, bool use_alias
,
180 Index ignore_rel
, List
**ignore_conds
,
181 List
**additional_conds
,
183 static void appendWhereClause(List
*exprs
, List
*additional_conds
,
184 deparse_expr_cxt
*context
);
185 static void deparseFromExpr(List
*quals
, deparse_expr_cxt
*context
);
186 static void deparseRangeTblRef(StringInfo buf
, PlannerInfo
*root
,
187 RelOptInfo
*foreignrel
, bool make_subquery
,
188 Index ignore_rel
, List
**ignore_conds
,
189 List
**additional_conds
, List
**params_list
);
190 static void deparseAggref(Aggref
*node
, deparse_expr_cxt
*context
);
191 static void appendGroupByClause(List
*tlist
, deparse_expr_cxt
*context
);
192 static void appendOrderBySuffix(Oid sortop
, Oid sortcoltype
, bool nulls_first
,
193 deparse_expr_cxt
*context
);
194 static void appendAggOrderBy(List
*orderList
, List
*targetList
,
195 deparse_expr_cxt
*context
);
196 static void appendFunctionName(Oid funcid
, deparse_expr_cxt
*context
);
197 static Node
*deparseSortGroupClause(Index ref
, List
*tlist
, bool force_colno
,
198 deparse_expr_cxt
*context
);
203 static bool is_subquery_var(Var
*node
, RelOptInfo
*foreignrel
,
204 int *relno
, int *colno
);
205 static void get_relation_column_alias_ids(Var
*node
, RelOptInfo
*foreignrel
,
206 int *relno
, int *colno
);
210 * Examine each qual clause in input_conds, and classify them into two groups,
211 * which are returned as two lists:
212 * - remote_conds contains expressions that can be evaluated remotely
213 * - local_conds contains expressions that can't be evaluated remotely
216 classifyConditions(PlannerInfo
*root
,
227 foreach(lc
, input_conds
)
229 RestrictInfo
*ri
= lfirst_node(RestrictInfo
, lc
);
231 if (is_foreign_expr(root
, baserel
, ri
->clause
))
232 *remote_conds
= lappend(*remote_conds
, ri
);
234 *local_conds
= lappend(*local_conds
, ri
);
239 * Returns true if given expr is safe to evaluate on the foreign server.
242 is_foreign_expr(PlannerInfo
*root
,
246 foreign_glob_cxt glob_cxt
;
247 foreign_loc_cxt loc_cxt
;
248 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) (baserel
->fdw_private
);
251 * Check that the expression consists of nodes that are safe to execute
254 glob_cxt
.root
= root
;
255 glob_cxt
.foreignrel
= baserel
;
258 * For an upper relation, use relids from its underneath scan relation,
259 * because the upperrel's own relids currently aren't set to anything
260 * meaningful by the core code. For other relation, use their own relids.
262 if (IS_UPPER_REL(baserel
))
263 glob_cxt
.relids
= fpinfo
->outerrel
->relids
;
265 glob_cxt
.relids
= baserel
->relids
;
266 loc_cxt
.collation
= InvalidOid
;
267 loc_cxt
.state
= FDW_COLLATE_NONE
;
268 if (!foreign_expr_walker((Node
*) expr
, &glob_cxt
, &loc_cxt
, NULL
))
272 * If the expression has a valid collation that does not arise from a
273 * foreign var, the expression can not be sent over.
275 if (loc_cxt
.state
== FDW_COLLATE_UNSAFE
)
279 * An expression which includes any mutable functions can't be sent over
280 * because its result is not stable. For example, sending now() remote
281 * side could cause confusion from clock offsets. Future versions might
282 * be able to make this choice with more granularity. (We check this last
283 * because it requires a lot of expensive catalog lookups.)
285 if (contain_mutable_functions((Node
*) expr
))
288 /* OK to evaluate on the remote server */
293 * Check if expression is safe to execute remotely, and return true if so.
295 * In addition, *outer_cxt is updated with collation information.
297 * case_arg_cxt is NULL if this subexpression is not inside a CASE-with-arg.
298 * Otherwise, it points to the collation info derived from the arg expression,
299 * which must be consulted by any CaseTestExpr.
301 * We must check that the expression contains only node types we can deparse,
302 * that all types/functions/operators are safe to send (they are "shippable"),
303 * and that all collations used in the expression derive from Vars of the
304 * foreign table. Because of the latter, the logic is pretty close to
305 * assign_collations_walker() in parse_collate.c, though we can assume here
306 * that the given expression is valid. Note function mutability is not
307 * currently considered here.
310 foreign_expr_walker(Node
*node
,
311 foreign_glob_cxt
*glob_cxt
,
312 foreign_loc_cxt
*outer_cxt
,
313 foreign_loc_cxt
*case_arg_cxt
)
315 bool check_type
= true;
316 PgFdwRelationInfo
*fpinfo
;
317 foreign_loc_cxt inner_cxt
;
319 FDWCollateState state
;
321 /* Need do nothing for empty subexpressions */
325 /* May need server info from baserel's fdw_private struct */
326 fpinfo
= (PgFdwRelationInfo
*) (glob_cxt
->foreignrel
->fdw_private
);
328 /* Set up inner_cxt for possible recursion to child nodes */
329 inner_cxt
.collation
= InvalidOid
;
330 inner_cxt
.state
= FDW_COLLATE_NONE
;
332 switch (nodeTag(node
))
336 Var
*var
= (Var
*) node
;
339 * If the Var is from the foreign table, we consider its
340 * collation (if any) safe to use. If it is from another
341 * table, we treat its collation the same way as we would a
342 * Param's collation, ie it's not safe for it to have a
343 * non-default collation.
345 if (bms_is_member(var
->varno
, glob_cxt
->relids
) &&
346 var
->varlevelsup
== 0)
348 /* Var belongs to foreign table */
351 * System columns other than ctid should not be sent to
352 * the remote, since we don't make any effort to ensure
353 * that local and remote values match (tableoid, in
354 * particular, almost certainly doesn't match).
356 if (var
->varattno
< 0 &&
357 var
->varattno
!= SelfItemPointerAttributeNumber
)
360 /* Else check the collation */
361 collation
= var
->varcollid
;
362 state
= OidIsValid(collation
) ? FDW_COLLATE_SAFE
: FDW_COLLATE_NONE
;
366 /* Var belongs to some other table */
367 collation
= var
->varcollid
;
368 if (collation
== InvalidOid
||
369 collation
== DEFAULT_COLLATION_OID
)
372 * It's noncollatable, or it's safe to combine with a
373 * collatable foreign Var, so set state to NONE.
375 state
= FDW_COLLATE_NONE
;
380 * Do not fail right away, since the Var might appear
381 * in a collation-insensitive context.
383 state
= FDW_COLLATE_UNSAFE
;
390 Const
*c
= (Const
*) node
;
393 * Constants of regproc and related types can't be shipped
394 * unless the referenced object is shippable. But NULL's ok.
395 * (See also the related code in dependency.c.)
399 switch (c
->consttype
)
402 case REGPROCEDUREOID
:
403 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
404 ProcedureRelationId
, fpinfo
))
409 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
410 OperatorRelationId
, fpinfo
))
414 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
415 RelationRelationId
, fpinfo
))
419 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
420 TypeRelationId
, fpinfo
))
423 case REGCOLLATIONOID
:
424 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
425 CollationRelationId
, fpinfo
))
431 * For text search objects only, we weaken the
432 * normal shippability criterion to allow all OIDs
433 * below FirstNormalObjectId. Without this, none
434 * of the initdb-installed TS configurations would
435 * be shippable, which would be quite annoying.
437 if (DatumGetObjectId(c
->constvalue
) >= FirstNormalObjectId
&&
438 !is_shippable(DatumGetObjectId(c
->constvalue
),
439 TSConfigRelationId
, fpinfo
))
442 case REGDICTIONARYOID
:
443 if (DatumGetObjectId(c
->constvalue
) >= FirstNormalObjectId
&&
444 !is_shippable(DatumGetObjectId(c
->constvalue
),
445 TSDictionaryRelationId
, fpinfo
))
448 case REGNAMESPACEOID
:
449 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
450 NamespaceRelationId
, fpinfo
))
454 if (!is_shippable(DatumGetObjectId(c
->constvalue
),
455 AuthIdRelationId
, fpinfo
))
462 * If the constant has nondefault collation, either it's of a
463 * non-builtin type, or it reflects folding of a CollateExpr.
464 * It's unsafe to send to the remote unless it's used in a
465 * non-collation-sensitive context.
467 collation
= c
->constcollid
;
468 if (collation
== InvalidOid
||
469 collation
== DEFAULT_COLLATION_OID
)
470 state
= FDW_COLLATE_NONE
;
472 state
= FDW_COLLATE_UNSAFE
;
477 Param
*p
= (Param
*) node
;
480 * If it's a MULTIEXPR Param, punt. We can't tell from here
481 * whether the referenced sublink/subplan contains any remote
482 * Vars; if it does, handling that is too complicated to
483 * consider supporting at present. Fortunately, MULTIEXPR
484 * Params are not reduced to plain PARAM_EXEC until the end of
485 * planning, so we can easily detect this case. (Normal
486 * PARAM_EXEC Params are safe to ship because their values
487 * come from somewhere else in the plan tree; but a MULTIEXPR
488 * references a sub-select elsewhere in the same targetlist,
489 * so we'd be on the hook to evaluate it somehow if we wanted
490 * to handle such cases as direct foreign updates.)
492 if (p
->paramkind
== PARAM_MULTIEXPR
)
496 * Collation rule is same as for Consts and non-foreign Vars.
498 collation
= p
->paramcollid
;
499 if (collation
== InvalidOid
||
500 collation
== DEFAULT_COLLATION_OID
)
501 state
= FDW_COLLATE_NONE
;
503 state
= FDW_COLLATE_UNSAFE
;
506 case T_SubscriptingRef
:
508 SubscriptingRef
*sr
= (SubscriptingRef
*) node
;
510 /* Assignment should not be in restrictions. */
511 if (sr
->refassgnexpr
!= NULL
)
515 * Recurse into the remaining subexpressions. The container
516 * subscripts will not affect collation of the SubscriptingRef
517 * result, so do those first and reset inner_cxt afterwards.
519 if (!foreign_expr_walker((Node
*) sr
->refupperindexpr
,
520 glob_cxt
, &inner_cxt
, case_arg_cxt
))
522 inner_cxt
.collation
= InvalidOid
;
523 inner_cxt
.state
= FDW_COLLATE_NONE
;
524 if (!foreign_expr_walker((Node
*) sr
->reflowerindexpr
,
525 glob_cxt
, &inner_cxt
, case_arg_cxt
))
527 inner_cxt
.collation
= InvalidOid
;
528 inner_cxt
.state
= FDW_COLLATE_NONE
;
529 if (!foreign_expr_walker((Node
*) sr
->refexpr
,
530 glob_cxt
, &inner_cxt
, case_arg_cxt
))
534 * Container subscripting typically yields same collation as
535 * refexpr's, but in case it doesn't, use same logic as for
538 collation
= sr
->refcollid
;
539 if (collation
== InvalidOid
)
540 state
= FDW_COLLATE_NONE
;
541 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
542 collation
== inner_cxt
.collation
)
543 state
= FDW_COLLATE_SAFE
;
544 else if (collation
== DEFAULT_COLLATION_OID
)
545 state
= FDW_COLLATE_NONE
;
547 state
= FDW_COLLATE_UNSAFE
;
552 FuncExpr
*fe
= (FuncExpr
*) node
;
555 * If function used by the expression is not shippable, it
556 * can't be sent to remote because it might have incompatible
557 * semantics on remote side.
559 if (!is_shippable(fe
->funcid
, ProcedureRelationId
, fpinfo
))
563 * Recurse to input subexpressions.
565 if (!foreign_expr_walker((Node
*) fe
->args
,
566 glob_cxt
, &inner_cxt
, case_arg_cxt
))
570 * If function's input collation is not derived from a foreign
571 * Var, it can't be sent to remote.
573 if (fe
->inputcollid
== InvalidOid
)
574 /* OK, inputs are all noncollatable */ ;
575 else if (inner_cxt
.state
!= FDW_COLLATE_SAFE
||
576 fe
->inputcollid
!= inner_cxt
.collation
)
580 * Detect whether node is introducing a collation not derived
581 * from a foreign Var. (If so, we just mark it unsafe for now
582 * rather than immediately returning false, since the parent
583 * node might not care.)
585 collation
= fe
->funccollid
;
586 if (collation
== InvalidOid
)
587 state
= FDW_COLLATE_NONE
;
588 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
589 collation
== inner_cxt
.collation
)
590 state
= FDW_COLLATE_SAFE
;
591 else if (collation
== DEFAULT_COLLATION_OID
)
592 state
= FDW_COLLATE_NONE
;
594 state
= FDW_COLLATE_UNSAFE
;
598 case T_DistinctExpr
: /* struct-equivalent to OpExpr */
600 OpExpr
*oe
= (OpExpr
*) node
;
603 * Similarly, only shippable operators can be sent to remote.
604 * (If the operator is shippable, we assume its underlying
607 if (!is_shippable(oe
->opno
, OperatorRelationId
, fpinfo
))
611 * Recurse to input subexpressions.
613 if (!foreign_expr_walker((Node
*) oe
->args
,
614 glob_cxt
, &inner_cxt
, case_arg_cxt
))
618 * If operator's input collation is not derived from a foreign
619 * Var, it can't be sent to remote.
621 if (oe
->inputcollid
== InvalidOid
)
622 /* OK, inputs are all noncollatable */ ;
623 else if (inner_cxt
.state
!= FDW_COLLATE_SAFE
||
624 oe
->inputcollid
!= inner_cxt
.collation
)
627 /* Result-collation handling is same as for functions */
628 collation
= oe
->opcollid
;
629 if (collation
== InvalidOid
)
630 state
= FDW_COLLATE_NONE
;
631 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
632 collation
== inner_cxt
.collation
)
633 state
= FDW_COLLATE_SAFE
;
634 else if (collation
== DEFAULT_COLLATION_OID
)
635 state
= FDW_COLLATE_NONE
;
637 state
= FDW_COLLATE_UNSAFE
;
640 case T_ScalarArrayOpExpr
:
642 ScalarArrayOpExpr
*oe
= (ScalarArrayOpExpr
*) node
;
645 * Again, only shippable operators can be sent to remote.
647 if (!is_shippable(oe
->opno
, OperatorRelationId
, fpinfo
))
651 * Recurse to input subexpressions.
653 if (!foreign_expr_walker((Node
*) oe
->args
,
654 glob_cxt
, &inner_cxt
, case_arg_cxt
))
658 * If operator's input collation is not derived from a foreign
659 * Var, it can't be sent to remote.
661 if (oe
->inputcollid
== InvalidOid
)
662 /* OK, inputs are all noncollatable */ ;
663 else if (inner_cxt
.state
!= FDW_COLLATE_SAFE
||
664 oe
->inputcollid
!= inner_cxt
.collation
)
667 /* Output is always boolean and so noncollatable. */
668 collation
= InvalidOid
;
669 state
= FDW_COLLATE_NONE
;
674 RelabelType
*r
= (RelabelType
*) node
;
677 * Recurse to input subexpression.
679 if (!foreign_expr_walker((Node
*) r
->arg
,
680 glob_cxt
, &inner_cxt
, case_arg_cxt
))
684 * RelabelType must not introduce a collation not derived from
685 * an input foreign Var (same logic as for a real function).
687 collation
= r
->resultcollid
;
688 if (collation
== InvalidOid
)
689 state
= FDW_COLLATE_NONE
;
690 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
691 collation
== inner_cxt
.collation
)
692 state
= FDW_COLLATE_SAFE
;
693 else if (collation
== DEFAULT_COLLATION_OID
)
694 state
= FDW_COLLATE_NONE
;
696 state
= FDW_COLLATE_UNSAFE
;
701 BoolExpr
*b
= (BoolExpr
*) node
;
704 * Recurse to input subexpressions.
706 if (!foreign_expr_walker((Node
*) b
->args
,
707 glob_cxt
, &inner_cxt
, case_arg_cxt
))
710 /* Output is always boolean and so noncollatable. */
711 collation
= InvalidOid
;
712 state
= FDW_COLLATE_NONE
;
717 NullTest
*nt
= (NullTest
*) node
;
720 * Recurse to input subexpressions.
722 if (!foreign_expr_walker((Node
*) nt
->arg
,
723 glob_cxt
, &inner_cxt
, case_arg_cxt
))
726 /* Output is always boolean and so noncollatable. */
727 collation
= InvalidOid
;
728 state
= FDW_COLLATE_NONE
;
733 CaseExpr
*ce
= (CaseExpr
*) node
;
734 foreign_loc_cxt arg_cxt
;
735 foreign_loc_cxt tmp_cxt
;
739 * Recurse to CASE's arg expression, if any. Its collation
740 * has to be saved aside for use while examining CaseTestExprs
741 * within the WHEN expressions.
743 arg_cxt
.collation
= InvalidOid
;
744 arg_cxt
.state
= FDW_COLLATE_NONE
;
747 if (!foreign_expr_walker((Node
*) ce
->arg
,
748 glob_cxt
, &arg_cxt
, case_arg_cxt
))
752 /* Examine the CaseWhen subexpressions. */
753 foreach(lc
, ce
->args
)
755 CaseWhen
*cw
= lfirst_node(CaseWhen
, lc
);
760 * In a CASE-with-arg, the parser should have produced
761 * WHEN clauses of the form "CaseTestExpr = RHS",
762 * possibly with an implicit coercion inserted above
763 * the CaseTestExpr. However in an expression that's
764 * been through the optimizer, the WHEN clause could
765 * be almost anything (since the equality operator
766 * could have been expanded into an inline function).
767 * In such cases forbid pushdown, because
768 * deparseCaseExpr can't handle it.
770 Node
*whenExpr
= (Node
*) cw
->expr
;
773 if (!IsA(whenExpr
, OpExpr
))
776 opArgs
= ((OpExpr
*) whenExpr
)->args
;
777 if (list_length(opArgs
) != 2 ||
778 !IsA(strip_implicit_coercions(linitial(opArgs
)),
784 * Recurse to WHEN expression, passing down the arg info.
785 * Its collation doesn't affect the result (really, it
786 * should be boolean and thus not have a collation).
788 tmp_cxt
.collation
= InvalidOid
;
789 tmp_cxt
.state
= FDW_COLLATE_NONE
;
790 if (!foreign_expr_walker((Node
*) cw
->expr
,
791 glob_cxt
, &tmp_cxt
, &arg_cxt
))
794 /* Recurse to THEN expression. */
795 if (!foreign_expr_walker((Node
*) cw
->result
,
796 glob_cxt
, &inner_cxt
, case_arg_cxt
))
800 /* Recurse to ELSE expression. */
801 if (!foreign_expr_walker((Node
*) ce
->defresult
,
802 glob_cxt
, &inner_cxt
, case_arg_cxt
))
806 * Detect whether node is introducing a collation not derived
807 * from a foreign Var. (If so, we just mark it unsafe for now
808 * rather than immediately returning false, since the parent
809 * node might not care.) This is the same as for function
810 * nodes, except that the input collation is derived from only
811 * the THEN and ELSE subexpressions.
813 collation
= ce
->casecollid
;
814 if (collation
== InvalidOid
)
815 state
= FDW_COLLATE_NONE
;
816 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
817 collation
== inner_cxt
.collation
)
818 state
= FDW_COLLATE_SAFE
;
819 else if (collation
== DEFAULT_COLLATION_OID
)
820 state
= FDW_COLLATE_NONE
;
822 state
= FDW_COLLATE_UNSAFE
;
827 CaseTestExpr
*c
= (CaseTestExpr
*) node
;
829 /* Punt if we seem not to be inside a CASE arg WHEN. */
834 * Otherwise, any nondefault collation attached to the
835 * CaseTestExpr node must be derived from foreign Var(s) in
838 collation
= c
->collation
;
839 if (collation
== InvalidOid
)
840 state
= FDW_COLLATE_NONE
;
841 else if (case_arg_cxt
->state
== FDW_COLLATE_SAFE
&&
842 collation
== case_arg_cxt
->collation
)
843 state
= FDW_COLLATE_SAFE
;
844 else if (collation
== DEFAULT_COLLATION_OID
)
845 state
= FDW_COLLATE_NONE
;
847 state
= FDW_COLLATE_UNSAFE
;
852 ArrayExpr
*a
= (ArrayExpr
*) node
;
855 * Recurse to input subexpressions.
857 if (!foreign_expr_walker((Node
*) a
->elements
,
858 glob_cxt
, &inner_cxt
, case_arg_cxt
))
862 * ArrayExpr must not introduce a collation not derived from
863 * an input foreign Var (same logic as for a function).
865 collation
= a
->array_collid
;
866 if (collation
== InvalidOid
)
867 state
= FDW_COLLATE_NONE
;
868 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
869 collation
== inner_cxt
.collation
)
870 state
= FDW_COLLATE_SAFE
;
871 else if (collation
== DEFAULT_COLLATION_OID
)
872 state
= FDW_COLLATE_NONE
;
874 state
= FDW_COLLATE_UNSAFE
;
879 List
*l
= (List
*) node
;
883 * Recurse to component subexpressions.
887 if (!foreign_expr_walker((Node
*) lfirst(lc
),
888 glob_cxt
, &inner_cxt
, case_arg_cxt
))
893 * When processing a list, collation state just bubbles up
894 * from the list elements.
896 collation
= inner_cxt
.collation
;
897 state
= inner_cxt
.state
;
899 /* Don't apply exprType() to the list. */
905 Aggref
*agg
= (Aggref
*) node
;
908 /* Not safe to pushdown when not in grouping context */
909 if (!IS_UPPER_REL(glob_cxt
->foreignrel
))
912 /* Only non-split aggregates are pushable. */
913 if (agg
->aggsplit
!= AGGSPLIT_SIMPLE
)
916 /* As usual, it must be shippable. */
917 if (!is_shippable(agg
->aggfnoid
, ProcedureRelationId
, fpinfo
))
921 * Recurse to input args. aggdirectargs, aggorder and
922 * aggdistinct are all present in args, so no need to check
923 * their shippability explicitly.
925 foreach(lc
, agg
->args
)
927 Node
*n
= (Node
*) lfirst(lc
);
929 /* If TargetEntry, extract the expression from it */
930 if (IsA(n
, TargetEntry
))
932 TargetEntry
*tle
= (TargetEntry
*) n
;
934 n
= (Node
*) tle
->expr
;
937 if (!foreign_expr_walker(n
,
938 glob_cxt
, &inner_cxt
, case_arg_cxt
))
943 * For aggorder elements, check whether the sort operator, if
944 * specified, is shippable or not.
948 foreach(lc
, agg
->aggorder
)
950 SortGroupClause
*srt
= (SortGroupClause
*) lfirst(lc
);
952 TypeCacheEntry
*typentry
;
955 tle
= get_sortgroupref_tle(srt
->tleSortGroupRef
,
957 sortcoltype
= exprType((Node
*) tle
->expr
);
958 typentry
= lookup_type_cache(sortcoltype
,
959 TYPECACHE_LT_OPR
| TYPECACHE_GT_OPR
);
960 /* Check shippability of non-default sort operator. */
961 if (srt
->sortop
!= typentry
->lt_opr
&&
962 srt
->sortop
!= typentry
->gt_opr
&&
963 !is_shippable(srt
->sortop
, OperatorRelationId
,
969 /* Check aggregate filter */
970 if (!foreign_expr_walker((Node
*) agg
->aggfilter
,
971 glob_cxt
, &inner_cxt
, case_arg_cxt
))
975 * If aggregate's input collation is not derived from a
976 * foreign Var, it can't be sent to remote.
978 if (agg
->inputcollid
== InvalidOid
)
979 /* OK, inputs are all noncollatable */ ;
980 else if (inner_cxt
.state
!= FDW_COLLATE_SAFE
||
981 agg
->inputcollid
!= inner_cxt
.collation
)
985 * Detect whether node is introducing a collation not derived
986 * from a foreign Var. (If so, we just mark it unsafe for now
987 * rather than immediately returning false, since the parent
988 * node might not care.)
990 collation
= agg
->aggcollid
;
991 if (collation
== InvalidOid
)
992 state
= FDW_COLLATE_NONE
;
993 else if (inner_cxt
.state
== FDW_COLLATE_SAFE
&&
994 collation
== inner_cxt
.collation
)
995 state
= FDW_COLLATE_SAFE
;
996 else if (collation
== DEFAULT_COLLATION_OID
)
997 state
= FDW_COLLATE_NONE
;
999 state
= FDW_COLLATE_UNSAFE
;
1005 * If it's anything else, assume it's unsafe. This list can be
1006 * expanded later, but don't forget to add deparse support below.
1012 * If result type of given expression is not shippable, it can't be sent
1013 * to remote because it might have incompatible semantics on remote side.
1015 if (check_type
&& !is_shippable(exprType(node
), TypeRelationId
, fpinfo
))
1019 * Now, merge my collation information into my parent's state.
1021 if (state
> outer_cxt
->state
)
1023 /* Override previous parent state */
1024 outer_cxt
->collation
= collation
;
1025 outer_cxt
->state
= state
;
1027 else if (state
== outer_cxt
->state
)
1029 /* Merge, or detect error if there's a collation conflict */
1032 case FDW_COLLATE_NONE
:
1033 /* Nothing + nothing is still nothing */
1035 case FDW_COLLATE_SAFE
:
1036 if (collation
!= outer_cxt
->collation
)
1039 * Non-default collation always beats default.
1041 if (outer_cxt
->collation
== DEFAULT_COLLATION_OID
)
1043 /* Override previous parent state */
1044 outer_cxt
->collation
= collation
;
1046 else if (collation
!= DEFAULT_COLLATION_OID
)
1049 * Conflict; show state as indeterminate. We don't
1050 * want to "return false" right away, since parent
1051 * node might not care about collation.
1053 outer_cxt
->state
= FDW_COLLATE_UNSAFE
;
1057 case FDW_COLLATE_UNSAFE
:
1058 /* We're still conflicted ... */
1068 * Returns true if given expr is something we'd have to send the value of
1069 * to the foreign server.
1071 * This should return true when the expression is a shippable node that
1072 * deparseExpr would add to context->params_list. Note that we don't care
1073 * if the expression *contains* such a node, only whether one appears at top
1074 * level. We need this to detect cases where setrefs.c would recognize a
1075 * false match between an fdw_exprs item (which came from the params_list)
1076 * and an entry in fdw_scan_tlist (which we're considering putting the given
1080 is_foreign_param(PlannerInfo
*root
,
1081 RelOptInfo
*baserel
,
1087 switch (nodeTag(expr
))
1091 /* It would have to be sent unless it's a foreign Var */
1092 Var
*var
= (Var
*) expr
;
1093 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) (baserel
->fdw_private
);
1096 if (IS_UPPER_REL(baserel
))
1097 relids
= fpinfo
->outerrel
->relids
;
1099 relids
= baserel
->relids
;
1101 if (bms_is_member(var
->varno
, relids
) && var
->varlevelsup
== 0)
1102 return false; /* foreign Var, so not a param */
1104 return true; /* it'd have to be a param */
1108 /* Params always have to be sent to the foreign server */
1117 * Returns true if it's safe to push down the sort expression described by
1118 * 'pathkey' to the foreign server.
1121 is_foreign_pathkey(PlannerInfo
*root
,
1122 RelOptInfo
*baserel
,
1125 EquivalenceClass
*pathkey_ec
= pathkey
->pk_eclass
;
1126 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) baserel
->fdw_private
;
1129 * is_foreign_expr would detect volatile expressions as well, but checking
1130 * ec_has_volatile here saves some cycles.
1132 if (pathkey_ec
->ec_has_volatile
)
1135 /* can't push down the sort if the pathkey's opfamily is not shippable */
1136 if (!is_shippable(pathkey
->pk_opfamily
, OperatorFamilyRelationId
, fpinfo
))
1139 /* can push if a suitable EC member exists */
1140 return (find_em_for_rel(root
, pathkey_ec
, baserel
) != NULL
);
1144 * Convert type OID + typmod info into a type name we can ship to the remote
1145 * server. Someplace else had better have verified that this type name is
1146 * expected to be known on the remote end.
1148 * This is almost just format_type_with_typemod(), except that if left to its
1149 * own devices, that function will make schema-qualification decisions based
1150 * on the local search_path, which is wrong. We must schema-qualify all
1151 * type names that are not in pg_catalog. We assume here that built-in types
1152 * are all in pg_catalog and need not be qualified; otherwise, qualify.
1155 deparse_type_name(Oid type_oid
, int32 typemod
)
1157 bits16 flags
= FORMAT_TYPE_TYPEMOD_GIVEN
;
1159 if (!is_builtin(type_oid
))
1160 flags
|= FORMAT_TYPE_FORCE_QUALIFY
;
1162 return format_type_extended(type_oid
, typemod
, flags
);
1166 * Build the targetlist for given relation to be deparsed as SELECT clause.
1168 * The output targetlist contains the columns that need to be fetched from the
1169 * foreign server for the given relation. If foreignrel is an upper relation,
1170 * then the output targetlist can also contain expressions to be evaluated on
1174 build_tlist_to_deparse(RelOptInfo
*foreignrel
)
1177 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
1181 * For an upper relation, we have already built the target list while
1182 * checking shippability, so just return that.
1184 if (IS_UPPER_REL(foreignrel
))
1185 return fpinfo
->grouped_tlist
;
1188 * We require columns specified in foreignrel->reltarget->exprs and those
1189 * required for evaluating the local conditions.
1191 tlist
= add_to_flat_tlist(tlist
,
1192 pull_var_clause((Node
*) foreignrel
->reltarget
->exprs
,
1193 PVC_RECURSE_PLACEHOLDERS
));
1194 foreach(lc
, fpinfo
->local_conds
)
1196 RestrictInfo
*rinfo
= lfirst_node(RestrictInfo
, lc
);
1198 tlist
= add_to_flat_tlist(tlist
,
1199 pull_var_clause((Node
*) rinfo
->clause
,
1200 PVC_RECURSE_PLACEHOLDERS
));
1207 * Deparse SELECT statement for given relation into buf.
1209 * tlist contains the list of desired columns to be fetched from foreign server.
1210 * For a base relation fpinfo->attrs_used is used to construct SELECT clause,
1211 * hence the tlist is ignored for a base relation.
1213 * remote_conds is the list of conditions to be deparsed into the WHERE clause
1214 * (or, in the case of upper relations, into the HAVING clause).
1216 * If params_list is not NULL, it receives a list of Params and other-relation
1217 * Vars used in the clauses; these values must be transmitted to the remote
1218 * server as parameter values.
1220 * If params_list is NULL, we're generating the query for EXPLAIN purposes,
1221 * so Params and other-relation Vars should be replaced by dummy values.
1223 * pathkeys is the list of pathkeys to order the result by.
1225 * is_subquery is the flag to indicate whether to deparse the specified
1226 * relation as a subquery.
1228 * List of columns selected is returned in retrieved_attrs.
1231 deparseSelectStmtForRel(StringInfo buf
, PlannerInfo
*root
, RelOptInfo
*rel
,
1232 List
*tlist
, List
*remote_conds
, List
*pathkeys
,
1233 bool has_final_sort
, bool has_limit
, bool is_subquery
,
1234 List
**retrieved_attrs
, List
**params_list
)
1236 deparse_expr_cxt context
;
1237 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) rel
->fdw_private
;
1241 * We handle relations for foreign tables, joins between those and upper
1244 Assert(IS_JOIN_REL(rel
) || IS_SIMPLE_REL(rel
) || IS_UPPER_REL(rel
));
1246 /* Fill portions of context common to upper, join and base relation */
1248 context
.root
= root
;
1249 context
.foreignrel
= rel
;
1250 context
.scanrel
= IS_UPPER_REL(rel
) ? fpinfo
->outerrel
: rel
;
1251 context
.params_list
= params_list
;
1253 /* Construct SELECT clause */
1254 deparseSelectSql(tlist
, is_subquery
, retrieved_attrs
, &context
);
1257 * For upper relations, the WHERE clause is built from the remote
1258 * conditions of the underlying scan relation; otherwise, we can use the
1259 * supplied list of remote conditions directly.
1261 if (IS_UPPER_REL(rel
))
1263 PgFdwRelationInfo
*ofpinfo
;
1265 ofpinfo
= (PgFdwRelationInfo
*) fpinfo
->outerrel
->fdw_private
;
1266 quals
= ofpinfo
->remote_conds
;
1269 quals
= remote_conds
;
1271 /* Construct FROM and WHERE clauses */
1272 deparseFromExpr(quals
, &context
);
1274 if (IS_UPPER_REL(rel
))
1276 /* Append GROUP BY clause */
1277 appendGroupByClause(tlist
, &context
);
1279 /* Append HAVING clause */
1282 appendStringInfoString(buf
, " HAVING ");
1283 appendConditions(remote_conds
, &context
);
1287 /* Add ORDER BY clause if we found any useful pathkeys */
1289 appendOrderByClause(pathkeys
, has_final_sort
, &context
);
1291 /* Add LIMIT clause if necessary */
1293 appendLimitClause(&context
);
1295 /* Add any necessary FOR UPDATE/SHARE. */
1296 deparseLockingClause(&context
);
1300 * Construct a simple SELECT statement that retrieves desired columns
1301 * of the specified foreign table, and append it to "buf". The output
1302 * contains just "SELECT ... ".
1304 * We also create an integer List of the columns being retrieved, which is
1305 * returned to *retrieved_attrs, unless we deparse the specified relation
1308 * tlist is the list of desired columns. is_subquery is the flag to
1309 * indicate whether to deparse the specified relation as a subquery.
1310 * Read prologue of deparseSelectStmtForRel() for details.
1313 deparseSelectSql(List
*tlist
, bool is_subquery
, List
**retrieved_attrs
,
1314 deparse_expr_cxt
*context
)
1316 StringInfo buf
= context
->buf
;
1317 RelOptInfo
*foreignrel
= context
->foreignrel
;
1318 PlannerInfo
*root
= context
->root
;
1319 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
1322 * Construct SELECT list
1324 appendStringInfoString(buf
, "SELECT ");
1329 * For a relation that is deparsed as a subquery, emit expressions
1330 * specified in the relation's reltarget. Note that since this is for
1331 * the subquery, no need to care about *retrieved_attrs.
1333 deparseSubqueryTargetList(context
);
1335 else if (IS_JOIN_REL(foreignrel
) || IS_UPPER_REL(foreignrel
))
1338 * For a join or upper relation the input tlist gives the list of
1339 * columns required to be fetched from the foreign server.
1341 deparseExplicitTargetList(tlist
, false, retrieved_attrs
, context
);
1346 * For a base relation fpinfo->attrs_used gives the list of columns
1347 * required to be fetched from the foreign server.
1349 RangeTblEntry
*rte
= planner_rt_fetch(foreignrel
->relid
, root
);
1352 * Core code already has some lock on each rel being planned, so we
1353 * can use NoLock here.
1355 Relation rel
= table_open(rte
->relid
, NoLock
);
1357 deparseTargetList(buf
, rte
, foreignrel
->relid
, rel
, false,
1358 fpinfo
->attrs_used
, false, retrieved_attrs
);
1359 table_close(rel
, NoLock
);
1364 * Construct a FROM clause and, if needed, a WHERE clause, and append those to
1367 * quals is the list of clauses to be included in the WHERE clause.
1368 * (These may or may not include RestrictInfo decoration.)
1371 deparseFromExpr(List
*quals
, deparse_expr_cxt
*context
)
1373 StringInfo buf
= context
->buf
;
1374 RelOptInfo
*scanrel
= context
->scanrel
;
1375 List
*additional_conds
= NIL
;
1377 /* For upper relations, scanrel must be either a joinrel or a baserel */
1378 Assert(!IS_UPPER_REL(context
->foreignrel
) ||
1379 IS_JOIN_REL(scanrel
) || IS_SIMPLE_REL(scanrel
));
1381 /* Construct FROM clause */
1382 appendStringInfoString(buf
, " FROM ");
1383 deparseFromExprForRel(buf
, context
->root
, scanrel
,
1384 (bms_membership(scanrel
->relids
) == BMS_MULTIPLE
),
1385 (Index
) 0, NULL
, &additional_conds
,
1386 context
->params_list
);
1387 appendWhereClause(quals
, additional_conds
, context
);
1388 if (additional_conds
!= NIL
)
1389 list_free_deep(additional_conds
);
1393 * Emit a target list that retrieves the columns specified in attrs_used.
1394 * This is used for both SELECT and RETURNING targetlists; the is_returning
1395 * parameter is true only for a RETURNING targetlist.
1397 * The tlist text is appended to buf, and we also create an integer List
1398 * of the columns being retrieved, which is returned to *retrieved_attrs.
1400 * If qualify_col is true, add relation alias before the column name.
1403 deparseTargetList(StringInfo buf
,
1408 Bitmapset
*attrs_used
,
1410 List
**retrieved_attrs
)
1412 TupleDesc tupdesc
= RelationGetDescr(rel
);
1417 *retrieved_attrs
= NIL
;
1419 /* If there's a whole-row reference, we'll need all the columns. */
1420 have_wholerow
= bms_is_member(0 - FirstLowInvalidHeapAttributeNumber
,
1424 for (i
= 1; i
<= tupdesc
->natts
; i
++)
1426 Form_pg_attribute attr
= TupleDescAttr(tupdesc
, i
- 1);
1428 /* Ignore dropped attributes. */
1429 if (attr
->attisdropped
)
1432 if (have_wholerow
||
1433 bms_is_member(i
- FirstLowInvalidHeapAttributeNumber
,
1437 appendStringInfoString(buf
, ", ");
1438 else if (is_returning
)
1439 appendStringInfoString(buf
, " RETURNING ");
1442 deparseColumnRef(buf
, rtindex
, i
, rte
, qualify_col
);
1444 *retrieved_attrs
= lappend_int(*retrieved_attrs
, i
);
1449 * Add ctid if needed. We currently don't support retrieving any other
1452 if (bms_is_member(SelfItemPointerAttributeNumber
- FirstLowInvalidHeapAttributeNumber
,
1456 appendStringInfoString(buf
, ", ");
1457 else if (is_returning
)
1458 appendStringInfoString(buf
, " RETURNING ");
1462 ADD_REL_QUALIFIER(buf
, rtindex
);
1463 appendStringInfoString(buf
, "ctid");
1465 *retrieved_attrs
= lappend_int(*retrieved_attrs
,
1466 SelfItemPointerAttributeNumber
);
1469 /* Don't generate bad syntax if no undropped columns */
1470 if (first
&& !is_returning
)
1471 appendStringInfoString(buf
, "NULL");
1475 * Deparse the appropriate locking clause (FOR UPDATE or FOR SHARE) for a
1476 * given relation (context->scanrel).
1479 deparseLockingClause(deparse_expr_cxt
*context
)
1481 StringInfo buf
= context
->buf
;
1482 PlannerInfo
*root
= context
->root
;
1483 RelOptInfo
*rel
= context
->scanrel
;
1484 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) rel
->fdw_private
;
1487 while ((relid
= bms_next_member(rel
->relids
, relid
)) >= 0)
1490 * Ignore relation if it appears in a lower subquery. Locking clause
1491 * for such a relation is included in the subquery if necessary.
1493 if (bms_is_member(relid
, fpinfo
->lower_subquery_rels
))
1497 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1498 * initial row fetch, rather than later on as is done for local
1499 * tables. The extra roundtrips involved in trying to duplicate the
1500 * local semantics exactly don't seem worthwhile (see also comments
1503 * Note: because we actually run the query as a cursor, this assumes
1504 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1507 if (bms_is_member(relid
, root
->all_result_relids
) &&
1508 (root
->parse
->commandType
== CMD_UPDATE
||
1509 root
->parse
->commandType
== CMD_DELETE
))
1511 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1512 appendStringInfoString(buf
, " FOR UPDATE");
1514 /* Add the relation alias if we are here for a join relation */
1515 if (IS_JOIN_REL(rel
))
1516 appendStringInfo(buf
, " OF %s%d", REL_ALIAS_PREFIX
, relid
);
1520 PlanRowMark
*rc
= get_plan_rowmark(root
->rowMarks
, relid
);
1525 * Relation is specified as a FOR UPDATE/SHARE target, so
1526 * handle that. (But we could also see LCS_NONE, meaning this
1527 * isn't a target relation after all.)
1529 * For now, just ignore any [NO] KEY specification, since (a)
1530 * it's not clear what that means for a remote table that we
1531 * don't have complete information about, and (b) it wouldn't
1532 * work anyway on older remote servers. Likewise, we don't
1533 * worry about NOWAIT.
1535 switch (rc
->strength
)
1538 /* No locking needed */
1540 case LCS_FORKEYSHARE
:
1542 appendStringInfoString(buf
, " FOR SHARE");
1544 case LCS_FORNOKEYUPDATE
:
1546 appendStringInfoString(buf
, " FOR UPDATE");
1550 /* Add the relation alias if we are here for a join relation */
1551 if (bms_membership(rel
->relids
) == BMS_MULTIPLE
&&
1552 rc
->strength
!= LCS_NONE
)
1553 appendStringInfo(buf
, " OF %s%d", REL_ALIAS_PREFIX
, relid
);
1560 * Deparse conditions from the provided list and append them to buf.
1562 * The conditions in the list are assumed to be ANDed. This function is used to
1563 * deparse WHERE clauses, JOIN .. ON clauses and HAVING clauses.
1565 * Depending on the caller, the list elements might be either RestrictInfos
1569 appendConditions(List
*exprs
, deparse_expr_cxt
*context
)
1573 bool is_first
= true;
1574 StringInfo buf
= context
->buf
;
1576 /* Make sure any constants in the exprs are printed portably */
1577 nestlevel
= set_transmission_modes();
1581 Expr
*expr
= (Expr
*) lfirst(lc
);
1583 /* Extract clause from RestrictInfo, if required */
1584 if (IsA(expr
, RestrictInfo
))
1585 expr
= ((RestrictInfo
*) expr
)->clause
;
1587 /* Connect expressions with "AND" and parenthesize each condition. */
1589 appendStringInfoString(buf
, " AND ");
1591 appendStringInfoChar(buf
, '(');
1592 deparseExpr(expr
, context
);
1593 appendStringInfoChar(buf
, ')');
1598 reset_transmission_modes(nestlevel
);
1602 * Append WHERE clause, containing conditions from exprs and additional_conds,
1606 appendWhereClause(List
*exprs
, List
*additional_conds
, deparse_expr_cxt
*context
)
1608 StringInfo buf
= context
->buf
;
1609 bool need_and
= false;
1612 if (exprs
!= NIL
|| additional_conds
!= NIL
)
1613 appendStringInfoString(buf
, " WHERE ");
1616 * If there are some filters, append them.
1620 appendConditions(exprs
, context
);
1625 * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1628 foreach(lc
, additional_conds
)
1631 appendStringInfoString(buf
, " AND ");
1632 appendStringInfoString(buf
, (char *) lfirst(lc
));
1637 /* Output join name for given join type */
1639 get_jointype_name(JoinType jointype
)
1659 /* Shouldn't come here, but protect from buggy code. */
1660 elog(ERROR
, "unsupported join type %d", jointype
);
1663 /* Keep compiler happy */
1668 * Deparse given targetlist and append it to context->buf.
1670 * tlist is list of TargetEntry's which in turn contain Var nodes.
1672 * retrieved_attrs is the list of continuously increasing integers starting
1673 * from 1. It has same number of entries as tlist.
1675 * This is used for both SELECT and RETURNING targetlists; the is_returning
1676 * parameter is true only for a RETURNING targetlist.
1679 deparseExplicitTargetList(List
*tlist
,
1681 List
**retrieved_attrs
,
1682 deparse_expr_cxt
*context
)
1685 StringInfo buf
= context
->buf
;
1688 *retrieved_attrs
= NIL
;
1692 TargetEntry
*tle
= lfirst_node(TargetEntry
, lc
);
1695 appendStringInfoString(buf
, ", ");
1696 else if (is_returning
)
1697 appendStringInfoString(buf
, " RETURNING ");
1699 deparseExpr((Expr
*) tle
->expr
, context
);
1701 *retrieved_attrs
= lappend_int(*retrieved_attrs
, i
+ 1);
1705 if (i
== 0 && !is_returning
)
1706 appendStringInfoString(buf
, "NULL");
1710 * Emit expressions specified in the given relation's reltarget.
1712 * This is used for deparsing the given relation as a subquery.
1715 deparseSubqueryTargetList(deparse_expr_cxt
*context
)
1717 StringInfo buf
= context
->buf
;
1718 RelOptInfo
*foreignrel
= context
->foreignrel
;
1722 /* Should only be called in these cases. */
1723 Assert(IS_SIMPLE_REL(foreignrel
) || IS_JOIN_REL(foreignrel
));
1726 foreach(lc
, foreignrel
->reltarget
->exprs
)
1728 Node
*node
= (Node
*) lfirst(lc
);
1731 appendStringInfoString(buf
, ", ");
1734 deparseExpr((Expr
*) node
, context
);
1737 /* Don't generate bad syntax if no expressions */
1739 appendStringInfoString(buf
, "NULL");
1743 * Construct FROM clause for given relation
1745 * The function constructs ... JOIN ... ON ... for join relation. For a base
1746 * relation it just returns schema-qualified tablename, with the appropriate
1747 * alias if so requested.
1749 * 'ignore_rel' is either zero or the RT index of a target relation. In the
1750 * latter case the function constructs FROM clause of UPDATE or USING clause
1751 * of DELETE; it deparses the join relation as if the relation never contained
1752 * the target relation, and creates a List of conditions to be deparsed into
1753 * the top-level WHERE clause, which is returned to *ignore_conds.
1755 * 'additional_conds' is a pointer to a list of strings to be appended to
1756 * the WHERE clause, coming from lower-level SEMI-JOINs.
1759 deparseFromExprForRel(StringInfo buf
, PlannerInfo
*root
, RelOptInfo
*foreignrel
,
1760 bool use_alias
, Index ignore_rel
, List
**ignore_conds
,
1761 List
**additional_conds
, List
**params_list
)
1763 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
1765 if (IS_JOIN_REL(foreignrel
))
1767 StringInfoData join_sql_o
;
1768 StringInfoData join_sql_i
;
1769 RelOptInfo
*outerrel
= fpinfo
->outerrel
;
1770 RelOptInfo
*innerrel
= fpinfo
->innerrel
;
1771 bool outerrel_is_target
= false;
1772 bool innerrel_is_target
= false;
1773 List
*additional_conds_i
= NIL
;
1774 List
*additional_conds_o
= NIL
;
1776 if (ignore_rel
> 0 && bms_is_member(ignore_rel
, foreignrel
->relids
))
1779 * If this is an inner join, add joinclauses to *ignore_conds and
1780 * set it to empty so that those can be deparsed into the WHERE
1781 * clause. Note that since the target relation can never be
1782 * within the nullable side of an outer join, those could safely
1783 * be pulled up into the WHERE clause (see foreign_join_ok()).
1784 * Note also that since the target relation is only inner-joined
1785 * to any other relation in the query, all conditions in the join
1786 * tree mentioning the target relation could be deparsed into the
1787 * WHERE clause by doing this recursively.
1789 if (fpinfo
->jointype
== JOIN_INNER
)
1791 *ignore_conds
= list_concat(*ignore_conds
,
1792 fpinfo
->joinclauses
);
1793 fpinfo
->joinclauses
= NIL
;
1797 * Check if either of the input relations is the target relation.
1799 if (outerrel
->relid
== ignore_rel
)
1800 outerrel_is_target
= true;
1801 else if (innerrel
->relid
== ignore_rel
)
1802 innerrel_is_target
= true;
1805 /* Deparse outer relation if not the target relation. */
1806 if (!outerrel_is_target
)
1808 initStringInfo(&join_sql_o
);
1809 deparseRangeTblRef(&join_sql_o
, root
, outerrel
,
1810 fpinfo
->make_outerrel_subquery
,
1811 ignore_rel
, ignore_conds
, &additional_conds_o
,
1815 * If inner relation is the target relation, skip deparsing it.
1816 * Note that since the join of the target relation with any other
1817 * relation in the query is an inner join and can never be within
1818 * the nullable side of an outer join, the join could be
1819 * interchanged with higher-level joins (cf. identity 1 on outer
1820 * join reordering shown in src/backend/optimizer/README), which
1821 * means it's safe to skip the target-relation deparsing here.
1823 if (innerrel_is_target
)
1825 Assert(fpinfo
->jointype
== JOIN_INNER
);
1826 Assert(fpinfo
->joinclauses
== NIL
);
1827 appendBinaryStringInfo(buf
, join_sql_o
.data
, join_sql_o
.len
);
1828 /* Pass EXISTS conditions to upper level */
1829 if (additional_conds_o
!= NIL
)
1831 Assert(*additional_conds
== NIL
);
1832 *additional_conds
= additional_conds_o
;
1838 /* Deparse inner relation if not the target relation. */
1839 if (!innerrel_is_target
)
1841 initStringInfo(&join_sql_i
);
1842 deparseRangeTblRef(&join_sql_i
, root
, innerrel
,
1843 fpinfo
->make_innerrel_subquery
,
1844 ignore_rel
, ignore_conds
, &additional_conds_i
,
1848 * SEMI-JOIN is deparsed as the EXISTS subquery. It references
1849 * outer and inner relations, so it should be evaluated as the
1850 * condition in the upper-level WHERE clause. We deparse the
1851 * condition and pass it to upper level callers as an
1852 * additional_conds list. Upper level callers are responsible for
1853 * inserting conditions from the list where appropriate.
1855 if (fpinfo
->jointype
== JOIN_SEMI
)
1857 deparse_expr_cxt context
;
1860 /* Construct deparsed condition from this SEMI-JOIN */
1861 initStringInfo(&str
);
1862 appendStringInfo(&str
, "EXISTS (SELECT NULL FROM %s",
1866 context
.foreignrel
= foreignrel
;
1867 context
.scanrel
= foreignrel
;
1868 context
.root
= root
;
1869 context
.params_list
= params_list
;
1872 * Append SEMI-JOIN clauses and EXISTS conditions from lower
1873 * levels to the current EXISTS subquery
1875 appendWhereClause(fpinfo
->joinclauses
, additional_conds_i
, &context
);
1878 * EXISTS conditions, coming from lower join levels, have just
1881 if (additional_conds_i
!= NIL
)
1883 list_free_deep(additional_conds_i
);
1884 additional_conds_i
= NIL
;
1887 /* Close parentheses for EXISTS subquery */
1888 appendStringInfoChar(&str
, ')');
1890 *additional_conds
= lappend(*additional_conds
, str
.data
);
1894 * If outer relation is the target relation, skip deparsing it.
1895 * See the above note about safety.
1897 if (outerrel_is_target
)
1899 Assert(fpinfo
->jointype
== JOIN_INNER
);
1900 Assert(fpinfo
->joinclauses
== NIL
);
1901 appendBinaryStringInfo(buf
, join_sql_i
.data
, join_sql_i
.len
);
1902 /* Pass EXISTS conditions to the upper call */
1903 if (additional_conds_i
!= NIL
)
1905 Assert(*additional_conds
== NIL
);
1906 *additional_conds
= additional_conds_i
;
1912 /* Neither of the relations is the target relation. */
1913 Assert(!outerrel_is_target
&& !innerrel_is_target
);
1916 * For semijoin FROM clause is deparsed as an outer relation. An inner
1917 * relation and join clauses are converted to EXISTS condition and
1918 * passed to the upper level.
1920 if (fpinfo
->jointype
== JOIN_SEMI
)
1922 appendBinaryStringInfo(buf
, join_sql_o
.data
, join_sql_o
.len
);
1927 * For a join relation FROM clause, entry is deparsed as
1929 * ((outer relation) <join type> (inner relation) ON
1932 appendStringInfo(buf
, "(%s %s JOIN %s ON ", join_sql_o
.data
,
1933 get_jointype_name(fpinfo
->jointype
), join_sql_i
.data
);
1935 /* Append join clause; (TRUE) if no join clause */
1936 if (fpinfo
->joinclauses
)
1938 deparse_expr_cxt context
;
1941 context
.foreignrel
= foreignrel
;
1942 context
.scanrel
= foreignrel
;
1943 context
.root
= root
;
1944 context
.params_list
= params_list
;
1946 appendStringInfoChar(buf
, '(');
1947 appendConditions(fpinfo
->joinclauses
, &context
);
1948 appendStringInfoChar(buf
, ')');
1951 appendStringInfoString(buf
, "(TRUE)");
1953 /* End the FROM clause entry. */
1954 appendStringInfoChar(buf
, ')');
1958 * Construct additional_conds to be passed to the upper caller from
1959 * current level additional_conds and additional_conds, coming from
1960 * inner and outer rels.
1962 if (additional_conds_o
!= NIL
)
1964 *additional_conds
= list_concat(*additional_conds
,
1965 additional_conds_o
);
1966 list_free(additional_conds_o
);
1969 if (additional_conds_i
!= NIL
)
1971 *additional_conds
= list_concat(*additional_conds
,
1972 additional_conds_i
);
1973 list_free(additional_conds_i
);
1978 RangeTblEntry
*rte
= planner_rt_fetch(foreignrel
->relid
, root
);
1981 * Core code already has some lock on each rel being planned, so we
1982 * can use NoLock here.
1984 Relation rel
= table_open(rte
->relid
, NoLock
);
1986 deparseRelation(buf
, rel
);
1989 * Add a unique alias to avoid any conflict in relation names due to
1990 * pulled up subqueries in the query being built for a pushed down
1994 appendStringInfo(buf
, " %s%d", REL_ALIAS_PREFIX
, foreignrel
->relid
);
1996 table_close(rel
, NoLock
);
2001 * Append FROM clause entry for the given relation into buf.
2002 * Conditions from lower-level SEMI-JOINs are appended to additional_conds
2003 * and should be added to upper level WHERE clause.
2006 deparseRangeTblRef(StringInfo buf
, PlannerInfo
*root
, RelOptInfo
*foreignrel
,
2007 bool make_subquery
, Index ignore_rel
, List
**ignore_conds
,
2008 List
**additional_conds
, List
**params_list
)
2010 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
2012 /* Should only be called in these cases. */
2013 Assert(IS_SIMPLE_REL(foreignrel
) || IS_JOIN_REL(foreignrel
));
2015 Assert(fpinfo
->local_conds
== NIL
);
2017 /* If make_subquery is true, deparse the relation as a subquery. */
2020 List
*retrieved_attrs
;
2024 * The given relation shouldn't contain the target relation, because
2025 * this should only happen for input relations for a full join, and
2026 * such relations can never contain an UPDATE/DELETE target.
2028 Assert(ignore_rel
== 0 ||
2029 !bms_is_member(ignore_rel
, foreignrel
->relids
));
2031 /* Deparse the subquery representing the relation. */
2032 appendStringInfoChar(buf
, '(');
2033 deparseSelectStmtForRel(buf
, root
, foreignrel
, NIL
,
2034 fpinfo
->remote_conds
, NIL
,
2036 &retrieved_attrs
, params_list
);
2037 appendStringInfoChar(buf
, ')');
2039 /* Append the relation alias. */
2040 appendStringInfo(buf
, " %s%d", SUBQUERY_REL_ALIAS_PREFIX
,
2041 fpinfo
->relation_index
);
2044 * Append the column aliases if needed. Note that the subquery emits
2045 * expressions specified in the relation's reltarget (see
2046 * deparseSubqueryTargetList).
2048 ncols
= list_length(foreignrel
->reltarget
->exprs
);
2053 appendStringInfoChar(buf
, '(');
2054 for (i
= 1; i
<= ncols
; i
++)
2057 appendStringInfoString(buf
, ", ");
2059 appendStringInfo(buf
, "%s%d", SUBQUERY_COL_ALIAS_PREFIX
, i
);
2061 appendStringInfoChar(buf
, ')');
2065 deparseFromExprForRel(buf
, root
, foreignrel
, true, ignore_rel
,
2066 ignore_conds
, additional_conds
,
2071 * deparse remote INSERT statement
2073 * The statement text is appended to buf, and we also create an integer List
2074 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
2075 * which is returned to *retrieved_attrs.
2077 * This also stores end position of the VALUES clause, so that we can rebuild
2078 * an INSERT for a batch of rows later.
2081 deparseInsertSql(StringInfo buf
, RangeTblEntry
*rte
,
2082 Index rtindex
, Relation rel
,
2083 List
*targetAttrs
, bool doNothing
,
2084 List
*withCheckOptionList
, List
*returningList
,
2085 List
**retrieved_attrs
, int *values_end_len
)
2087 TupleDesc tupdesc
= RelationGetDescr(rel
);
2092 appendStringInfoString(buf
, "INSERT INTO ");
2093 deparseRelation(buf
, rel
);
2097 appendStringInfoChar(buf
, '(');
2100 foreach(lc
, targetAttrs
)
2102 int attnum
= lfirst_int(lc
);
2105 appendStringInfoString(buf
, ", ");
2108 deparseColumnRef(buf
, rtindex
, attnum
, rte
, false);
2111 appendStringInfoString(buf
, ") VALUES (");
2115 foreach(lc
, targetAttrs
)
2117 int attnum
= lfirst_int(lc
);
2118 Form_pg_attribute attr
= TupleDescAttr(tupdesc
, attnum
- 1);
2121 appendStringInfoString(buf
, ", ");
2124 if (attr
->attgenerated
)
2125 appendStringInfoString(buf
, "DEFAULT");
2128 appendStringInfo(buf
, "$%d", pindex
);
2133 appendStringInfoChar(buf
, ')');
2136 appendStringInfoString(buf
, " DEFAULT VALUES");
2137 *values_end_len
= buf
->len
;
2140 appendStringInfoString(buf
, " ON CONFLICT DO NOTHING");
2142 deparseReturningList(buf
, rte
, rtindex
, rel
,
2143 rel
->trigdesc
&& rel
->trigdesc
->trig_insert_after_row
,
2144 withCheckOptionList
, returningList
, retrieved_attrs
);
2148 * rebuild remote INSERT statement
2150 * Provided a number of rows in a batch, builds INSERT statement with the
2151 * right number of parameters.
2154 rebuildInsertSql(StringInfo buf
, Relation rel
,
2155 char *orig_query
, List
*target_attrs
,
2156 int values_end_len
, int num_params
,
2159 TupleDesc tupdesc
= RelationGetDescr(rel
);
2165 /* Make sure the values_end_len is sensible */
2166 Assert((values_end_len
> 0) && (values_end_len
<= strlen(orig_query
)));
2168 /* Copy up to the end of the first record from the original query */
2169 appendBinaryStringInfo(buf
, orig_query
, values_end_len
);
2172 * Add records to VALUES clause (we already have parameters for the first
2173 * row, so start at the right offset).
2175 pindex
= num_params
+ 1;
2176 for (i
= 0; i
< num_rows
; i
++)
2178 appendStringInfoString(buf
, ", (");
2181 foreach(lc
, target_attrs
)
2183 int attnum
= lfirst_int(lc
);
2184 Form_pg_attribute attr
= TupleDescAttr(tupdesc
, attnum
- 1);
2187 appendStringInfoString(buf
, ", ");
2190 if (attr
->attgenerated
)
2191 appendStringInfoString(buf
, "DEFAULT");
2194 appendStringInfo(buf
, "$%d", pindex
);
2199 appendStringInfoChar(buf
, ')');
2202 /* Copy stuff after VALUES clause from the original query */
2203 appendStringInfoString(buf
, orig_query
+ values_end_len
);
2207 * deparse remote UPDATE statement
2209 * The statement text is appended to buf, and we also create an integer List
2210 * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any),
2211 * which is returned to *retrieved_attrs.
2214 deparseUpdateSql(StringInfo buf
, RangeTblEntry
*rte
,
2215 Index rtindex
, Relation rel
,
2217 List
*withCheckOptionList
, List
*returningList
,
2218 List
**retrieved_attrs
)
2220 TupleDesc tupdesc
= RelationGetDescr(rel
);
2225 appendStringInfoString(buf
, "UPDATE ");
2226 deparseRelation(buf
, rel
);
2227 appendStringInfoString(buf
, " SET ");
2229 pindex
= 2; /* ctid is always the first param */
2231 foreach(lc
, targetAttrs
)
2233 int attnum
= lfirst_int(lc
);
2234 Form_pg_attribute attr
= TupleDescAttr(tupdesc
, attnum
- 1);
2237 appendStringInfoString(buf
, ", ");
2240 deparseColumnRef(buf
, rtindex
, attnum
, rte
, false);
2241 if (attr
->attgenerated
)
2242 appendStringInfoString(buf
, " = DEFAULT");
2245 appendStringInfo(buf
, " = $%d", pindex
);
2249 appendStringInfoString(buf
, " WHERE ctid = $1");
2251 deparseReturningList(buf
, rte
, rtindex
, rel
,
2252 rel
->trigdesc
&& rel
->trigdesc
->trig_update_after_row
,
2253 withCheckOptionList
, returningList
, retrieved_attrs
);
2257 * deparse remote UPDATE statement
2259 * 'buf' is the output buffer to append the statement to
2260 * 'rtindex' is the RT index of the associated target relation
2261 * 'rel' is the relation descriptor for the target relation
2262 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
2263 * containing all base relations in the query
2264 * 'targetlist' is the tlist of the underlying foreign-scan plan node
2265 * (note that this only contains new-value expressions and junk attrs)
2266 * 'targetAttrs' is the target columns of the UPDATE
2267 * 'remote_conds' is the qual clauses that must be evaluated remotely
2268 * '*params_list' is an output list of exprs that will become remote Params
2269 * 'returningList' is the RETURNING targetlist
2270 * '*retrieved_attrs' is an output list of integers of columns being retrieved
2271 * by RETURNING (if any)
2274 deparseDirectUpdateSql(StringInfo buf
, PlannerInfo
*root
,
2275 Index rtindex
, Relation rel
,
2276 RelOptInfo
*foreignrel
,
2281 List
*returningList
,
2282 List
**retrieved_attrs
)
2284 deparse_expr_cxt context
;
2287 RangeTblEntry
*rte
= planner_rt_fetch(rtindex
, root
);
2290 List
*additional_conds
= NIL
;
2292 /* Set up context struct for recursion */
2293 context
.root
= root
;
2294 context
.foreignrel
= foreignrel
;
2295 context
.scanrel
= foreignrel
;
2297 context
.params_list
= params_list
;
2299 appendStringInfoString(buf
, "UPDATE ");
2300 deparseRelation(buf
, rel
);
2301 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2302 appendStringInfo(buf
, " %s%d", REL_ALIAS_PREFIX
, rtindex
);
2303 appendStringInfoString(buf
, " SET ");
2305 /* Make sure any constants in the exprs are printed portably */
2306 nestlevel
= set_transmission_modes();
2309 forboth(lc
, targetlist
, lc2
, targetAttrs
)
2311 TargetEntry
*tle
= lfirst_node(TargetEntry
, lc
);
2312 int attnum
= lfirst_int(lc2
);
2314 /* update's new-value expressions shouldn't be resjunk */
2315 Assert(!tle
->resjunk
);
2318 appendStringInfoString(buf
, ", ");
2321 deparseColumnRef(buf
, rtindex
, attnum
, rte
, false);
2322 appendStringInfoString(buf
, " = ");
2323 deparseExpr((Expr
*) tle
->expr
, &context
);
2326 reset_transmission_modes(nestlevel
);
2328 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2330 List
*ignore_conds
= NIL
;
2333 appendStringInfoString(buf
, " FROM ");
2334 deparseFromExprForRel(buf
, root
, foreignrel
, true, rtindex
,
2335 &ignore_conds
, &additional_conds
, params_list
);
2336 remote_conds
= list_concat(remote_conds
, ignore_conds
);
2339 appendWhereClause(remote_conds
, additional_conds
, &context
);
2341 if (additional_conds
!= NIL
)
2342 list_free_deep(additional_conds
);
2344 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2345 deparseExplicitTargetList(returningList
, true, retrieved_attrs
,
2348 deparseReturningList(buf
, rte
, rtindex
, rel
, false,
2349 NIL
, returningList
, retrieved_attrs
);
2353 * deparse remote DELETE statement
2355 * The statement text is appended to buf, and we also create an integer List
2356 * of the columns being retrieved by RETURNING (if any), which is returned
2357 * to *retrieved_attrs.
2360 deparseDeleteSql(StringInfo buf
, RangeTblEntry
*rte
,
2361 Index rtindex
, Relation rel
,
2362 List
*returningList
,
2363 List
**retrieved_attrs
)
2365 appendStringInfoString(buf
, "DELETE FROM ");
2366 deparseRelation(buf
, rel
);
2367 appendStringInfoString(buf
, " WHERE ctid = $1");
2369 deparseReturningList(buf
, rte
, rtindex
, rel
,
2370 rel
->trigdesc
&& rel
->trigdesc
->trig_delete_after_row
,
2371 NIL
, returningList
, retrieved_attrs
);
2375 * deparse remote DELETE statement
2377 * 'buf' is the output buffer to append the statement to
2378 * 'rtindex' is the RT index of the associated target relation
2379 * 'rel' is the relation descriptor for the target relation
2380 * 'foreignrel' is the RelOptInfo for the target relation or the join relation
2381 * containing all base relations in the query
2382 * 'remote_conds' is the qual clauses that must be evaluated remotely
2383 * '*params_list' is an output list of exprs that will become remote Params
2384 * 'returningList' is the RETURNING targetlist
2385 * '*retrieved_attrs' is an output list of integers of columns being retrieved
2386 * by RETURNING (if any)
2389 deparseDirectDeleteSql(StringInfo buf
, PlannerInfo
*root
,
2390 Index rtindex
, Relation rel
,
2391 RelOptInfo
*foreignrel
,
2394 List
*returningList
,
2395 List
**retrieved_attrs
)
2397 deparse_expr_cxt context
;
2398 List
*additional_conds
= NIL
;
2400 /* Set up context struct for recursion */
2401 context
.root
= root
;
2402 context
.foreignrel
= foreignrel
;
2403 context
.scanrel
= foreignrel
;
2405 context
.params_list
= params_list
;
2407 appendStringInfoString(buf
, "DELETE FROM ");
2408 deparseRelation(buf
, rel
);
2409 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2410 appendStringInfo(buf
, " %s%d", REL_ALIAS_PREFIX
, rtindex
);
2412 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2414 List
*ignore_conds
= NIL
;
2416 appendStringInfoString(buf
, " USING ");
2417 deparseFromExprForRel(buf
, root
, foreignrel
, true, rtindex
,
2418 &ignore_conds
, &additional_conds
, params_list
);
2419 remote_conds
= list_concat(remote_conds
, ignore_conds
);
2422 appendWhereClause(remote_conds
, additional_conds
, &context
);
2424 if (additional_conds
!= NIL
)
2425 list_free_deep(additional_conds
);
2427 if (foreignrel
->reloptkind
== RELOPT_JOINREL
)
2428 deparseExplicitTargetList(returningList
, true, retrieved_attrs
,
2431 deparseReturningList(buf
, planner_rt_fetch(rtindex
, root
),
2432 rtindex
, rel
, false,
2433 NIL
, returningList
, retrieved_attrs
);
2437 * Add a RETURNING clause, if needed, to an INSERT/UPDATE/DELETE.
2440 deparseReturningList(StringInfo buf
, RangeTblEntry
*rte
,
2441 Index rtindex
, Relation rel
,
2442 bool trig_after_row
,
2443 List
*withCheckOptionList
,
2444 List
*returningList
,
2445 List
**retrieved_attrs
)
2447 Bitmapset
*attrs_used
= NULL
;
2451 /* whole-row reference acquires all non-system columns */
2453 bms_make_singleton(0 - FirstLowInvalidHeapAttributeNumber
);
2456 if (withCheckOptionList
!= NIL
)
2459 * We need the attrs, non-system and system, mentioned in the local
2460 * query's WITH CHECK OPTION list.
2462 * Note: we do this to ensure that WCO constraints will be evaluated
2463 * on the data actually inserted/updated on the remote side, which
2464 * might differ from the data supplied by the core code, for example
2465 * as a result of remote triggers.
2467 pull_varattnos((Node
*) withCheckOptionList
, rtindex
,
2471 if (returningList
!= NIL
)
2474 * We need the attrs, non-system and system, mentioned in the local
2475 * query's RETURNING list.
2477 pull_varattnos((Node
*) returningList
, rtindex
,
2481 if (attrs_used
!= NULL
)
2482 deparseTargetList(buf
, rte
, rtindex
, rel
, true, attrs_used
, false,
2485 *retrieved_attrs
= NIL
;
2489 * Construct SELECT statement to acquire size in blocks of given relation.
2491 * Note: we use local definition of block size, not remote definition.
2492 * This is perhaps debatable.
2494 * Note: pg_relation_size() exists in 8.1 and later.
2497 deparseAnalyzeSizeSql(StringInfo buf
, Relation rel
)
2499 StringInfoData relname
;
2501 /* We'll need the remote relation name as a literal. */
2502 initStringInfo(&relname
);
2503 deparseRelation(&relname
, rel
);
2505 appendStringInfoString(buf
, "SELECT pg_catalog.pg_relation_size(");
2506 deparseStringLiteral(buf
, relname
.data
);
2507 appendStringInfo(buf
, "::pg_catalog.regclass) / %d", BLCKSZ
);
2511 * Construct SELECT statement to acquire the number of rows and the relkind of
2514 * Note: we just return the remote server's reltuples value, which might
2515 * be off a good deal, but it doesn't seem worth working harder. See
2516 * comments in postgresAcquireSampleRowsFunc.
2519 deparseAnalyzeInfoSql(StringInfo buf
, Relation rel
)
2521 StringInfoData relname
;
2523 /* We'll need the remote relation name as a literal. */
2524 initStringInfo(&relname
);
2525 deparseRelation(&relname
, rel
);
2527 appendStringInfoString(buf
, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2528 deparseStringLiteral(buf
, relname
.data
);
2529 appendStringInfoString(buf
, "::pg_catalog.regclass");
2533 * Construct SELECT statement to acquire sample rows of given relation.
2535 * SELECT command is appended to buf, and list of columns retrieved
2536 * is returned to *retrieved_attrs.
2538 * We only support sampling methods we can decide based on server version.
2539 * Allowing custom TSM modules (like tsm_system_rows) might be useful, but it
2540 * would require detecting which extensions are installed, to allow automatic
2541 * fall-back. Moreover, the methods may use different parameters like number
2542 * of rows (and not sampling rate). So we leave this for future improvements.
2544 * Using random() to sample rows on the remote server has the advantage that
2545 * this works on all PostgreSQL versions (unlike TABLESAMPLE), and that it
2546 * does the sampling on the remote side (without transferring everything and
2547 * then discarding most rows).
2549 * The disadvantage is that we still have to read all rows and evaluate the
2550 * random(), while TABLESAMPLE (at least with the "system" method) may skip.
2551 * It's not that different from the "bernoulli" method, though.
2553 * We could also do "ORDER BY random() LIMIT x", which would always pick
2554 * the expected number of rows, but it requires sorting so it may be much
2555 * more expensive (particularly on large tables, which is what the
2556 * remote sampling is meant to improve).
2559 deparseAnalyzeSql(StringInfo buf
, Relation rel
,
2560 PgFdwSamplingMethod sample_method
, double sample_frac
,
2561 List
**retrieved_attrs
)
2563 Oid relid
= RelationGetRelid(rel
);
2564 TupleDesc tupdesc
= RelationGetDescr(rel
);
2571 *retrieved_attrs
= NIL
;
2573 appendStringInfoString(buf
, "SELECT ");
2574 for (i
= 0; i
< tupdesc
->natts
; i
++)
2576 /* Ignore dropped columns. */
2577 if (TupleDescAttr(tupdesc
, i
)->attisdropped
)
2581 appendStringInfoString(buf
, ", ");
2584 /* Use attribute name or column_name option. */
2585 colname
= NameStr(TupleDescAttr(tupdesc
, i
)->attname
);
2586 options
= GetForeignColumnOptions(relid
, i
+ 1);
2588 foreach(lc
, options
)
2590 DefElem
*def
= (DefElem
*) lfirst(lc
);
2592 if (strcmp(def
->defname
, "column_name") == 0)
2594 colname
= defGetString(def
);
2599 appendStringInfoString(buf
, quote_identifier(colname
));
2601 *retrieved_attrs
= lappend_int(*retrieved_attrs
, i
+ 1);
2604 /* Don't generate bad syntax for zero-column relation. */
2606 appendStringInfoString(buf
, "NULL");
2609 * Construct FROM clause, and perhaps WHERE clause too, depending on the
2610 * selected sampling method.
2612 appendStringInfoString(buf
, " FROM ");
2613 deparseRelation(buf
, rel
);
2615 switch (sample_method
)
2617 case ANALYZE_SAMPLE_OFF
:
2618 /* nothing to do here */
2621 case ANALYZE_SAMPLE_RANDOM
:
2622 appendStringInfo(buf
, " WHERE pg_catalog.random() < %f", sample_frac
);
2625 case ANALYZE_SAMPLE_SYSTEM
:
2626 appendStringInfo(buf
, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac
));
2629 case ANALYZE_SAMPLE_BERNOULLI
:
2630 appendStringInfo(buf
, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac
));
2633 case ANALYZE_SAMPLE_AUTO
:
2634 /* should have been resolved into actual method */
2635 elog(ERROR
, "unexpected sampling method");
2641 * Construct a simple "TRUNCATE rel" statement
2644 deparseTruncateSql(StringInfo buf
,
2646 DropBehavior behavior
,
2651 appendStringInfoString(buf
, "TRUNCATE ");
2655 Relation rel
= lfirst(cell
);
2657 if (cell
!= list_head(rels
))
2658 appendStringInfoString(buf
, ", ");
2660 deparseRelation(buf
, rel
);
2663 appendStringInfo(buf
, " %s IDENTITY",
2664 restart_seqs
? "RESTART" : "CONTINUE");
2666 if (behavior
== DROP_RESTRICT
)
2667 appendStringInfoString(buf
, " RESTRICT");
2668 else if (behavior
== DROP_CASCADE
)
2669 appendStringInfoString(buf
, " CASCADE");
2673 * Construct name to use for given column, and emit it into buf.
2674 * If it has a column_name FDW option, use that instead of attribute name.
2676 * If qualify_col is true, qualify column name with the alias of relation.
2679 deparseColumnRef(StringInfo buf
, int varno
, int varattno
, RangeTblEntry
*rte
,
2682 /* We support fetching the remote side's CTID and OID. */
2683 if (varattno
== SelfItemPointerAttributeNumber
)
2686 ADD_REL_QUALIFIER(buf
, varno
);
2687 appendStringInfoString(buf
, "ctid");
2689 else if (varattno
< 0)
2692 * All other system attributes are fetched as 0, except for table OID,
2693 * which is fetched as the local table OID. However, we must be
2694 * careful; the table could be beneath an outer join, in which case it
2695 * must go to NULL whenever the rest of the row does.
2699 if (varattno
== TableOidAttributeNumber
)
2700 fetchval
= rte
->relid
;
2704 appendStringInfoString(buf
, "CASE WHEN (");
2705 ADD_REL_QUALIFIER(buf
, varno
);
2706 appendStringInfo(buf
, "*)::text IS NOT NULL THEN %u END", fetchval
);
2709 appendStringInfo(buf
, "%u", fetchval
);
2711 else if (varattno
== 0)
2713 /* Whole row reference */
2715 Bitmapset
*attrs_used
;
2717 /* Required only to be passed down to deparseTargetList(). */
2718 List
*retrieved_attrs
;
2721 * The lock on the relation will be held by upper callers, so it's
2722 * fine to open it with no lock here.
2724 rel
= table_open(rte
->relid
, NoLock
);
2727 * The local name of the foreign table can not be recognized by the
2728 * foreign server and the table it references on foreign server might
2729 * have different column ordering or different columns than those
2730 * declared locally. Hence we have to deparse whole-row reference as
2731 * ROW(columns referenced locally). Construct this by deparsing a
2732 * "whole row" attribute.
2734 attrs_used
= bms_add_member(NULL
,
2735 0 - FirstLowInvalidHeapAttributeNumber
);
2738 * In case the whole-row reference is under an outer join then it has
2739 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2740 * query would always involve multiple relations, thus qualify_col
2745 appendStringInfoString(buf
, "CASE WHEN (");
2746 ADD_REL_QUALIFIER(buf
, varno
);
2747 appendStringInfoString(buf
, "*)::text IS NOT NULL THEN ");
2750 appendStringInfoString(buf
, "ROW(");
2751 deparseTargetList(buf
, rte
, varno
, rel
, false, attrs_used
, qualify_col
,
2753 appendStringInfoChar(buf
, ')');
2755 /* Complete the CASE WHEN statement started above. */
2757 appendStringInfoString(buf
, " END");
2759 table_close(rel
, NoLock
);
2760 bms_free(attrs_used
);
2764 char *colname
= NULL
;
2768 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2769 Assert(!IS_SPECIAL_VARNO(varno
));
2772 * If it's a column of a foreign table, and it has the column_name FDW
2773 * option, use that value.
2775 options
= GetForeignColumnOptions(rte
->relid
, varattno
);
2776 foreach(lc
, options
)
2778 DefElem
*def
= (DefElem
*) lfirst(lc
);
2780 if (strcmp(def
->defname
, "column_name") == 0)
2782 colname
= defGetString(def
);
2788 * If it's a column of a regular table or it doesn't have column_name
2789 * FDW option, use attribute name.
2791 if (colname
== NULL
)
2792 colname
= get_attname(rte
->relid
, varattno
, false);
2795 ADD_REL_QUALIFIER(buf
, varno
);
2797 appendStringInfoString(buf
, quote_identifier(colname
));
2802 * Append remote name of specified foreign table to buf.
2803 * Use value of table_name FDW option (if any) instead of relation's name.
2804 * Similarly, schema_name FDW option overrides schema name.
2807 deparseRelation(StringInfo buf
, Relation rel
)
2809 ForeignTable
*table
;
2810 const char *nspname
= NULL
;
2811 const char *relname
= NULL
;
2814 /* obtain additional catalog information. */
2815 table
= GetForeignTable(RelationGetRelid(rel
));
2818 * Use value of FDW options if any, instead of the name of object itself.
2820 foreach(lc
, table
->options
)
2822 DefElem
*def
= (DefElem
*) lfirst(lc
);
2824 if (strcmp(def
->defname
, "schema_name") == 0)
2825 nspname
= defGetString(def
);
2826 else if (strcmp(def
->defname
, "table_name") == 0)
2827 relname
= defGetString(def
);
2831 * Note: we could skip printing the schema name if it's pg_catalog, but
2832 * that doesn't seem worth the trouble.
2834 if (nspname
== NULL
)
2835 nspname
= get_namespace_name(RelationGetNamespace(rel
));
2836 if (relname
== NULL
)
2837 relname
= RelationGetRelationName(rel
);
2839 appendStringInfo(buf
, "%s.%s",
2840 quote_identifier(nspname
), quote_identifier(relname
));
2844 * Append a SQL string literal representing "val" to buf.
2847 deparseStringLiteral(StringInfo buf
, const char *val
)
2852 * Rather than making assumptions about the remote server's value of
2853 * standard_conforming_strings, always use E'foo' syntax if there are any
2854 * backslashes. This will fail on remote servers before 8.1, but those
2855 * are long out of support.
2857 if (strchr(val
, '\\') != NULL
)
2858 appendStringInfoChar(buf
, ESCAPE_STRING_SYNTAX
);
2859 appendStringInfoChar(buf
, '\'');
2860 for (valptr
= val
; *valptr
; valptr
++)
2864 if (SQL_STR_DOUBLE(ch
, true))
2865 appendStringInfoChar(buf
, ch
);
2866 appendStringInfoChar(buf
, ch
);
2868 appendStringInfoChar(buf
, '\'');
2872 * Deparse given expression into context->buf.
2874 * This function must support all the same node types that foreign_expr_walker
2877 * Note: unlike ruleutils.c, we just use a simple hard-wired parenthesization
2878 * scheme: anything more complex than a Var, Const, function call or cast
2879 * should be self-parenthesized.
2882 deparseExpr(Expr
*node
, deparse_expr_cxt
*context
)
2887 switch (nodeTag(node
))
2890 deparseVar((Var
*) node
, context
);
2893 deparseConst((Const
*) node
, context
, 0);
2896 deparseParam((Param
*) node
, context
);
2898 case T_SubscriptingRef
:
2899 deparseSubscriptingRef((SubscriptingRef
*) node
, context
);
2902 deparseFuncExpr((FuncExpr
*) node
, context
);
2905 deparseOpExpr((OpExpr
*) node
, context
);
2907 case T_DistinctExpr
:
2908 deparseDistinctExpr((DistinctExpr
*) node
, context
);
2910 case T_ScalarArrayOpExpr
:
2911 deparseScalarArrayOpExpr((ScalarArrayOpExpr
*) node
, context
);
2914 deparseRelabelType((RelabelType
*) node
, context
);
2917 deparseBoolExpr((BoolExpr
*) node
, context
);
2920 deparseNullTest((NullTest
*) node
, context
);
2923 deparseCaseExpr((CaseExpr
*) node
, context
);
2926 deparseArrayExpr((ArrayExpr
*) node
, context
);
2929 deparseAggref((Aggref
*) node
, context
);
2932 elog(ERROR
, "unsupported expression type for deparse: %d",
2933 (int) nodeTag(node
));
2939 * Deparse given Var node into context->buf.
2941 * If the Var belongs to the foreign relation, just print its remote name.
2942 * Otherwise, it's effectively a Param (and will in fact be a Param at
2943 * run time). Handle it the same way we handle plain Params --- see
2944 * deparseParam for comments.
2947 deparseVar(Var
*node
, deparse_expr_cxt
*context
)
2949 Relids relids
= context
->scanrel
->relids
;
2953 /* Qualify columns when multiple relations are involved. */
2954 bool qualify_col
= (bms_membership(relids
) == BMS_MULTIPLE
);
2957 * If the Var belongs to the foreign relation that is deparsed as a
2958 * subquery, use the relation and column alias to the Var provided by the
2959 * subquery, instead of the remote name.
2961 if (is_subquery_var(node
, context
->scanrel
, &relno
, &colno
))
2963 appendStringInfo(context
->buf
, "%s%d.%s%d",
2964 SUBQUERY_REL_ALIAS_PREFIX
, relno
,
2965 SUBQUERY_COL_ALIAS_PREFIX
, colno
);
2969 if (bms_is_member(node
->varno
, relids
) && node
->varlevelsup
== 0)
2970 deparseColumnRef(context
->buf
, node
->varno
, node
->varattno
,
2971 planner_rt_fetch(node
->varno
, context
->root
),
2975 /* Treat like a Param */
2976 if (context
->params_list
)
2981 /* find its index in params_list */
2982 foreach(lc
, *context
->params_list
)
2985 if (equal(node
, (Node
*) lfirst(lc
)))
2990 /* not in list, so add it */
2992 *context
->params_list
= lappend(*context
->params_list
, node
);
2995 printRemoteParam(pindex
, node
->vartype
, node
->vartypmod
, context
);
2999 printRemotePlaceholder(node
->vartype
, node
->vartypmod
, context
);
3005 * Deparse given constant value into context->buf.
3007 * This function has to be kept in sync with ruleutils.c's get_const_expr.
3009 * As in that function, showtype can be -1 to never show "::typename"
3010 * decoration, +1 to always show it, or 0 to show it only if the constant
3011 * wouldn't be assumed to be the right type by default.
3013 * In addition, this code allows showtype to be -2 to indicate that we should
3014 * not show "::typename" decoration if the constant is printed as an untyped
3015 * literal or NULL (while in other cases, behaving as for showtype == 0).
3018 deparseConst(Const
*node
, deparse_expr_cxt
*context
, int showtype
)
3020 StringInfo buf
= context
->buf
;
3024 bool isfloat
= false;
3025 bool isstring
= false;
3028 if (node
->constisnull
)
3030 appendStringInfoString(buf
, "NULL");
3032 appendStringInfo(buf
, "::%s",
3033 deparse_type_name(node
->consttype
,
3034 node
->consttypmod
));
3038 getTypeOutputInfo(node
->consttype
,
3039 &typoutput
, &typIsVarlena
);
3040 extval
= OidOutputFunctionCall(typoutput
, node
->constvalue
);
3042 switch (node
->consttype
)
3053 * No need to quote unless it's a special value such as 'NaN'.
3054 * See comments in get_const_expr().
3056 if (strspn(extval
, "0123456789+-eE.") == strlen(extval
))
3058 if (extval
[0] == '+' || extval
[0] == '-')
3059 appendStringInfo(buf
, "(%s)", extval
);
3061 appendStringInfoString(buf
, extval
);
3062 if (strcspn(extval
, "eE.") != strlen(extval
))
3063 isfloat
= true; /* it looks like a float */
3066 appendStringInfo(buf
, "'%s'", extval
);
3071 appendStringInfo(buf
, "B'%s'", extval
);
3074 if (strcmp(extval
, "t") == 0)
3075 appendStringInfoString(buf
, "true");
3077 appendStringInfoString(buf
, "false");
3080 deparseStringLiteral(buf
, extval
);
3088 return; /* never print type label */
3091 * For showtype == 0, append ::typename unless the constant will be
3092 * implicitly typed as the right type when it is read in.
3094 * XXX this code has to be kept in sync with the behavior of the parser,
3095 * especially make_const.
3097 switch (node
->consttype
)
3105 needlabel
= !isfloat
|| (node
->consttypmod
>= 0);
3110 /* label unless we printed it as an untyped string */
3111 needlabel
= !isstring
;
3117 if (needlabel
|| showtype
> 0)
3118 appendStringInfo(buf
, "::%s",
3119 deparse_type_name(node
->consttype
,
3120 node
->consttypmod
));
3124 * Deparse given Param node.
3126 * If we're generating the query "for real", add the Param to
3127 * context->params_list if it's not already present, and then use its index
3128 * in that list as the remote parameter number. During EXPLAIN, there's
3129 * no need to identify a parameter number.
3132 deparseParam(Param
*node
, deparse_expr_cxt
*context
)
3134 if (context
->params_list
)
3139 /* find its index in params_list */
3140 foreach(lc
, *context
->params_list
)
3143 if (equal(node
, (Node
*) lfirst(lc
)))
3148 /* not in list, so add it */
3150 *context
->params_list
= lappend(*context
->params_list
, node
);
3153 printRemoteParam(pindex
, node
->paramtype
, node
->paramtypmod
, context
);
3157 printRemotePlaceholder(node
->paramtype
, node
->paramtypmod
, context
);
3162 * Deparse a container subscript expression.
3165 deparseSubscriptingRef(SubscriptingRef
*node
, deparse_expr_cxt
*context
)
3167 StringInfo buf
= context
->buf
;
3168 ListCell
*lowlist_item
;
3169 ListCell
*uplist_item
;
3171 /* Always parenthesize the expression. */
3172 appendStringInfoChar(buf
, '(');
3175 * Deparse referenced array expression first. If that expression includes
3176 * a cast, we have to parenthesize to prevent the array subscript from
3177 * being taken as typename decoration. We can avoid that in the typical
3178 * case of subscripting a Var, but otherwise do it.
3180 if (IsA(node
->refexpr
, Var
))
3181 deparseExpr(node
->refexpr
, context
);
3184 appendStringInfoChar(buf
, '(');
3185 deparseExpr(node
->refexpr
, context
);
3186 appendStringInfoChar(buf
, ')');
3189 /* Deparse subscript expressions. */
3190 lowlist_item
= list_head(node
->reflowerindexpr
); /* could be NULL */
3191 foreach(uplist_item
, node
->refupperindexpr
)
3193 appendStringInfoChar(buf
, '[');
3196 deparseExpr(lfirst(lowlist_item
), context
);
3197 appendStringInfoChar(buf
, ':');
3198 lowlist_item
= lnext(node
->reflowerindexpr
, lowlist_item
);
3200 deparseExpr(lfirst(uplist_item
), context
);
3201 appendStringInfoChar(buf
, ']');
3204 appendStringInfoChar(buf
, ')');
3208 * Deparse a function call.
3211 deparseFuncExpr(FuncExpr
*node
, deparse_expr_cxt
*context
)
3213 StringInfo buf
= context
->buf
;
3219 * If the function call came from an implicit coercion, then just show the
3222 if (node
->funcformat
== COERCE_IMPLICIT_CAST
)
3224 deparseExpr((Expr
*) linitial(node
->args
), context
);
3229 * If the function call came from a cast, then show the first argument
3230 * plus an explicit cast operation.
3232 if (node
->funcformat
== COERCE_EXPLICIT_CAST
)
3234 Oid rettype
= node
->funcresulttype
;
3235 int32 coercedTypmod
;
3237 /* Get the typmod if this is a length-coercion function */
3238 (void) exprIsLengthCoercion((Node
*) node
, &coercedTypmod
);
3240 deparseExpr((Expr
*) linitial(node
->args
), context
);
3241 appendStringInfo(buf
, "::%s",
3242 deparse_type_name(rettype
, coercedTypmod
));
3246 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3247 use_variadic
= node
->funcvariadic
;
3250 * Normal function: display as proname(args).
3252 appendFunctionName(node
->funcid
, context
);
3253 appendStringInfoChar(buf
, '(');
3255 /* ... and all the arguments */
3257 foreach(arg
, node
->args
)
3260 appendStringInfoString(buf
, ", ");
3261 if (use_variadic
&& lnext(node
->args
, arg
) == NULL
)
3262 appendStringInfoString(buf
, "VARIADIC ");
3263 deparseExpr((Expr
*) lfirst(arg
), context
);
3266 appendStringInfoChar(buf
, ')');
3270 * Deparse given operator expression. To avoid problems around
3271 * priority of operations, we always parenthesize the arguments.
3274 deparseOpExpr(OpExpr
*node
, deparse_expr_cxt
*context
)
3276 StringInfo buf
= context
->buf
;
3278 Form_pg_operator form
;
3280 bool canSuppressRightConstCast
= false;
3283 /* Retrieve information about the operator from system catalog. */
3284 tuple
= SearchSysCache1(OPEROID
, ObjectIdGetDatum(node
->opno
));
3285 if (!HeapTupleIsValid(tuple
))
3286 elog(ERROR
, "cache lookup failed for operator %u", node
->opno
);
3287 form
= (Form_pg_operator
) GETSTRUCT(tuple
);
3288 oprkind
= form
->oprkind
;
3291 Assert((oprkind
== 'l' && list_length(node
->args
) == 1) ||
3292 (oprkind
== 'b' && list_length(node
->args
) == 2));
3294 right
= llast(node
->args
);
3296 /* Always parenthesize the expression. */
3297 appendStringInfoChar(buf
, '(');
3299 /* Deparse left operand, if any. */
3302 Expr
*left
= linitial(node
->args
);
3303 Oid leftType
= exprType((Node
*) left
);
3304 Oid rightType
= exprType((Node
*) right
);
3305 bool canSuppressLeftConstCast
= false;
3308 * When considering a binary operator, if one operand is a Const that
3309 * can be printed as a bare string literal or NULL (i.e., it will look
3310 * like type UNKNOWN to the remote parser), the Const normally
3311 * receives an explicit cast to the operator's input type. However,
3312 * in Const-to-Var comparisons where both operands are of the same
3313 * type, we prefer to suppress the explicit cast, leaving the Const's
3314 * type resolution up to the remote parser. The remote's resolution
3315 * heuristic will assume that an unknown input type being compared to
3316 * a known input type is of that known type as well.
3318 * This hack allows some cases to succeed where a remote column is
3319 * declared with a different type in the local (foreign) table. By
3320 * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3321 * like, we allow the remote parser to pick an "=" operator that's
3322 * compatible with whatever type the remote column really is, such as
3325 * We allow cast suppression to happen only when the other operand is
3326 * a plain foreign Var. Although the remote's unknown-type heuristic
3327 * would apply to other cases just as well, we would be taking a
3328 * bigger risk that the inferred type is something unexpected. With
3329 * this restriction, if anything goes wrong it's the user's fault for
3330 * not declaring the local column with the same type as the remote
3333 if (leftType
== rightType
)
3335 if (IsA(left
, Const
))
3336 canSuppressLeftConstCast
= isPlainForeignVar(right
, context
);
3337 else if (IsA(right
, Const
))
3338 canSuppressRightConstCast
= isPlainForeignVar(left
, context
);
3341 if (canSuppressLeftConstCast
)
3342 deparseConst((Const
*) left
, context
, -2);
3344 deparseExpr(left
, context
);
3346 appendStringInfoChar(buf
, ' ');
3349 /* Deparse operator name. */
3350 deparseOperatorName(buf
, form
);
3352 /* Deparse right operand. */
3353 appendStringInfoChar(buf
, ' ');
3355 if (canSuppressRightConstCast
)
3356 deparseConst((Const
*) right
, context
, -2);
3358 deparseExpr(right
, context
);
3360 appendStringInfoChar(buf
, ')');
3362 ReleaseSysCache(tuple
);
3366 * Will "node" deparse as a plain foreign Var?
3369 isPlainForeignVar(Expr
*node
, deparse_expr_cxt
*context
)
3372 * We allow the foreign Var to have an implicit RelabelType, mainly so
3373 * that this'll work with varchar columns. Note that deparseRelabelType
3374 * will not print such a cast, so we're not breaking the restriction that
3375 * the expression print as a plain Var. We won't risk it for an implicit
3376 * cast that requires a function, nor for non-implicit RelabelType; such
3377 * cases seem too likely to involve semantics changes compared to what
3378 * would happen on the remote side.
3380 if (IsA(node
, RelabelType
) &&
3381 ((RelabelType
*) node
)->relabelformat
== COERCE_IMPLICIT_CAST
)
3382 node
= ((RelabelType
*) node
)->arg
;
3387 * The Var must be one that'll deparse as a foreign column reference
3390 Var
*var
= (Var
*) node
;
3391 Relids relids
= context
->scanrel
->relids
;
3393 if (bms_is_member(var
->varno
, relids
) && var
->varlevelsup
== 0)
3401 * Print the name of an operator.
3404 deparseOperatorName(StringInfo buf
, Form_pg_operator opform
)
3408 /* opname is not a SQL identifier, so we should not quote it. */
3409 opname
= NameStr(opform
->oprname
);
3411 /* Print schema name only if it's not pg_catalog */
3412 if (opform
->oprnamespace
!= PG_CATALOG_NAMESPACE
)
3414 const char *opnspname
;
3416 opnspname
= get_namespace_name(opform
->oprnamespace
);
3417 /* Print fully qualified operator name. */
3418 appendStringInfo(buf
, "OPERATOR(%s.%s)",
3419 quote_identifier(opnspname
), opname
);
3423 /* Just print operator name. */
3424 appendStringInfoString(buf
, opname
);
3429 * Deparse IS DISTINCT FROM.
3432 deparseDistinctExpr(DistinctExpr
*node
, deparse_expr_cxt
*context
)
3434 StringInfo buf
= context
->buf
;
3436 Assert(list_length(node
->args
) == 2);
3438 appendStringInfoChar(buf
, '(');
3439 deparseExpr(linitial(node
->args
), context
);
3440 appendStringInfoString(buf
, " IS DISTINCT FROM ");
3441 deparseExpr(lsecond(node
->args
), context
);
3442 appendStringInfoChar(buf
, ')');
3446 * Deparse given ScalarArrayOpExpr expression. To avoid problems
3447 * around priority of operations, we always parenthesize the arguments.
3450 deparseScalarArrayOpExpr(ScalarArrayOpExpr
*node
, deparse_expr_cxt
*context
)
3452 StringInfo buf
= context
->buf
;
3454 Form_pg_operator form
;
3458 /* Retrieve information about the operator from system catalog. */
3459 tuple
= SearchSysCache1(OPEROID
, ObjectIdGetDatum(node
->opno
));
3460 if (!HeapTupleIsValid(tuple
))
3461 elog(ERROR
, "cache lookup failed for operator %u", node
->opno
);
3462 form
= (Form_pg_operator
) GETSTRUCT(tuple
);
3465 Assert(list_length(node
->args
) == 2);
3467 /* Always parenthesize the expression. */
3468 appendStringInfoChar(buf
, '(');
3470 /* Deparse left operand. */
3471 arg1
= linitial(node
->args
);
3472 deparseExpr(arg1
, context
);
3473 appendStringInfoChar(buf
, ' ');
3475 /* Deparse operator name plus decoration. */
3476 deparseOperatorName(buf
, form
);
3477 appendStringInfo(buf
, " %s (", node
->useOr
? "ANY" : "ALL");
3479 /* Deparse right operand. */
3480 arg2
= lsecond(node
->args
);
3481 deparseExpr(arg2
, context
);
3483 appendStringInfoChar(buf
, ')');
3485 /* Always parenthesize the expression. */
3486 appendStringInfoChar(buf
, ')');
3488 ReleaseSysCache(tuple
);
3492 * Deparse a RelabelType (binary-compatible cast) node.
3495 deparseRelabelType(RelabelType
*node
, deparse_expr_cxt
*context
)
3497 deparseExpr(node
->arg
, context
);
3498 if (node
->relabelformat
!= COERCE_IMPLICIT_CAST
)
3499 appendStringInfo(context
->buf
, "::%s",
3500 deparse_type_name(node
->resulttype
,
3501 node
->resulttypmod
));
3505 * Deparse a BoolExpr node.
3508 deparseBoolExpr(BoolExpr
*node
, deparse_expr_cxt
*context
)
3510 StringInfo buf
= context
->buf
;
3511 const char *op
= NULL
; /* keep compiler quiet */
3515 switch (node
->boolop
)
3524 appendStringInfoString(buf
, "(NOT ");
3525 deparseExpr(linitial(node
->args
), context
);
3526 appendStringInfoChar(buf
, ')');
3530 appendStringInfoChar(buf
, '(');
3532 foreach(lc
, node
->args
)
3535 appendStringInfo(buf
, " %s ", op
);
3536 deparseExpr((Expr
*) lfirst(lc
), context
);
3539 appendStringInfoChar(buf
, ')');
3543 * Deparse IS [NOT] NULL expression.
3546 deparseNullTest(NullTest
*node
, deparse_expr_cxt
*context
)
3548 StringInfo buf
= context
->buf
;
3550 appendStringInfoChar(buf
, '(');
3551 deparseExpr(node
->arg
, context
);
3554 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3555 * shorter and traditional. If it's a rowtype input but we're applying a
3556 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3559 if (node
->argisrow
|| !type_is_rowtype(exprType((Node
*) node
->arg
)))
3561 if (node
->nulltesttype
== IS_NULL
)
3562 appendStringInfoString(buf
, " IS NULL)");
3564 appendStringInfoString(buf
, " IS NOT NULL)");
3568 if (node
->nulltesttype
== IS_NULL
)
3569 appendStringInfoString(buf
, " IS NOT DISTINCT FROM NULL)");
3571 appendStringInfoString(buf
, " IS DISTINCT FROM NULL)");
3576 * Deparse CASE expression
3579 deparseCaseExpr(CaseExpr
*node
, deparse_expr_cxt
*context
)
3581 StringInfo buf
= context
->buf
;
3584 appendStringInfoString(buf
, "(CASE");
3586 /* If this is a CASE arg WHEN then emit the arg expression */
3587 if (node
->arg
!= NULL
)
3589 appendStringInfoChar(buf
, ' ');
3590 deparseExpr(node
->arg
, context
);
3593 /* Add each condition/result of the CASE clause */
3594 foreach(lc
, node
->args
)
3596 CaseWhen
*whenclause
= (CaseWhen
*) lfirst(lc
);
3599 appendStringInfoString(buf
, " WHEN ");
3600 if (node
->arg
== NULL
) /* CASE WHEN */
3601 deparseExpr(whenclause
->expr
, context
);
3602 else /* CASE arg WHEN */
3604 /* Ignore the CaseTestExpr and equality operator. */
3605 deparseExpr(lsecond(castNode(OpExpr
, whenclause
->expr
)->args
),
3610 appendStringInfoString(buf
, " THEN ");
3611 deparseExpr(whenclause
->result
, context
);
3614 /* add ELSE if present */
3615 if (node
->defresult
!= NULL
)
3617 appendStringInfoString(buf
, " ELSE ");
3618 deparseExpr(node
->defresult
, context
);
3622 appendStringInfoString(buf
, " END)");
3626 * Deparse ARRAY[...] construct.
3629 deparseArrayExpr(ArrayExpr
*node
, deparse_expr_cxt
*context
)
3631 StringInfo buf
= context
->buf
;
3635 appendStringInfoString(buf
, "ARRAY[");
3636 foreach(lc
, node
->elements
)
3639 appendStringInfoString(buf
, ", ");
3640 deparseExpr(lfirst(lc
), context
);
3643 appendStringInfoChar(buf
, ']');
3645 /* If the array is empty, we need an explicit cast to the array type. */
3646 if (node
->elements
== NIL
)
3647 appendStringInfo(buf
, "::%s",
3648 deparse_type_name(node
->array_typeid
, -1));
3652 * Deparse an Aggref node.
3655 deparseAggref(Aggref
*node
, deparse_expr_cxt
*context
)
3657 StringInfo buf
= context
->buf
;
3660 /* Only basic, non-split aggregation accepted. */
3661 Assert(node
->aggsplit
== AGGSPLIT_SIMPLE
);
3663 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3664 use_variadic
= node
->aggvariadic
;
3666 /* Find aggregate name from aggfnoid which is a pg_proc entry */
3667 appendFunctionName(node
->aggfnoid
, context
);
3668 appendStringInfoChar(buf
, '(');
3671 appendStringInfoString(buf
, (node
->aggdistinct
!= NIL
) ? "DISTINCT " : "");
3673 if (AGGKIND_IS_ORDERED_SET(node
->aggkind
))
3675 /* Add WITHIN GROUP (ORDER BY ..) */
3679 Assert(!node
->aggvariadic
);
3680 Assert(node
->aggorder
!= NIL
);
3682 foreach(arg
, node
->aggdirectargs
)
3685 appendStringInfoString(buf
, ", ");
3688 deparseExpr((Expr
*) lfirst(arg
), context
);
3691 appendStringInfoString(buf
, ") WITHIN GROUP (ORDER BY ");
3692 appendAggOrderBy(node
->aggorder
, node
->args
, context
);
3696 /* aggstar can be set only in zero-argument aggregates */
3698 appendStringInfoChar(buf
, '*');
3704 /* Add all the arguments */
3705 foreach(arg
, node
->args
)
3707 TargetEntry
*tle
= (TargetEntry
*) lfirst(arg
);
3708 Node
*n
= (Node
*) tle
->expr
;
3714 appendStringInfoString(buf
, ", ");
3718 if (use_variadic
&& lnext(node
->args
, arg
) == NULL
)
3719 appendStringInfoString(buf
, "VARIADIC ");
3721 deparseExpr((Expr
*) n
, context
);
3726 if (node
->aggorder
!= NIL
)
3728 appendStringInfoString(buf
, " ORDER BY ");
3729 appendAggOrderBy(node
->aggorder
, node
->args
, context
);
3733 /* Add FILTER (WHERE ..) */
3734 if (node
->aggfilter
!= NULL
)
3736 appendStringInfoString(buf
, ") FILTER (WHERE ");
3737 deparseExpr((Expr
*) node
->aggfilter
, context
);
3740 appendStringInfoChar(buf
, ')');
3744 * Append ORDER BY within aggregate function.
3747 appendAggOrderBy(List
*orderList
, List
*targetList
, deparse_expr_cxt
*context
)
3749 StringInfo buf
= context
->buf
;
3753 foreach(lc
, orderList
)
3755 SortGroupClause
*srt
= (SortGroupClause
*) lfirst(lc
);
3759 appendStringInfoString(buf
, ", ");
3762 /* Deparse the sort expression proper. */
3763 sortexpr
= deparseSortGroupClause(srt
->tleSortGroupRef
, targetList
,
3765 /* Add decoration as needed. */
3766 appendOrderBySuffix(srt
->sortop
, exprType(sortexpr
), srt
->nulls_first
,
3772 * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
3773 * of an ORDER BY clause.
3776 appendOrderBySuffix(Oid sortop
, Oid sortcoltype
, bool nulls_first
,
3777 deparse_expr_cxt
*context
)
3779 StringInfo buf
= context
->buf
;
3780 TypeCacheEntry
*typentry
;
3782 /* See whether operator is default < or > for sort expr's datatype. */
3783 typentry
= lookup_type_cache(sortcoltype
,
3784 TYPECACHE_LT_OPR
| TYPECACHE_GT_OPR
);
3786 if (sortop
== typentry
->lt_opr
)
3787 appendStringInfoString(buf
, " ASC");
3788 else if (sortop
== typentry
->gt_opr
)
3789 appendStringInfoString(buf
, " DESC");
3793 Form_pg_operator operform
;
3795 appendStringInfoString(buf
, " USING ");
3797 /* Append operator name. */
3798 opertup
= SearchSysCache1(OPEROID
, ObjectIdGetDatum(sortop
));
3799 if (!HeapTupleIsValid(opertup
))
3800 elog(ERROR
, "cache lookup failed for operator %u", sortop
);
3801 operform
= (Form_pg_operator
) GETSTRUCT(opertup
);
3802 deparseOperatorName(buf
, operform
);
3803 ReleaseSysCache(opertup
);
3807 appendStringInfoString(buf
, " NULLS FIRST");
3809 appendStringInfoString(buf
, " NULLS LAST");
3813 * Print the representation of a parameter to be sent to the remote side.
3815 * Note: we always label the Param's type explicitly rather than relying on
3816 * transmitting a numeric type OID in PQsendQueryParams(). This allows us to
3817 * avoid assuming that types have the same OIDs on the remote side as they
3818 * do locally --- they need only have the same names.
3821 printRemoteParam(int paramindex
, Oid paramtype
, int32 paramtypmod
,
3822 deparse_expr_cxt
*context
)
3824 StringInfo buf
= context
->buf
;
3825 char *ptypename
= deparse_type_name(paramtype
, paramtypmod
);
3827 appendStringInfo(buf
, "$%d::%s", paramindex
, ptypename
);
3831 * Print the representation of a placeholder for a parameter that will be
3832 * sent to the remote side at execution time.
3834 * This is used when we're just trying to EXPLAIN the remote query.
3835 * We don't have the actual value of the runtime parameter yet, and we don't
3836 * want the remote planner to generate a plan that depends on such a value
3837 * anyway. Thus, we can't do something simple like "$1::paramtype".
3838 * Instead, we emit "((SELECT null::paramtype)::paramtype)".
3839 * In all extant versions of Postgres, the planner will see that as an unknown
3840 * constant value, which is what we want. This might need adjustment if we
3841 * ever make the planner flatten scalar subqueries. Note: the reason for the
3842 * apparently useless outer cast is to ensure that the representation as a
3843 * whole will be parsed as an a_expr and not a select_with_parens; the latter
3844 * would do the wrong thing in the context "x = ANY(...)".
3847 printRemotePlaceholder(Oid paramtype
, int32 paramtypmod
,
3848 deparse_expr_cxt
*context
)
3850 StringInfo buf
= context
->buf
;
3851 char *ptypename
= deparse_type_name(paramtype
, paramtypmod
);
3853 appendStringInfo(buf
, "((SELECT null::%s)::%s)", ptypename
, ptypename
);
3857 * Deparse GROUP BY clause.
3860 appendGroupByClause(List
*tlist
, deparse_expr_cxt
*context
)
3862 StringInfo buf
= context
->buf
;
3863 Query
*query
= context
->root
->parse
;
3867 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3868 if (!query
->groupClause
)
3871 appendStringInfoString(buf
, " GROUP BY ");
3874 * Queries with grouping sets are not pushed down, so we don't expect
3875 * grouping sets here.
3877 Assert(!query
->groupingSets
);
3880 * We intentionally print query->groupClause not processed_groupClause,
3881 * leaving it to the remote planner to get rid of any redundant GROUP BY
3882 * items again. This is necessary in case processed_groupClause reduced
3883 * to empty, and in any case the redundancy situation on the remote might
3884 * be different than what we think here.
3886 foreach(lc
, query
->groupClause
)
3888 SortGroupClause
*grp
= (SortGroupClause
*) lfirst(lc
);
3891 appendStringInfoString(buf
, ", ");
3894 deparseSortGroupClause(grp
->tleSortGroupRef
, tlist
, true, context
);
3899 * Deparse ORDER BY clause defined by the given pathkeys.
3901 * The clause should use Vars from context->scanrel if !has_final_sort,
3902 * or from context->foreignrel's targetlist if has_final_sort.
3904 * We find a suitable pathkey expression (some earlier step
3905 * should have verified that there is one) and deparse it.
3908 appendOrderByClause(List
*pathkeys
, bool has_final_sort
,
3909 deparse_expr_cxt
*context
)
3913 StringInfo buf
= context
->buf
;
3914 bool gotone
= false;
3916 /* Make sure any constants in the exprs are printed portably */
3917 nestlevel
= set_transmission_modes();
3919 foreach(lcell
, pathkeys
)
3921 PathKey
*pathkey
= lfirst(lcell
);
3922 EquivalenceMember
*em
;
3929 * By construction, context->foreignrel is the input relation to
3932 em
= find_em_for_rel_target(context
->root
,
3934 context
->foreignrel
);
3937 em
= find_em_for_rel(context
->root
,
3942 * We don't expect any error here; it would mean that shippability
3943 * wasn't verified earlier. For the same reason, we don't recheck
3944 * shippability of the sort operator.
3947 elog(ERROR
, "could not find pathkey item to sort");
3949 em_expr
= em
->em_expr
;
3952 * If the member is a Const expression then we needn't add it to the
3953 * ORDER BY clause. This can happen in UNION ALL queries where the
3954 * union child targetlist has a Const. Adding these would be
3955 * wasteful, but also, for INT columns, an integer literal would be
3956 * seen as an ordinal column position rather than a value to sort by.
3957 * deparseConst() does have code to handle this, but it seems less
3958 * effort on all accounts just to skip these for ORDER BY clauses.
3960 if (IsA(em_expr
, Const
))
3965 appendStringInfoString(buf
, " ORDER BY ");
3969 appendStringInfoString(buf
, ", ");
3972 * Lookup the operator corresponding to the strategy in the opclass.
3973 * The datatype used by the opfamily is not necessarily the same as
3974 * the expression type (for array types for example).
3976 oprid
= get_opfamily_member(pathkey
->pk_opfamily
,
3979 pathkey
->pk_strategy
);
3980 if (!OidIsValid(oprid
))
3981 elog(ERROR
, "missing operator %d(%u,%u) in opfamily %u",
3982 pathkey
->pk_strategy
, em
->em_datatype
, em
->em_datatype
,
3983 pathkey
->pk_opfamily
);
3985 deparseExpr(em_expr
, context
);
3988 * Here we need to use the expression's actual type to discover
3989 * whether the desired operator will be the default or not.
3991 appendOrderBySuffix(oprid
, exprType((Node
*) em_expr
),
3992 pathkey
->pk_nulls_first
, context
);
3995 reset_transmission_modes(nestlevel
);
3999 * Deparse LIMIT/OFFSET clause.
4002 appendLimitClause(deparse_expr_cxt
*context
)
4004 PlannerInfo
*root
= context
->root
;
4005 StringInfo buf
= context
->buf
;
4008 /* Make sure any constants in the exprs are printed portably */
4009 nestlevel
= set_transmission_modes();
4011 if (root
->parse
->limitCount
)
4013 appendStringInfoString(buf
, " LIMIT ");
4014 deparseExpr((Expr
*) root
->parse
->limitCount
, context
);
4016 if (root
->parse
->limitOffset
)
4018 appendStringInfoString(buf
, " OFFSET ");
4019 deparseExpr((Expr
*) root
->parse
->limitOffset
, context
);
4022 reset_transmission_modes(nestlevel
);
4026 * appendFunctionName
4027 * Deparses function name from given function oid.
4030 appendFunctionName(Oid funcid
, deparse_expr_cxt
*context
)
4032 StringInfo buf
= context
->buf
;
4034 Form_pg_proc procform
;
4035 const char *proname
;
4037 proctup
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(funcid
));
4038 if (!HeapTupleIsValid(proctup
))
4039 elog(ERROR
, "cache lookup failed for function %u", funcid
);
4040 procform
= (Form_pg_proc
) GETSTRUCT(proctup
);
4042 /* Print schema name only if it's not pg_catalog */
4043 if (procform
->pronamespace
!= PG_CATALOG_NAMESPACE
)
4045 const char *schemaname
;
4047 schemaname
= get_namespace_name(procform
->pronamespace
);
4048 appendStringInfo(buf
, "%s.", quote_identifier(schemaname
));
4051 /* Always print the function name */
4052 proname
= NameStr(procform
->proname
);
4053 appendStringInfoString(buf
, quote_identifier(proname
));
4055 ReleaseSysCache(proctup
);
4059 * Appends a sort or group clause.
4061 * Like get_rule_sortgroupclause(), returns the expression tree, so caller
4062 * need not find it again.
4065 deparseSortGroupClause(Index ref
, List
*tlist
, bool force_colno
,
4066 deparse_expr_cxt
*context
)
4068 StringInfo buf
= context
->buf
;
4072 tle
= get_sortgroupref_tle(ref
, tlist
);
4077 /* Use column-number form when requested by caller. */
4078 Assert(!tle
->resjunk
);
4079 appendStringInfo(buf
, "%d", tle
->resno
);
4081 else if (expr
&& IsA(expr
, Const
))
4084 * Force a typecast here so that we don't emit something like "GROUP
4085 * BY 2", which will be misconstrued as a column position rather than
4088 deparseConst((Const
*) expr
, context
, 1);
4090 else if (!expr
|| IsA(expr
, Var
))
4091 deparseExpr(expr
, context
);
4094 /* Always parenthesize the expression. */
4095 appendStringInfoChar(buf
, '(');
4096 deparseExpr(expr
, context
);
4097 appendStringInfoChar(buf
, ')');
4100 return (Node
*) expr
;
4105 * Returns true if given Var is deparsed as a subquery output column, in
4106 * which case, *relno and *colno are set to the IDs for the relation and
4107 * column alias to the Var provided by the subquery.
4110 is_subquery_var(Var
*node
, RelOptInfo
*foreignrel
, int *relno
, int *colno
)
4112 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
4113 RelOptInfo
*outerrel
= fpinfo
->outerrel
;
4114 RelOptInfo
*innerrel
= fpinfo
->innerrel
;
4116 /* Should only be called in these cases. */
4117 Assert(IS_SIMPLE_REL(foreignrel
) || IS_JOIN_REL(foreignrel
));
4120 * If the given relation isn't a join relation, it doesn't have any lower
4121 * subqueries, so the Var isn't a subquery output column.
4123 if (!IS_JOIN_REL(foreignrel
))
4127 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
4130 if (!bms_is_member(node
->varno
, fpinfo
->lower_subquery_rels
))
4133 if (bms_is_member(node
->varno
, outerrel
->relids
))
4136 * If outer relation is deparsed as a subquery, the Var is an output
4137 * column of the subquery; get the IDs for the relation/column alias.
4139 if (fpinfo
->make_outerrel_subquery
)
4141 get_relation_column_alias_ids(node
, outerrel
, relno
, colno
);
4145 /* Otherwise, recurse into the outer relation. */
4146 return is_subquery_var(node
, outerrel
, relno
, colno
);
4150 Assert(bms_is_member(node
->varno
, innerrel
->relids
));
4153 * If inner relation is deparsed as a subquery, the Var is an output
4154 * column of the subquery; get the IDs for the relation/column alias.
4156 if (fpinfo
->make_innerrel_subquery
)
4158 get_relation_column_alias_ids(node
, innerrel
, relno
, colno
);
4162 /* Otherwise, recurse into the inner relation. */
4163 return is_subquery_var(node
, innerrel
, relno
, colno
);
4168 * Get the IDs for the relation and column alias to given Var belonging to
4169 * given relation, which are returned into *relno and *colno.
4172 get_relation_column_alias_ids(Var
*node
, RelOptInfo
*foreignrel
,
4173 int *relno
, int *colno
)
4175 PgFdwRelationInfo
*fpinfo
= (PgFdwRelationInfo
*) foreignrel
->fdw_private
;
4179 /* Get the relation alias ID */
4180 *relno
= fpinfo
->relation_index
;
4182 /* Get the column alias ID */
4184 foreach(lc
, foreignrel
->reltarget
->exprs
)
4186 Var
*tlvar
= (Var
*) lfirst(lc
);
4189 * Match reltarget entries only on varno/varattno. Ideally there
4190 * would be some cross-check on varnullingrels, but it's unclear what
4191 * to do exactly; we don't have enough context to know what that value
4194 if (IsA(tlvar
, Var
) &&
4195 tlvar
->varno
== node
->varno
&&
4196 tlvar
->varattno
== node
->varattno
)
4204 /* Shouldn't get here */
4205 elog(ERROR
, "unexpected expression in subquery output");