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

Generated by: LCOV version 1.16