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

Generated by: LCOV version 1.13