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

Generated by: LCOV version 1.13