LCOV - code coverage report
Current view: top level - contrib/postgres_fdw - deparse.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 1107 1221 90.7 %
Date: 2021-05-13 09:07:15 Functions: 55 55 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13