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

Generated by: LCOV version 1.14