LCOV - code coverage report
Current view: top level - contrib/postgres_fdw - deparse.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.2 % 1487 1311
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 62 62
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-2026, 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         2508 : classifyConditions(PlannerInfo *root,
     219              :                    RelOptInfo *baserel,
     220              :                    List *input_conds,
     221              :                    List **remote_conds,
     222              :                    List **local_conds)
     223              : {
     224              :     ListCell   *lc;
     225              : 
     226         2508 :     *remote_conds = NIL;
     227         2508 :     *local_conds = NIL;
     228              : 
     229         3272 :     foreach(lc, input_conds)
     230              :     {
     231          764 :         RestrictInfo *ri = lfirst_node(RestrictInfo, lc);
     232              : 
     233          764 :         if (is_foreign_expr(root, baserel, ri->clause))
     234          681 :             *remote_conds = lappend(*remote_conds, ri);
     235              :         else
     236           83 :             *local_conds = lappend(*local_conds, ri);
     237              :     }
     238         2508 : }
     239              : 
     240              : /*
     241              :  * Returns true if given expr is safe to evaluate on the foreign server.
     242              :  */
     243              : bool
     244         3810 : 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         3810 :     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         3810 :     glob_cxt.root = root;
     257         3810 :     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         3810 :     if (IS_UPPER_REL(baserel))
     265          453 :         glob_cxt.relids = fpinfo->outerrel->relids;
     266              :     else
     267         3357 :         glob_cxt.relids = baserel->relids;
     268         3810 :     loc_cxt.collation = InvalidOid;
     269         3810 :     loc_cxt.state = FDW_COLLATE_NONE;
     270         3810 :     if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt, NULL))
     271          150 :         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         3660 :     if (loc_cxt.state == FDW_COLLATE_UNSAFE)
     278            2 :         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         3658 :     if (contain_mutable_functions((Node *) expr))
     288           24 :         return false;
     289              : 
     290              :     /* OK to evaluate on the remote server */
     291         3634 :     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         9511 : 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         9511 :     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         9511 :     if (node == NULL)
     325          330 :         return true;
     326              : 
     327              :     /* May need server info from baserel's fdw_private struct */
     328         9181 :     fpinfo = (PgFdwRelationInfo *) (glob_cxt->foreignrel->fdw_private);
     329              : 
     330              :     /* Set up inner_cxt for possible recursion to child nodes */
     331         9181 :     inner_cxt.collation = InvalidOid;
     332         9181 :     inner_cxt.state = FDW_COLLATE_NONE;
     333              : 
     334         9181 :     switch (nodeTag(node))
     335              :     {
     336         4250 :         case T_Var:
     337              :             {
     338         4250 :                 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         4250 :                 if (bms_is_member(var->varno, glob_cxt->relids) &&
     348         3785 :                     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         3785 :                     if (var->varattno < 0 &&
     359           10 :                         var->varattno != SelfItemPointerAttributeNumber)
     360            8 :                         return false;
     361              : 
     362              :                     /* Else check the collation */
     363         3777 :                     collation = var->varcollid;
     364         3777 :                     state = OidIsValid(collation) ? FDW_COLLATE_SAFE : FDW_COLLATE_NONE;
     365              :                 }
     366              :                 else
     367              :                 {
     368              :                     /* Var belongs to some other table */
     369          465 :                     collation = var->varcollid;
     370          465 :                     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          465 :                         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         4242 :             break;
     390          926 :         case T_Const:
     391              :             {
     392          926 :                 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          926 :                 if (!c->constisnull)
     400              :                 {
     401          917 :                     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            4 :                         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            4 :                             if (DatumGetObjectId(c->constvalue) >= FirstNormalObjectId &&
     440            4 :                                 !is_shippable(DatumGetObjectId(c->constvalue),
     441              :                                               TSConfigRelationId, fpinfo))
     442            2 :                                 return false;
     443            2 :                             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          924 :                 collation = c->constcollid;
     475          924 :                 if (collation == InvalidOid ||
     476              :                     collation == DEFAULT_COLLATION_OID)
     477          922 :                     state = FDW_COLLATE_NONE;
     478              :                 else
     479            2 :                     state = FDW_COLLATE_UNSAFE;
     480              :             }
     481          924 :             break;
     482           30 :         case T_Param:
     483              :             {
     484           30 :                 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           30 :                 if (p->paramkind == PARAM_MULTIEXPR)
     500            3 :                     return false;
     501              : 
     502              :                 /*
     503              :                  * Collation rule is same as for Consts and non-foreign Vars.
     504              :                  */
     505           27 :                 collation = p->paramcollid;
     506           27 :                 if (collation == InvalidOid ||
     507              :                     collation == DEFAULT_COLLATION_OID)
     508           27 :                     state = FDW_COLLATE_NONE;
     509              :                 else
     510            0 :                     state = FDW_COLLATE_UNSAFE;
     511              :             }
     512           27 :             break;
     513            1 :         case T_SubscriptingRef:
     514              :             {
     515            1 :                 SubscriptingRef *sr = (SubscriptingRef *) node;
     516              : 
     517              :                 /* Assignment should not be in restrictions. */
     518            1 :                 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            1 :                 if (!foreign_expr_walker((Node *) sr->refupperindexpr,
     527              :                                          glob_cxt, &inner_cxt, case_arg_cxt))
     528            0 :                     return false;
     529            1 :                 inner_cxt.collation = InvalidOid;
     530            1 :                 inner_cxt.state = FDW_COLLATE_NONE;
     531            1 :                 if (!foreign_expr_walker((Node *) sr->reflowerindexpr,
     532              :                                          glob_cxt, &inner_cxt, case_arg_cxt))
     533            0 :                     return false;
     534            1 :                 inner_cxt.collation = InvalidOid;
     535            1 :                 inner_cxt.state = FDW_COLLATE_NONE;
     536            1 :                 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            1 :                 collation = sr->refcollid;
     546            1 :                 if (collation == InvalidOid)
     547            1 :                     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            1 :             break;
     557          134 :         case T_FuncExpr:
     558              :             {
     559          134 :                 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          134 :                 if (!is_shippable(fe->funcid, ProcedureRelationId, fpinfo))
     567            8 :                     return false;
     568              : 
     569              :                 /*
     570              :                  * Recurse to input subexpressions.
     571              :                  */
     572          126 :                 if (!foreign_expr_walker((Node *) fe->args,
     573              :                                          glob_cxt, &inner_cxt, case_arg_cxt))
     574           13 :                     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          113 :                 if (fe->inputcollid == InvalidOid)
     581              :                      /* OK, inputs are all noncollatable */ ;
     582           33 :                 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
     583           20 :                          fe->inputcollid != inner_cxt.collation)
     584           13 :                     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          100 :                 collation = fe->funccollid;
     593          100 :                 if (collation == InvalidOid)
     594           81 :                     state = FDW_COLLATE_NONE;
     595           19 :                 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
     596           18 :                          collation == inner_cxt.collation)
     597           18 :                     state = FDW_COLLATE_SAFE;
     598            1 :                 else if (collation == DEFAULT_COLLATION_OID)
     599            0 :                     state = FDW_COLLATE_NONE;
     600              :                 else
     601            1 :                     state = FDW_COLLATE_UNSAFE;
     602              :             }
     603          100 :             break;
     604         1622 :         case T_OpExpr:
     605              :         case T_DistinctExpr:    /* struct-equivalent to OpExpr */
     606              :             {
     607         1622 :                 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         1622 :                 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
     615           47 :                     return false;
     616              : 
     617              :                 /*
     618              :                  * Recurse to input subexpressions.
     619              :                  */
     620         1575 :                 if (!foreign_expr_walker((Node *) oe->args,
     621              :                                          glob_cxt, &inner_cxt, case_arg_cxt))
     622           63 :                     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         1512 :                 if (oe->inputcollid == InvalidOid)
     629              :                      /* OK, inputs are all noncollatable */ ;
     630           70 :                 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
     631           64 :                          oe->inputcollid != inner_cxt.collation)
     632            6 :                     return false;
     633              : 
     634              :                 /* Result-collation handling is same as for functions */
     635         1506 :                 collation = oe->opcollid;
     636         1506 :                 if (collation == InvalidOid)
     637         1492 :                     state = FDW_COLLATE_NONE;
     638           14 :                 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
     639           14 :                          collation == inner_cxt.collation)
     640           14 :                     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         1506 :             break;
     647            4 :         case T_ScalarArrayOpExpr:
     648              :             {
     649            4 :                 ScalarArrayOpExpr *oe = (ScalarArrayOpExpr *) node;
     650              : 
     651              :                 /*
     652              :                  * Again, only shippable operators can be sent to remote.
     653              :                  */
     654            4 :                 if (!is_shippable(oe->opno, OperatorRelationId, fpinfo))
     655            0 :                     return false;
     656              : 
     657              :                 /*
     658              :                  * Recurse to input subexpressions.
     659              :                  */
     660            4 :                 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            4 :                 if (oe->inputcollid == InvalidOid)
     669              :                      /* OK, inputs are all noncollatable */ ;
     670            1 :                 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
     671            1 :                          oe->inputcollid != inner_cxt.collation)
     672            0 :                     return false;
     673              : 
     674              :                 /* Output is always boolean and so noncollatable. */
     675            4 :                 collation = InvalidOid;
     676            4 :                 state = FDW_COLLATE_NONE;
     677              :             }
     678            4 :             break;
     679           69 :         case T_RelabelType:
     680              :             {
     681           69 :                 RelabelType *r = (RelabelType *) node;
     682              : 
     683              :                 /*
     684              :                  * Recurse to input subexpression.
     685              :                  */
     686           69 :                 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           69 :                 collation = r->resultcollid;
     695           69 :                 if (collation == InvalidOid)
     696            0 :                     state = FDW_COLLATE_NONE;
     697           69 :                 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
     698           65 :                          collation == inner_cxt.collation)
     699           59 :                     state = FDW_COLLATE_SAFE;
     700           10 :                 else if (collation == DEFAULT_COLLATION_OID)
     701            3 :                     state = FDW_COLLATE_NONE;
     702              :                 else
     703            7 :                     state = FDW_COLLATE_UNSAFE;
     704              :             }
     705           69 :             break;
     706            1 :         case T_ArrayCoerceExpr:
     707              :             {
     708            1 :                 ArrayCoerceExpr *e = (ArrayCoerceExpr *) node;
     709              : 
     710              :                 /*
     711              :                  * Recurse to input subexpression.
     712              :                  */
     713            1 :                 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            1 :                 collation = e->resultcollid;
     723            1 :                 if (collation == InvalidOid)
     724            0 :                     state = FDW_COLLATE_NONE;
     725            1 :                 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
     726            0 :                          collation == inner_cxt.collation)
     727            0 :                     state = FDW_COLLATE_SAFE;
     728            1 :                 else if (collation == DEFAULT_COLLATION_OID)
     729            1 :                     state = FDW_COLLATE_NONE;
     730              :                 else
     731            0 :                     state = FDW_COLLATE_UNSAFE;
     732              :             }
     733            1 :             break;
     734           36 :         case T_BoolExpr:
     735              :             {
     736           36 :                 BoolExpr   *b = (BoolExpr *) node;
     737              : 
     738              :                 /*
     739              :                  * Recurse to input subexpressions.
     740              :                  */
     741           36 :                 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           36 :                 collation = InvalidOid;
     747           36 :                 state = FDW_COLLATE_NONE;
     748              :             }
     749           36 :             break;
     750           25 :         case T_NullTest:
     751              :             {
     752           25 :                 NullTest   *nt = (NullTest *) node;
     753              : 
     754              :                 /*
     755              :                  * Recurse to input subexpressions.
     756              :                  */
     757           25 :                 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           25 :                 collation = InvalidOid;
     763           25 :                 state = FDW_COLLATE_NONE;
     764              :             }
     765           25 :             break;
     766           13 :         case T_CaseExpr:
     767              :             {
     768           13 :                 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           13 :                 arg_cxt.collation = InvalidOid;
     779           13 :                 arg_cxt.state = FDW_COLLATE_NONE;
     780           13 :                 if (ce->arg)
     781              :                 {
     782            7 :                     if (!foreign_expr_walker((Node *) ce->arg,
     783              :                                              glob_cxt, &arg_cxt, case_arg_cxt))
     784            1 :                         return false;
     785              :                 }
     786              : 
     787              :                 /* Examine the CaseWhen subexpressions. */
     788           29 :                 foreach(lc, ce->args)
     789              :                 {
     790           17 :                     CaseWhen   *cw = lfirst_node(CaseWhen, lc);
     791              : 
     792           17 :                     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           11 :                         Node       *whenExpr = (Node *) cw->expr;
     806              :                         List       *opArgs;
     807              : 
     808           11 :                         if (!IsA(whenExpr, OpExpr))
     809            1 :                             return false;
     810              : 
     811           11 :                         opArgs = ((OpExpr *) whenExpr)->args;
     812           11 :                         if (list_length(opArgs) != 2 ||
     813           11 :                             !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           17 :                     tmp_cxt.collation = InvalidOid;
     824           17 :                     tmp_cxt.state = FDW_COLLATE_NONE;
     825           17 :                     if (!foreign_expr_walker((Node *) cw->expr,
     826              :                                              glob_cxt, &tmp_cxt, &arg_cxt))
     827            1 :                         return false;
     828              : 
     829              :                     /* Recurse to THEN expression. */
     830           16 :                     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           12 :                 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           12 :                 collation = ce->casecollid;
     849           12 :                 if (collation == InvalidOid)
     850           12 :                     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           12 :             break;
     860           11 :         case T_CaseTestExpr:
     861              :             {
     862           11 :                 CaseTestExpr *c = (CaseTestExpr *) node;
     863              : 
     864              :                 /* Punt if we seem not to be inside a CASE arg WHEN. */
     865           11 :                 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           11 :                 collation = c->collation;
     874           11 :                 if (collation == InvalidOid)
     875            8 :                     state = FDW_COLLATE_NONE;
     876            3 :                 else if (case_arg_cxt->state == FDW_COLLATE_SAFE &&
     877            2 :                          collation == case_arg_cxt->collation)
     878            2 :                     state = FDW_COLLATE_SAFE;
     879            1 :                 else if (collation == DEFAULT_COLLATION_OID)
     880            0 :                     state = FDW_COLLATE_NONE;
     881              :                 else
     882            1 :                     state = FDW_COLLATE_UNSAFE;
     883              :             }
     884           11 :             break;
     885            4 :         case T_ArrayExpr:
     886              :             {
     887            4 :                 ArrayExpr  *a = (ArrayExpr *) node;
     888              : 
     889              :                 /*
     890              :                  * Recurse to input subexpressions.
     891              :                  */
     892            4 :                 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            4 :                 collation = a->array_collid;
     901            4 :                 if (collation == InvalidOid)
     902            4 :                     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            4 :             break;
     912         1745 :         case T_List:
     913              :             {
     914         1745 :                 List       *l = (List *) node;
     915              :                 ListCell   *lc;
     916              : 
     917              :                 /*
     918              :                  * Recurse to component subexpressions.
     919              :                  */
     920         4975 :                 foreach(lc, l)
     921              :                 {
     922         3319 :                     if (!foreign_expr_walker((Node *) lfirst(lc),
     923              :                                              glob_cxt, &inner_cxt, case_arg_cxt))
     924           89 :                         return false;
     925              :                 }
     926              : 
     927              :                 /*
     928              :                  * When processing a list, collation state just bubbles up
     929              :                  * from the list elements.
     930              :                  */
     931         1656 :                 collation = inner_cxt.collation;
     932         1656 :                 state = inner_cxt.state;
     933              : 
     934              :                 /* Don't apply exprType() to the list. */
     935         1656 :                 check_type = false;
     936              :             }
     937         1656 :             break;
     938          280 :         case T_Aggref:
     939              :             {
     940          280 :                 Aggref     *agg = (Aggref *) node;
     941              :                 ListCell   *lc;
     942              : 
     943              :                 /* Not safe to pushdown when not in grouping context */
     944          280 :                 if (!IS_UPPER_REL(glob_cxt->foreignrel))
     945            0 :                     return false;
     946              : 
     947              :                 /* Only non-split aggregates are pushable. */
     948          280 :                 if (agg->aggsplit != AGGSPLIT_SIMPLE)
     949            0 :                     return false;
     950              : 
     951              :                 /* As usual, it must be shippable. */
     952          280 :                 if (!is_shippable(agg->aggfnoid, ProcedureRelationId, fpinfo))
     953            4 :                     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          491 :                 foreach(lc, agg->args)
     961              :                 {
     962          227 :                     Node       *n = (Node *) lfirst(lc);
     963              : 
     964              :                     /* If TargetEntry, extract the expression from it */
     965          227 :                     if (IsA(n, TargetEntry))
     966              :                     {
     967          227 :                         TargetEntry *tle = (TargetEntry *) n;
     968              : 
     969          227 :                         n = (Node *) tle->expr;
     970              :                     }
     971              : 
     972          227 :                     if (!foreign_expr_walker(n,
     973              :                                              glob_cxt, &inner_cxt, case_arg_cxt))
     974           12 :                         return false;
     975              :                 }
     976              : 
     977              :                 /*
     978              :                  * For aggorder elements, check whether the sort operator, if
     979              :                  * specified, is shippable or not.
     980              :                  */
     981          264 :                 if (agg->aggorder)
     982              :                 {
     983           70 :                     foreach(lc, agg->aggorder)
     984              :                     {
     985           38 :                         SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
     986              :                         Oid         sortcoltype;
     987              :                         TypeCacheEntry *typentry;
     988              :                         TargetEntry *tle;
     989              : 
     990           38 :                         tle = get_sortgroupref_tle(srt->tleSortGroupRef,
     991              :                                                    agg->args);
     992           38 :                         sortcoltype = exprType((Node *) tle->expr);
     993           38 :                         typentry = lookup_type_cache(sortcoltype,
     994              :                                                      TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
     995              :                         /* Check shippability of non-default sort operator. */
     996           38 :                         if (srt->sortop != typentry->lt_opr &&
     997           14 :                             srt->sortop != typentry->gt_opr &&
     998            6 :                             !is_shippable(srt->sortop, OperatorRelationId,
     999              :                                           fpinfo))
    1000            4 :                             return false;
    1001              :                     }
    1002              :                 }
    1003              : 
    1004              :                 /* Check aggregate filter */
    1005          260 :                 if (!foreign_expr_walker((Node *) agg->aggfilter,
    1006              :                                          glob_cxt, &inner_cxt, case_arg_cxt))
    1007            2 :                     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          258 :                 if (agg->inputcollid == InvalidOid)
    1014              :                      /* OK, inputs are all noncollatable */ ;
    1015           22 :                 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
    1016           22 :                          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          258 :                 collation = agg->aggcollid;
    1026          258 :                 if (collation == InvalidOid)
    1027          257 :                     state = FDW_COLLATE_NONE;
    1028            1 :                 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
    1029            1 :                          collation == inner_cxt.collation)
    1030            1 :                     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          258 :             break;
    1037           30 :         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           30 :             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         8876 :     if (check_type && !is_shippable(exprType(node), TypeRelationId, fpinfo))
    1051           25 :         return false;
    1052              : 
    1053              :     /*
    1054              :      * Now, merge my collation information into my parent's state.
    1055              :      */
    1056         8851 :     if (state > outer_cxt->state)
    1057              :     {
    1058              :         /* Override previous parent state */
    1059          485 :         outer_cxt->collation = collation;
    1060          485 :         outer_cxt->state = state;
    1061              :     }
    1062         8366 :     else if (state == outer_cxt->state)
    1063              :     {
    1064              :         /* Merge, or detect error if there's a collation conflict */
    1065         8314 :         switch (state)
    1066              :         {
    1067         8301 :             case FDW_COLLATE_NONE:
    1068              :                 /* Nothing + nothing is still nothing */
    1069         8301 :                 break;
    1070           12 :             case FDW_COLLATE_SAFE:
    1071           12 :                 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           12 :                 break;
    1092            1 :             case FDW_COLLATE_UNSAFE:
    1093              :                 /* We're still conflicted ... */
    1094            1 :                 break;
    1095              :         }
    1096              :     }
    1097              : 
    1098              :     /* It looks OK */
    1099         8851 :     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          276 : is_foreign_param(PlannerInfo *root,
    1116              :                  RelOptInfo *baserel,
    1117              :                  Expr *expr)
    1118              : {
    1119          276 :     if (expr == NULL)
    1120            0 :         return false;
    1121              : 
    1122          276 :     switch (nodeTag(expr))
    1123              :     {
    1124           76 :         case T_Var:
    1125              :             {
    1126              :                 /* It would have to be sent unless it's a foreign Var */
    1127           76 :                 Var        *var = (Var *) expr;
    1128           76 :                 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
    1129              :                 Relids      relids;
    1130              : 
    1131           76 :                 if (IS_UPPER_REL(baserel))
    1132           76 :                     relids = fpinfo->outerrel->relids;
    1133              :                 else
    1134            0 :                     relids = baserel->relids;
    1135              : 
    1136           76 :                 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
    1137           76 :                     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            4 :         case T_Param:
    1143              :             /* Params always have to be sent to the foreign server */
    1144            4 :             return true;
    1145          196 :         default:
    1146          196 :             break;
    1147              :     }
    1148          196 :     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          775 : is_foreign_pathkey(PlannerInfo *root,
    1157              :                    RelOptInfo *baserel,
    1158              :                    PathKey *pathkey)
    1159              : {
    1160          775 :     EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
    1161          775 :     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          775 :     if (pathkey_ec->ec_has_volatile)
    1168            4 :         return false;
    1169              : 
    1170              :     /* can't push down the sort if the pathkey's opfamily is not shippable */
    1171          771 :     if (!is_shippable(pathkey->pk_opfamily, OperatorFamilyRelationId, fpinfo))
    1172            3 :         return false;
    1173              : 
    1174              :     /* can push if a suitable EC member exists */
    1175          768 :     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          569 : deparse_type_name(Oid type_oid, int32 typemod)
    1191              : {
    1192          569 :     bits16      flags = FORMAT_TYPE_TYPEMOD_GIVEN;
    1193              : 
    1194          569 :     if (!is_builtin(type_oid))
    1195            0 :         flags |= FORMAT_TYPE_FORCE_QUALIFY;
    1196              : 
    1197          569 :     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          812 : build_tlist_to_deparse(RelOptInfo *foreignrel)
    1210              : {
    1211          812 :     List       *tlist = NIL;
    1212          812 :     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          812 :     if (IS_UPPER_REL(foreignrel))
    1220          166 :         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          646 :     tlist = add_to_flat_tlist(tlist,
    1227          646 :                               pull_var_clause((Node *) foreignrel->reltarget->exprs,
    1228              :                                               PVC_RECURSE_PLACEHOLDERS));
    1229          670 :     foreach(lc, fpinfo->local_conds)
    1230              :     {
    1231           24 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    1232              : 
    1233           24 :         tlist = add_to_flat_tlist(tlist,
    1234           24 :                                   pull_var_clause((Node *) rinfo->clause,
    1235              :                                                   PVC_RECURSE_PLACEHOLDERS));
    1236              :     }
    1237              : 
    1238          646 :     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         2372 : 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         2372 :     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         2372 :     context.buf = buf;
    1283         2372 :     context.root = root;
    1284         2372 :     context.foreignrel = rel;
    1285         2372 :     context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
    1286         2372 :     context.params_list = params_list;
    1287              : 
    1288              :     /* Construct SELECT clause */
    1289         2372 :     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         2372 :     if (IS_UPPER_REL(rel))
    1297          166 :     {
    1298              :         PgFdwRelationInfo *ofpinfo;
    1299              : 
    1300          166 :         ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
    1301          166 :         quals = ofpinfo->remote_conds;
    1302              :     }
    1303              :     else
    1304         2206 :         quals = remote_conds;
    1305              : 
    1306              :     /* Construct FROM and WHERE clauses */
    1307         2372 :     deparseFromExpr(quals, &context);
    1308              : 
    1309         2372 :     if (IS_UPPER_REL(rel))
    1310              :     {
    1311              :         /* Append GROUP BY clause */
    1312          166 :         appendGroupByClause(tlist, &context);
    1313              : 
    1314              :         /* Append HAVING clause */
    1315          166 :         if (remote_conds)
    1316              :         {
    1317           18 :             appendStringInfoString(buf, " HAVING ");
    1318           18 :             appendConditions(remote_conds, &context);
    1319              :         }
    1320              :     }
    1321              : 
    1322              :     /* Add ORDER BY clause if we found any useful pathkeys */
    1323         2372 :     if (pathkeys)
    1324          750 :         appendOrderByClause(pathkeys, has_final_sort, &context);
    1325              : 
    1326              :     /* Add LIMIT clause if necessary */
    1327         2372 :     if (has_limit)
    1328          146 :         appendLimitClause(&context);
    1329              : 
    1330              :     /* Add any necessary FOR UPDATE/SHARE. */
    1331         2372 :     deparseLockingClause(&context);
    1332         2372 : }
    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         2372 : deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
    1349              :                  deparse_expr_cxt *context)
    1350              : {
    1351         2372 :     StringInfo  buf = context->buf;
    1352         2372 :     RelOptInfo *foreignrel = context->foreignrel;
    1353         2372 :     PlannerInfo *root = context->root;
    1354         2372 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    1355              : 
    1356              :     /*
    1357              :      * Construct SELECT list
    1358              :      */
    1359         2372 :     appendStringInfoString(buf, "SELECT ");
    1360              : 
    1361         2372 :     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           50 :         deparseSubqueryTargetList(context);
    1369              :     }
    1370         2322 :     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          812 :         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         1510 :         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         1510 :         Relation    rel = table_open(rte->relid, NoLock);
    1391              : 
    1392         1510 :         deparseTargetList(buf, rte, foreignrel->relid, rel, false,
    1393              :                           fpinfo->attrs_used, false, retrieved_attrs);
    1394         1510 :         table_close(rel, NoLock);
    1395              :     }
    1396         2372 : }
    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         2372 : deparseFromExpr(List *quals, deparse_expr_cxt *context)
    1407              : {
    1408         2372 :     StringInfo  buf = context->buf;
    1409         2372 :     RelOptInfo *scanrel = context->scanrel;
    1410         2372 :     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         2372 :     appendStringInfoString(buf, " FROM ");
    1418         2372 :     deparseFromExprForRel(buf, context->root, scanrel,
    1419         2372 :                           (bms_membership(scanrel->relids) == BMS_MULTIPLE),
    1420              :                           (Index) 0, NULL, &additional_conds,
    1421              :                           context->params_list);
    1422         2372 :     appendWhereClause(quals, additional_conds, context);
    1423         2372 :     if (additional_conds != NIL)
    1424          158 :         list_free_deep(additional_conds);
    1425         2372 : }
    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         1906 : 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         1906 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    1448              :     bool        have_wholerow;
    1449              :     bool        first;
    1450              :     int         i;
    1451              : 
    1452         1906 :     *retrieved_attrs = NIL;
    1453              : 
    1454              :     /* If there's a whole-row reference, we'll need all the columns. */
    1455         1906 :     have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
    1456              :                                   attrs_used);
    1457              : 
    1458         1906 :     first = true;
    1459        13483 :     for (i = 1; i <= tupdesc->natts; i++)
    1460              :     {
    1461              :         /* Ignore dropped attributes. */
    1462        11577 :         if (TupleDescCompactAttr(tupdesc, i - 1)->attisdropped)
    1463         1037 :             continue;
    1464              : 
    1465        17612 :         if (have_wholerow ||
    1466         7072 :             bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
    1467              :                           attrs_used))
    1468              :         {
    1469         6583 :             if (!first)
    1470         4803 :                 appendStringInfoString(buf, ", ");
    1471         1780 :             else if (is_returning)
    1472          112 :                 appendStringInfoString(buf, " RETURNING ");
    1473         6583 :             first = false;
    1474              : 
    1475         6583 :             deparseColumnRef(buf, rtindex, i, rte, qualify_col);
    1476              : 
    1477         6583 :             *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         1906 :     if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber,
    1486              :                       attrs_used))
    1487              :     {
    1488          308 :         if (!first)
    1489          232 :             appendStringInfoString(buf, ", ");
    1490           76 :         else if (is_returning)
    1491            0 :             appendStringInfoString(buf, " RETURNING ");
    1492          308 :         first = false;
    1493              : 
    1494          308 :         if (qualify_col)
    1495            0 :             ADD_REL_QUALIFIER(buf, rtindex);
    1496          308 :         appendStringInfoString(buf, "ctid");
    1497              : 
    1498          308 :         *retrieved_attrs = lappend_int(*retrieved_attrs,
    1499              :                                        SelfItemPointerAttributeNumber);
    1500              :     }
    1501              : 
    1502              :     /* Don't generate bad syntax if no undropped columns */
    1503         1906 :     if (first && !is_returning)
    1504           44 :         appendStringInfoString(buf, "NULL");
    1505         1906 : }
    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         2372 : deparseLockingClause(deparse_expr_cxt *context)
    1513              : {
    1514         2372 :     StringInfo  buf = context->buf;
    1515         2372 :     PlannerInfo *root = context->root;
    1516         2372 :     RelOptInfo *rel = context->scanrel;
    1517         2372 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
    1518         2372 :     int         relid = -1;
    1519              : 
    1520         5946 :     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         3574 :         if (bms_is_member(relid, fpinfo->lower_subquery_rels))
    1527           80 :             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         3494 :         if (bms_is_member(relid, root->all_result_relids) &&
    1541          317 :             (root->parse->commandType == CMD_UPDATE ||
    1542          128 :              root->parse->commandType == CMD_DELETE))
    1543              :         {
    1544              :             /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
    1545          315 :             appendStringInfoString(buf, " FOR UPDATE");
    1546              : 
    1547              :             /* Add the relation alias if we are here for a join relation */
    1548          315 :             if (IS_JOIN_REL(rel))
    1549           54 :                 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
    1550              :         }
    1551              :         else
    1552              :         {
    1553         3179 :             PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
    1554              : 
    1555         3179 :             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          404 :                 switch (rc->strength)
    1569              :                 {
    1570          240 :                     case LCS_NONE:
    1571              :                         /* No locking needed */
    1572          240 :                         break;
    1573           38 :                     case LCS_FORKEYSHARE:
    1574              :                     case LCS_FORSHARE:
    1575           38 :                         appendStringInfoString(buf, " FOR SHARE");
    1576           38 :                         break;
    1577          126 :                     case LCS_FORNOKEYUPDATE:
    1578              :                     case LCS_FORUPDATE:
    1579          126 :                         appendStringInfoString(buf, " FOR UPDATE");
    1580          126 :                         break;
    1581              :                 }
    1582              : 
    1583              :                 /* Add the relation alias if we are here for a join relation */
    1584          404 :                 if (bms_membership(rel->relids) == BMS_MULTIPLE &&
    1585          224 :                     rc->strength != LCS_NONE)
    1586          110 :                     appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
    1587              :             }
    1588              :         }
    1589              :     }
    1590         2372 : }
    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         1931 : appendConditions(List *exprs, deparse_expr_cxt *context)
    1603              : {
    1604              :     int         nestlevel;
    1605              :     ListCell   *lc;
    1606         1931 :     bool        is_first = true;
    1607         1931 :     StringInfo  buf = context->buf;
    1608              : 
    1609              :     /* Make sure any constants in the exprs are printed portably */
    1610         1931 :     nestlevel = set_transmission_modes();
    1611              : 
    1612         4425 :     foreach(lc, exprs)
    1613              :     {
    1614         2494 :         Expr       *expr = (Expr *) lfirst(lc);
    1615              : 
    1616              :         /* Extract clause from RestrictInfo, if required */
    1617         2494 :         if (IsA(expr, RestrictInfo))
    1618         2131 :             expr = ((RestrictInfo *) expr)->clause;
    1619              : 
    1620              :         /* Connect expressions with "AND" and parenthesize each condition. */
    1621         2494 :         if (!is_first)
    1622          563 :             appendStringInfoString(buf, " AND ");
    1623              : 
    1624         2494 :         appendStringInfoChar(buf, '(');
    1625         2494 :         deparseExpr(expr, context);
    1626         2494 :         appendStringInfoChar(buf, ')');
    1627              : 
    1628         2494 :         is_first = false;
    1629              :     }
    1630              : 
    1631         1931 :     reset_transmission_modes(nestlevel);
    1632         1931 : }
    1633              : 
    1634              : /*
    1635              :  * Append WHERE clause, containing conditions from exprs and additional_conds,
    1636              :  * to context->buf.
    1637              :  */
    1638              : static void
    1639         2666 : appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
    1640              : {
    1641         2666 :     StringInfo  buf = context->buf;
    1642         2666 :     bool        need_and = false;
    1643              :     ListCell   *lc;
    1644              : 
    1645         2666 :     if (exprs != NIL || additional_conds != NIL)
    1646         1266 :         appendStringInfoString(buf, " WHERE ");
    1647              : 
    1648              :     /*
    1649              :      * If there are some filters, append them.
    1650              :      */
    1651         2666 :     if (exprs != NIL)
    1652              :     {
    1653         1163 :         appendConditions(exprs, context);
    1654         1163 :         need_and = true;
    1655              :     }
    1656              : 
    1657              :     /*
    1658              :      * If there are some EXISTS conditions, coming from SEMI-JOINS, append
    1659              :      * them.
    1660              :      */
    1661         2856 :     foreach(lc, additional_conds)
    1662              :     {
    1663          190 :         if (need_and)
    1664           87 :             appendStringInfoString(buf, " AND ");
    1665          190 :         appendStringInfoString(buf, (char *) lfirst(lc));
    1666          190 :         need_and = true;
    1667              :     }
    1668         2666 : }
    1669              : 
    1670              : /* Output join name for given join type */
    1671              : const char *
    1672         1109 : get_jointype_name(JoinType jointype)
    1673              : {
    1674         1109 :     switch (jointype)
    1675              :     {
    1676          741 :         case JOIN_INNER:
    1677          741 :             return "INNER";
    1678              : 
    1679          216 :         case JOIN_LEFT:
    1680          216 :             return "LEFT";
    1681              : 
    1682            0 :         case JOIN_RIGHT:
    1683            0 :             return "RIGHT";
    1684              : 
    1685          108 :         case JOIN_FULL:
    1686          108 :             return "FULL";
    1687              : 
    1688           44 :         case JOIN_SEMI:
    1689           44 :             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          820 : deparseExplicitTargetList(List *tlist,
    1713              :                           bool is_returning,
    1714              :                           List **retrieved_attrs,
    1715              :                           deparse_expr_cxt *context)
    1716              : {
    1717              :     ListCell   *lc;
    1718          820 :     StringInfo  buf = context->buf;
    1719          820 :     int         i = 0;
    1720              : 
    1721          820 :     *retrieved_attrs = NIL;
    1722              : 
    1723         4818 :     foreach(lc, tlist)
    1724              :     {
    1725         3998 :         TargetEntry *tle = lfirst_node(TargetEntry, lc);
    1726              : 
    1727         3998 :         if (i > 0)
    1728         3190 :             appendStringInfoString(buf, ", ");
    1729          808 :         else if (is_returning)
    1730            2 :             appendStringInfoString(buf, " RETURNING ");
    1731              : 
    1732         3998 :         deparseExpr((Expr *) tle->expr, context);
    1733              : 
    1734         3998 :         *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
    1735         3998 :         i++;
    1736              :     }
    1737              : 
    1738          820 :     if (i == 0 && !is_returning)
    1739            6 :         appendStringInfoString(buf, "NULL");
    1740          820 : }
    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           50 : deparseSubqueryTargetList(deparse_expr_cxt *context)
    1749              : {
    1750           50 :     StringInfo  buf = context->buf;
    1751           50 :     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           50 :     first = true;
    1759          120 :     foreach(lc, foreignrel->reltarget->exprs)
    1760              :     {
    1761           70 :         Node       *node = (Node *) lfirst(lc);
    1762              : 
    1763           70 :         if (!first)
    1764           24 :             appendStringInfoString(buf, ", ");
    1765           70 :         first = false;
    1766              : 
    1767           70 :         deparseExpr((Expr *) node, context);
    1768              :     }
    1769              : 
    1770              :     /* Don't generate bad syntax if no expressions */
    1771           50 :     if (first)
    1772            4 :         appendStringInfoString(buf, "NULL");
    1773           50 : }
    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         4262 : 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         4262 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    1797              : 
    1798         4262 :     if (IS_JOIN_REL(foreignrel))
    1799          962 :     {
    1800              :         StringInfoData join_sql_o;
    1801              :         StringInfoData join_sql_i;
    1802          970 :         RelOptInfo *outerrel = fpinfo->outerrel;
    1803          970 :         RelOptInfo *innerrel = fpinfo->innerrel;
    1804          970 :         bool        outerrel_is_target = false;
    1805          970 :         bool        innerrel_is_target = false;
    1806          970 :         List       *additional_conds_i = NIL;
    1807          970 :         List       *additional_conds_o = NIL;
    1808              : 
    1809          970 :         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           12 :             if (fpinfo->jointype == JOIN_INNER)
    1823              :             {
    1824           20 :                 *ignore_conds = list_concat(*ignore_conds,
    1825           10 :                                             fpinfo->joinclauses);
    1826           10 :                 fpinfo->joinclauses = NIL;
    1827              :             }
    1828              : 
    1829              :             /*
    1830              :              * Check if either of the input relations is the target relation.
    1831              :              */
    1832           12 :             if (outerrel->relid == ignore_rel)
    1833            8 :                 outerrel_is_target = true;
    1834            4 :             else if (innerrel->relid == ignore_rel)
    1835            0 :                 innerrel_is_target = true;
    1836              :         }
    1837              : 
    1838              :         /* Deparse outer relation if not the target relation. */
    1839          970 :         if (!outerrel_is_target)
    1840              :         {
    1841          962 :             initStringInfo(&join_sql_o);
    1842          962 :             deparseRangeTblRef(&join_sql_o, root, outerrel,
    1843          962 :                                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          962 :             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            8 :                 return;
    1868              :             }
    1869              :         }
    1870              : 
    1871              :         /* Deparse inner relation if not the target relation. */
    1872          970 :         if (!innerrel_is_target)
    1873              :         {
    1874          970 :             initStringInfo(&join_sql_i);
    1875          970 :             deparseRangeTblRef(&join_sql_i, root, innerrel,
    1876          970 :                                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          970 :             if (fpinfo->jointype == JOIN_SEMI)
    1889              :             {
    1890              :                 deparse_expr_cxt context;
    1891              :                 StringInfoData str;
    1892              : 
    1893              :                 /* Construct deparsed condition from this SEMI-JOIN */
    1894          190 :                 initStringInfo(&str);
    1895          190 :                 appendStringInfo(&str, "EXISTS (SELECT NULL FROM %s",
    1896              :                                  join_sql_i.data);
    1897              : 
    1898          190 :                 context.buf = &str;
    1899          190 :                 context.foreignrel = foreignrel;
    1900          190 :                 context.scanrel = foreignrel;
    1901          190 :                 context.root = root;
    1902          190 :                 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          190 :                 appendWhereClause(fpinfo->joinclauses, additional_conds_i, &context);
    1909              : 
    1910              :                 /*
    1911              :                  * EXISTS conditions, coming from lower join levels, have just
    1912              :                  * been processed.
    1913              :                  */
    1914          190 :                 if (additional_conds_i != NIL)
    1915              :                 {
    1916           16 :                     list_free_deep(additional_conds_i);
    1917           16 :                     additional_conds_i = NIL;
    1918              :                 }
    1919              : 
    1920              :                 /* Close parentheses for EXISTS subquery */
    1921          190 :                 appendStringInfoChar(&str, ')');
    1922              : 
    1923          190 :                 *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          970 :             if (outerrel_is_target)
    1931              :             {
    1932              :                 Assert(fpinfo->jointype == JOIN_INNER);
    1933              :                 Assert(fpinfo->joinclauses == NIL);
    1934            8 :                 appendBinaryStringInfo(buf, join_sql_i.data, join_sql_i.len);
    1935              :                 /* Pass EXISTS conditions to the upper call */
    1936            8 :                 if (additional_conds_i != NIL)
    1937              :                 {
    1938              :                     Assert(*additional_conds == NIL);
    1939            0 :                     *additional_conds = additional_conds_i;
    1940              :                 }
    1941            8 :                 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          962 :         if (fpinfo->jointype == JOIN_SEMI)
    1954              :         {
    1955          190 :             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          772 :             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          772 :             if (fpinfo->joinclauses)
    1970              :             {
    1971              :                 deparse_expr_cxt context;
    1972              : 
    1973          750 :                 context.buf = buf;
    1974          750 :                 context.foreignrel = foreignrel;
    1975          750 :                 context.scanrel = foreignrel;
    1976          750 :                 context.root = root;
    1977          750 :                 context.params_list = params_list;
    1978              : 
    1979          750 :                 appendStringInfoChar(buf, '(');
    1980          750 :                 appendConditions(fpinfo->joinclauses, &context);
    1981          750 :                 appendStringInfoChar(buf, ')');
    1982              :             }
    1983              :             else
    1984           22 :                 appendStringInfoString(buf, "(TRUE)");
    1985              : 
    1986              :             /* End the FROM clause entry. */
    1987          772 :             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          962 :         if (additional_conds_o != NIL)
    1996              :         {
    1997           48 :             *additional_conds = list_concat(*additional_conds,
    1998              :                                             additional_conds_o);
    1999           48 :             list_free(additional_conds_o);
    2000              :         }
    2001              : 
    2002          962 :         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         3292 :         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         3292 :         Relation    rel = table_open(rte->relid, NoLock);
    2018              : 
    2019         3292 :         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         3292 :         if (use_alias)
    2027         1610 :             appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
    2028              : 
    2029         3292 :         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         1932 : 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         1932 :     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         1932 :     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           50 :         appendStringInfoChar(buf, '(');
    2066           50 :         deparseSelectStmtForRel(buf, root, foreignrel, NIL,
    2067              :                                 fpinfo->remote_conds, NIL,
    2068              :                                 false, false, true,
    2069              :                                 &retrieved_attrs, params_list);
    2070           50 :         appendStringInfoChar(buf, ')');
    2071              : 
    2072              :         /* Append the relation alias. */
    2073           50 :         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           50 :         ncols = list_length(foreignrel->reltarget->exprs);
    2082           50 :         if (ncols > 0)
    2083              :         {
    2084              :             int         i;
    2085              : 
    2086           46 :             appendStringInfoChar(buf, '(');
    2087          116 :             for (i = 1; i <= ncols; i++)
    2088              :             {
    2089           70 :                 if (i > 1)
    2090           24 :                     appendStringInfoString(buf, ", ");
    2091              : 
    2092           70 :                 appendStringInfo(buf, "%s%d", SUBQUERY_COL_ALIAS_PREFIX, i);
    2093              :             }
    2094           46 :             appendStringInfoChar(buf, ')');
    2095              :         }
    2096              :     }
    2097              :     else
    2098         1882 :         deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
    2099              :                               ignore_conds, additional_conds,
    2100              :                               params_list);
    2101         1932 : }
    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          146 : 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          146 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    2121              :     AttrNumber  pindex;
    2122              :     bool        first;
    2123              :     ListCell   *lc;
    2124              : 
    2125          146 :     appendStringInfoString(buf, "INSERT INTO ");
    2126          146 :     deparseRelation(buf, rel);
    2127              : 
    2128          146 :     if (targetAttrs)
    2129              :     {
    2130          145 :         appendStringInfoChar(buf, '(');
    2131              : 
    2132          145 :         first = true;
    2133          540 :         foreach(lc, targetAttrs)
    2134              :         {
    2135          395 :             int         attnum = lfirst_int(lc);
    2136              : 
    2137          395 :             if (!first)
    2138          250 :                 appendStringInfoString(buf, ", ");
    2139          395 :             first = false;
    2140              : 
    2141          395 :             deparseColumnRef(buf, rtindex, attnum, rte, false);
    2142              :         }
    2143              : 
    2144          145 :         appendStringInfoString(buf, ") VALUES (");
    2145              : 
    2146          145 :         pindex = 1;
    2147          145 :         first = true;
    2148          540 :         foreach(lc, targetAttrs)
    2149              :         {
    2150          395 :             int         attnum = lfirst_int(lc);
    2151          395 :             CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    2152              : 
    2153          395 :             if (!first)
    2154          250 :                 appendStringInfoString(buf, ", ");
    2155          395 :             first = false;
    2156              : 
    2157          395 :             if (attr->attgenerated)
    2158           10 :                 appendStringInfoString(buf, "DEFAULT");
    2159              :             else
    2160              :             {
    2161          385 :                 appendStringInfo(buf, "$%d", pindex);
    2162          385 :                 pindex++;
    2163              :             }
    2164              :         }
    2165              : 
    2166          145 :         appendStringInfoChar(buf, ')');
    2167              :     }
    2168              :     else
    2169            1 :         appendStringInfoString(buf, " DEFAULT VALUES");
    2170          146 :     *values_end_len = buf->len;
    2171              : 
    2172          146 :     if (doNothing)
    2173            3 :         appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
    2174              : 
    2175          146 :     deparseReturningList(buf, rte, rtindex, rel,
    2176          146 :                          rel->trigdesc && rel->trigdesc->trig_insert_after_row,
    2177          146 :                          withCheckOptionList, returningList, retrieved_attrs);
    2178          146 : }
    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           26 : 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           26 :     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           26 :     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           26 :     pindex = num_params + 1;
    2209          103 :     for (i = 0; i < num_rows; i++)
    2210              :     {
    2211           77 :         appendStringInfoString(buf, ", (");
    2212              : 
    2213           77 :         first = true;
    2214          226 :         foreach(lc, target_attrs)
    2215              :         {
    2216          149 :             int         attnum = lfirst_int(lc);
    2217          149 :             CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    2218              : 
    2219          149 :             if (!first)
    2220           72 :                 appendStringInfoString(buf, ", ");
    2221          149 :             first = false;
    2222              : 
    2223          149 :             if (attr->attgenerated)
    2224            2 :                 appendStringInfoString(buf, "DEFAULT");
    2225              :             else
    2226              :             {
    2227          147 :                 appendStringInfo(buf, "$%d", pindex);
    2228          147 :                 pindex++;
    2229              :             }
    2230              :         }
    2231              : 
    2232           77 :         appendStringInfoChar(buf, ')');
    2233              :     }
    2234              : 
    2235              :     /* Copy stuff after VALUES clause from the original query */
    2236           26 :     appendStringInfoString(buf, orig_query + values_end_len);
    2237           26 : }
    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           60 : deparseUpdateSql(StringInfo buf, RangeTblEntry *rte,
    2248              :                  Index rtindex, Relation rel,
    2249              :                  List *targetAttrs,
    2250              :                  List *withCheckOptionList, List *returningList,
    2251              :                  List **retrieved_attrs)
    2252              : {
    2253           60 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    2254              :     AttrNumber  pindex;
    2255              :     bool        first;
    2256              :     ListCell   *lc;
    2257              : 
    2258           60 :     appendStringInfoString(buf, "UPDATE ");
    2259           60 :     deparseRelation(buf, rel);
    2260           60 :     appendStringInfoString(buf, " SET ");
    2261              : 
    2262           60 :     pindex = 2;                 /* ctid is always the first param */
    2263           60 :     first = true;
    2264          147 :     foreach(lc, targetAttrs)
    2265              :     {
    2266           87 :         int         attnum = lfirst_int(lc);
    2267           87 :         CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    2268              : 
    2269           87 :         if (!first)
    2270           27 :             appendStringInfoString(buf, ", ");
    2271           87 :         first = false;
    2272              : 
    2273           87 :         deparseColumnRef(buf, rtindex, attnum, rte, false);
    2274           87 :         if (attr->attgenerated)
    2275            4 :             appendStringInfoString(buf, " = DEFAULT");
    2276              :         else
    2277              :         {
    2278           83 :             appendStringInfo(buf, " = $%d", pindex);
    2279           83 :             pindex++;
    2280              :         }
    2281              :     }
    2282           60 :     appendStringInfoString(buf, " WHERE ctid = $1");
    2283              : 
    2284           60 :     deparseReturningList(buf, rte, rtindex, rel,
    2285           60 :                          rel->trigdesc && rel->trigdesc->trig_update_after_row,
    2286           60 :                          withCheckOptionList, returningList, retrieved_attrs);
    2287           60 : }
    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           45 : 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           45 :     RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
    2321              :     ListCell   *lc,
    2322              :                *lc2;
    2323           45 :     List       *additional_conds = NIL;
    2324              : 
    2325              :     /* Set up context struct for recursion */
    2326           45 :     context.root = root;
    2327           45 :     context.foreignrel = foreignrel;
    2328           45 :     context.scanrel = foreignrel;
    2329           45 :     context.buf = buf;
    2330           45 :     context.params_list = params_list;
    2331              : 
    2332           45 :     appendStringInfoString(buf, "UPDATE ");
    2333           45 :     deparseRelation(buf, rel);
    2334           45 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2335            4 :         appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
    2336           45 :     appendStringInfoString(buf, " SET ");
    2337              : 
    2338              :     /* Make sure any constants in the exprs are printed portably */
    2339           45 :     nestlevel = set_transmission_modes();
    2340              : 
    2341           45 :     first = true;
    2342           98 :     forboth(lc, targetlist, lc2, targetAttrs)
    2343              :     {
    2344           53 :         TargetEntry *tle = lfirst_node(TargetEntry, lc);
    2345           53 :         int         attnum = lfirst_int(lc2);
    2346              : 
    2347              :         /* update's new-value expressions shouldn't be resjunk */
    2348              :         Assert(!tle->resjunk);
    2349              : 
    2350           53 :         if (!first)
    2351            8 :             appendStringInfoString(buf, ", ");
    2352           53 :         first = false;
    2353              : 
    2354           53 :         deparseColumnRef(buf, rtindex, attnum, rte, false);
    2355           53 :         appendStringInfoString(buf, " = ");
    2356           53 :         deparseExpr((Expr *) tle->expr, &context);
    2357              :     }
    2358              : 
    2359           45 :     reset_transmission_modes(nestlevel);
    2360              : 
    2361           45 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2362              :     {
    2363            4 :         List       *ignore_conds = NIL;
    2364              : 
    2365              : 
    2366            4 :         appendStringInfoString(buf, " FROM ");
    2367            4 :         deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
    2368              :                               &ignore_conds, &additional_conds, params_list);
    2369            4 :         remote_conds = list_concat(remote_conds, ignore_conds);
    2370              :     }
    2371              : 
    2372           45 :     appendWhereClause(remote_conds, additional_conds, &context);
    2373              : 
    2374           45 :     if (additional_conds != NIL)
    2375            0 :         list_free_deep(additional_conds);
    2376              : 
    2377           45 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2378            4 :         deparseExplicitTargetList(returningList, true, retrieved_attrs,
    2379              :                                   &context);
    2380              :     else
    2381           41 :         deparseReturningList(buf, rte, rtindex, rel, false,
    2382              :                              NIL, returningList, retrieved_attrs);
    2383           45 : }
    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           22 : deparseDeleteSql(StringInfo buf, RangeTblEntry *rte,
    2394              :                  Index rtindex, Relation rel,
    2395              :                  List *returningList,
    2396              :                  List **retrieved_attrs)
    2397              : {
    2398           22 :     appendStringInfoString(buf, "DELETE FROM ");
    2399           22 :     deparseRelation(buf, rel);
    2400           22 :     appendStringInfoString(buf, " WHERE ctid = $1");
    2401              : 
    2402           22 :     deparseReturningList(buf, rte, rtindex, rel,
    2403           22 :                          rel->trigdesc && rel->trigdesc->trig_delete_after_row,
    2404           22 :                          NIL, returningList, retrieved_attrs);
    2405           22 : }
    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           59 : 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           59 :     List       *additional_conds = NIL;
    2432              : 
    2433              :     /* Set up context struct for recursion */
    2434           59 :     context.root = root;
    2435           59 :     context.foreignrel = foreignrel;
    2436           59 :     context.scanrel = foreignrel;
    2437           59 :     context.buf = buf;
    2438           59 :     context.params_list = params_list;
    2439              : 
    2440           59 :     appendStringInfoString(buf, "DELETE FROM ");
    2441           59 :     deparseRelation(buf, rel);
    2442           59 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2443            4 :         appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
    2444              : 
    2445           59 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2446              :     {
    2447            4 :         List       *ignore_conds = NIL;
    2448              : 
    2449            4 :         appendStringInfoString(buf, " USING ");
    2450            4 :         deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
    2451              :                               &ignore_conds, &additional_conds, params_list);
    2452            4 :         remote_conds = list_concat(remote_conds, ignore_conds);
    2453              :     }
    2454              : 
    2455           59 :     appendWhereClause(remote_conds, additional_conds, &context);
    2456              : 
    2457           59 :     if (additional_conds != NIL)
    2458            0 :         list_free_deep(additional_conds);
    2459              : 
    2460           59 :     if (foreignrel->reloptkind == RELOPT_JOINREL)
    2461            4 :         deparseExplicitTargetList(returningList, true, retrieved_attrs,
    2462              :                                   &context);
    2463              :     else
    2464           55 :         deparseReturningList(buf, planner_rt_fetch(rtindex, root),
    2465              :                              rtindex, rel, false,
    2466              :                              NIL, returningList, retrieved_attrs);
    2467           59 : }
    2468              : 
    2469              : /*
    2470              :  * Add a RETURNING clause, if needed, to an INSERT/UPDATE/DELETE.
    2471              :  */
    2472              : static void
    2473          324 : 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          324 :     Bitmapset  *attrs_used = NULL;
    2481              : 
    2482          324 :     if (trig_after_row)
    2483              :     {
    2484              :         /* whole-row reference acquires all non-system columns */
    2485           24 :         attrs_used =
    2486           24 :             bms_make_singleton(0 - FirstLowInvalidHeapAttributeNumber);
    2487              :     }
    2488              : 
    2489          324 :     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           19 :         pull_varattnos((Node *) withCheckOptionList, rtindex,
    2501              :                        &attrs_used);
    2502              :     }
    2503              : 
    2504          324 :     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           76 :         pull_varattnos((Node *) returningList, rtindex,
    2511              :                        &attrs_used);
    2512              :     }
    2513              : 
    2514          324 :     if (attrs_used != NULL)
    2515          118 :         deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
    2516              :                           retrieved_attrs);
    2517              :     else
    2518          206 :         *retrieved_attrs = NIL;
    2519          324 : }
    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           47 : deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
    2531              : {
    2532              :     StringInfoData relname;
    2533              : 
    2534              :     /* We'll need the remote relation name as a literal. */
    2535           47 :     initStringInfo(&relname);
    2536           47 :     deparseRelation(&relname, rel);
    2537              : 
    2538           47 :     appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
    2539           47 :     deparseStringLiteral(buf, relname.data);
    2540           47 :     appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
    2541           47 : }
    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           46 : deparseAnalyzeInfoSql(StringInfo buf, Relation rel)
    2553              : {
    2554              :     StringInfoData relname;
    2555              : 
    2556              :     /* We'll need the remote relation name as a literal. */
    2557           46 :     initStringInfo(&relname);
    2558           46 :     deparseRelation(&relname, rel);
    2559              : 
    2560           46 :     appendStringInfoString(buf, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
    2561           46 :     deparseStringLiteral(buf, relname.data);
    2562           46 :     appendStringInfoString(buf, "::pg_catalog.regclass");
    2563           46 : }
    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           47 : deparseAnalyzeSql(StringInfo buf, Relation rel,
    2593              :                   PgFdwSamplingMethod sample_method, double sample_frac,
    2594              :                   List **retrieved_attrs)
    2595              : {
    2596           47 :     Oid         relid = RelationGetRelid(rel);
    2597           47 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    2598              :     int         i;
    2599              :     char       *colname;
    2600              :     List       *options;
    2601              :     ListCell   *lc;
    2602           47 :     bool        first = true;
    2603              : 
    2604           47 :     *retrieved_attrs = NIL;
    2605              : 
    2606           47 :     appendStringInfoString(buf, "SELECT ");
    2607          202 :     for (i = 0; i < tupdesc->natts; i++)
    2608              :     {
    2609              :         /* Ignore dropped columns. */
    2610          155 :         if (TupleDescAttr(tupdesc, i)->attisdropped)
    2611            3 :             continue;
    2612              : 
    2613          152 :         if (!first)
    2614          105 :             appendStringInfoString(buf, ", ");
    2615          152 :         first = false;
    2616              : 
    2617              :         /* Use attribute name or column_name option. */
    2618          152 :         colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
    2619          152 :         options = GetForeignColumnOptions(relid, i + 1);
    2620              : 
    2621          152 :         foreach(lc, options)
    2622              :         {
    2623            3 :             DefElem    *def = (DefElem *) lfirst(lc);
    2624              : 
    2625            3 :             if (strcmp(def->defname, "column_name") == 0)
    2626              :             {
    2627            3 :                 colname = defGetString(def);
    2628            3 :                 break;
    2629              :             }
    2630              :         }
    2631              : 
    2632          152 :         appendStringInfoString(buf, quote_identifier(colname));
    2633              : 
    2634          152 :         *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
    2635              :     }
    2636              : 
    2637              :     /* Don't generate bad syntax for zero-column relation. */
    2638           47 :     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           47 :     appendStringInfoString(buf, " FROM ");
    2646           47 :     deparseRelation(buf, rel);
    2647              : 
    2648           47 :     switch (sample_method)
    2649              :     {
    2650           47 :         case ANALYZE_SAMPLE_OFF:
    2651              :             /* nothing to do here */
    2652           47 :             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           47 : }
    2672              : 
    2673              : /*
    2674              :  * Construct a simple "TRUNCATE rel" statement
    2675              :  */
    2676              : void
    2677           12 : deparseTruncateSql(StringInfo buf,
    2678              :                    List *rels,
    2679              :                    DropBehavior behavior,
    2680              :                    bool restart_seqs)
    2681              : {
    2682              :     ListCell   *cell;
    2683              : 
    2684           12 :     appendStringInfoString(buf, "TRUNCATE ");
    2685              : 
    2686           26 :     foreach(cell, rels)
    2687              :     {
    2688           14 :         Relation    rel = lfirst(cell);
    2689              : 
    2690           14 :         if (cell != list_head(rels))
    2691            2 :             appendStringInfoString(buf, ", ");
    2692              : 
    2693           14 :         deparseRelation(buf, rel);
    2694              :     }
    2695              : 
    2696           12 :     appendStringInfo(buf, " %s IDENTITY",
    2697              :                      restart_seqs ? "RESTART" : "CONTINUE");
    2698              : 
    2699           12 :     if (behavior == DROP_RESTRICT)
    2700           10 :         appendStringInfoString(buf, " RESTRICT");
    2701            2 :     else if (behavior == DROP_CASCADE)
    2702            2 :         appendStringInfoString(buf, " CASCADE");
    2703           12 : }
    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        15432 : 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        15432 :     if (varattno == SelfItemPointerAttributeNumber)
    2717              :     {
    2718           60 :         if (qualify_col)
    2719           58 :             ADD_REL_QUALIFIER(buf, varno);
    2720           60 :         appendStringInfoString(buf, "ctid");
    2721              :     }
    2722        15372 :     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        15372 :     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          278 :         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          278 :         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          278 :         if (qualify_col)
    2777              :         {
    2778          274 :             appendStringInfoString(buf, "CASE WHEN (");
    2779          274 :             ADD_REL_QUALIFIER(buf, varno);
    2780          274 :             appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
    2781              :         }
    2782              : 
    2783          278 :         appendStringInfoString(buf, "ROW(");
    2784          278 :         deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
    2785              :                           &retrieved_attrs);
    2786          278 :         appendStringInfoChar(buf, ')');
    2787              : 
    2788              :         /* Complete the CASE WHEN statement started above. */
    2789          278 :         if (qualify_col)
    2790          274 :             appendStringInfoString(buf, " END");
    2791              : 
    2792          278 :         table_close(rel, NoLock);
    2793          278 :         bms_free(attrs_used);
    2794              :     }
    2795              :     else
    2796              :     {
    2797        15094 :         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        15094 :         options = GetForeignColumnOptions(rte->relid, varattno);
    2809        15094 :         foreach(lc, options)
    2810              :         {
    2811         3466 :             DefElem    *def = (DefElem *) lfirst(lc);
    2812              : 
    2813         3466 :             if (strcmp(def->defname, "column_name") == 0)
    2814              :             {
    2815         3466 :                 colname = defGetString(def);
    2816         3466 :                 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        15094 :         if (colname == NULL)
    2825        11628 :             colname = get_attname(rte->relid, varattno, false);
    2826              : 
    2827        15094 :         if (qualify_col)
    2828         7773 :             ADD_REL_QUALIFIER(buf, varno);
    2829              : 
    2830        15094 :         appendStringInfoString(buf, quote_identifier(colname));
    2831              :     }
    2832        15432 : }
    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         3778 : deparseRelation(StringInfo buf, Relation rel)
    2841              : {
    2842              :     ForeignTable *table;
    2843         3778 :     const char *nspname = NULL;
    2844         3778 :     const char *relname = NULL;
    2845              :     ListCell   *lc;
    2846              : 
    2847              :     /* obtain additional catalog information. */
    2848         3778 :     table = GetForeignTable(RelationGetRelid(rel));
    2849              : 
    2850              :     /*
    2851              :      * Use value of FDW options if any, instead of the name of object itself.
    2852              :      */
    2853        12312 :     foreach(lc, table->options)
    2854              :     {
    2855         8534 :         DefElem    *def = (DefElem *) lfirst(lc);
    2856              : 
    2857         8534 :         if (strcmp(def->defname, "schema_name") == 0)
    2858         2577 :             nspname = defGetString(def);
    2859         5957 :         else if (strcmp(def->defname, "table_name") == 0)
    2860         3778 :             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         3778 :     if (nspname == NULL)
    2868         1201 :         nspname = get_namespace_name(RelationGetNamespace(rel));
    2869         3778 :     if (relname == NULL)
    2870            0 :         relname = RelationGetRelationName(rel);
    2871              : 
    2872         3778 :     appendStringInfo(buf, "%s.%s",
    2873              :                      quote_identifier(nspname), quote_identifier(relname));
    2874         3778 : }
    2875              : 
    2876              : /*
    2877              :  * Append a SQL string literal representing "val" to buf.
    2878              :  */
    2879              : void
    2880          349 : 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          349 :     if (strchr(val, '\\') != NULL)
    2891            1 :         appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
    2892          349 :     appendStringInfoChar(buf, '\'');
    2893         3241 :     for (valptr = val; *valptr; valptr++)
    2894              :     {
    2895         2892 :         char        ch = *valptr;
    2896              : 
    2897         2892 :         if (SQL_STR_DOUBLE(ch, true))
    2898            2 :             appendStringInfoChar(buf, ch);
    2899         2892 :         appendStringInfoChar(buf, ch);
    2900              :     }
    2901          349 :     appendStringInfoChar(buf, '\'');
    2902          349 : }
    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        12588 : deparseExpr(Expr *node, deparse_expr_cxt *context)
    2916              : {
    2917        12588 :     if (node == NULL)
    2918            0 :         return;
    2919              : 
    2920        12588 :     switch (nodeTag(node))
    2921              :     {
    2922         8693 :         case T_Var:
    2923         8693 :             deparseVar((Var *) node, context);
    2924         8693 :             break;
    2925          583 :         case T_Const:
    2926          583 :             deparseConst((Const *) node, context, 0);
    2927          583 :             break;
    2928           43 :         case T_Param:
    2929           43 :             deparseParam((Param *) node, context);
    2930           43 :             break;
    2931            1 :         case T_SubscriptingRef:
    2932            1 :             deparseSubscriptingRef((SubscriptingRef *) node, context);
    2933            1 :             break;
    2934           58 :         case T_FuncExpr:
    2935           58 :             deparseFuncExpr((FuncExpr *) node, context);
    2936           58 :             break;
    2937         2811 :         case T_OpExpr:
    2938         2811 :             deparseOpExpr((OpExpr *) node, context);
    2939         2811 :             break;
    2940            1 :         case T_DistinctExpr:
    2941            1 :             deparseDistinctExpr((DistinctExpr *) node, context);
    2942            1 :             break;
    2943            7 :         case T_ScalarArrayOpExpr:
    2944            7 :             deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
    2945            7 :             break;
    2946           36 :         case T_RelabelType:
    2947           36 :             deparseRelabelType((RelabelType *) node, context);
    2948           36 :             break;
    2949            3 :         case T_ArrayCoerceExpr:
    2950            3 :             deparseArrayCoerceExpr((ArrayCoerceExpr *) node, context);
    2951            3 :             break;
    2952           38 :         case T_BoolExpr:
    2953           38 :             deparseBoolExpr((BoolExpr *) node, context);
    2954           38 :             break;
    2955           26 :         case T_NullTest:
    2956           26 :             deparseNullTest((NullTest *) node, context);
    2957           26 :             break;
    2958           21 :         case T_CaseExpr:
    2959           21 :             deparseCaseExpr((CaseExpr *) node, context);
    2960           21 :             break;
    2961            4 :         case T_ArrayExpr:
    2962            4 :             deparseArrayExpr((ArrayExpr *) node, context);
    2963            4 :             break;
    2964          263 :         case T_Aggref:
    2965          263 :             deparseAggref((Aggref *) node, context);
    2966          263 :             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         8693 : deparseVar(Var *node, deparse_expr_cxt *context)
    2984              : {
    2985         8693 :     Relids      relids = context->scanrel->relids;
    2986              :     int         relno;
    2987              :     int         colno;
    2988              : 
    2989              :     /* Qualify columns when multiple relations are involved. */
    2990         8693 :     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         8693 :     if (is_subquery_var(node, context->scanrel, &relno, &colno))
    2998              :     {
    2999          152 :         appendStringInfo(context->buf, "%s%d.%s%d",
    3000              :                          SUBQUERY_REL_ALIAS_PREFIX, relno,
    3001              :                          SUBQUERY_COL_ALIAS_PREFIX, colno);
    3002          152 :         return;
    3003              :     }
    3004              : 
    3005         8541 :     if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
    3006         8314 :         deparseColumnRef(context->buf, node->varno, node->varattno,
    3007         8314 :                          planner_rt_fetch(node->varno, context->root),
    3008              :                          qualify_col);
    3009              :     else
    3010              :     {
    3011              :         /* Treat like a Param */
    3012          227 :         if (context->params_list)
    3013              :         {
    3014           13 :             int         pindex = 0;
    3015              :             ListCell   *lc;
    3016              : 
    3017              :             /* find its index in params_list */
    3018           13 :             foreach(lc, *context->params_list)
    3019              :             {
    3020            0 :                 pindex++;
    3021            0 :                 if (equal(node, (Node *) lfirst(lc)))
    3022            0 :                     break;
    3023              :             }
    3024           13 :             if (lc == NULL)
    3025              :             {
    3026              :                 /* not in list, so add it */
    3027           13 :                 pindex++;
    3028           13 :                 *context->params_list = lappend(*context->params_list, node);
    3029              :             }
    3030              : 
    3031           13 :             printRemoteParam(pindex, node->vartype, node->vartypmod, context);
    3032              :         }
    3033              :         else
    3034              :         {
    3035          214 :             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         1875 : deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
    3055              : {
    3056         1875 :     StringInfo  buf = context->buf;
    3057              :     Oid         typoutput;
    3058              :     bool        typIsVarlena;
    3059              :     char       *extval;
    3060         1875 :     bool        isfloat = false;
    3061         1875 :     bool        isstring = false;
    3062              :     bool        needlabel;
    3063              : 
    3064         1875 :     if (node->constisnull)
    3065              :     {
    3066           19 :         appendStringInfoString(buf, "NULL");
    3067           19 :         if (showtype >= 0)
    3068           19 :             appendStringInfo(buf, "::%s",
    3069              :                              deparse_type_name(node->consttype,
    3070              :                                                node->consttypmod));
    3071           19 :         return;
    3072              :     }
    3073              : 
    3074         1856 :     getTypeOutputInfo(node->consttype,
    3075              :                       &typoutput, &typIsVarlena);
    3076         1856 :     extval = OidOutputFunctionCall(typoutput, node->constvalue);
    3077              : 
    3078         1856 :     switch (node->consttype)
    3079              :     {
    3080         1773 :         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         1773 :                 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
    3093              :                 {
    3094         1773 :                     if (extval[0] == '+' || extval[0] == '-')
    3095            1 :                         appendStringInfo(buf, "(%s)", extval);
    3096              :                     else
    3097         1772 :                         appendStringInfoString(buf, extval);
    3098         1773 :                     if (strcspn(extval, "eE.") != strlen(extval))
    3099            2 :                         isfloat = true; /* it looks like a float */
    3100              :                 }
    3101              :                 else
    3102            0 :                     appendStringInfo(buf, "'%s'", extval);
    3103              :             }
    3104         1773 :             break;
    3105            0 :         case BITOID:
    3106              :         case VARBITOID:
    3107            0 :             appendStringInfo(buf, "B'%s'", extval);
    3108            0 :             break;
    3109            2 :         case BOOLOID:
    3110            2 :             if (strcmp(extval, "t") == 0)
    3111            2 :                 appendStringInfoString(buf, "true");
    3112              :             else
    3113            0 :                 appendStringInfoString(buf, "false");
    3114            2 :             break;
    3115           81 :         default:
    3116           81 :             deparseStringLiteral(buf, extval);
    3117           81 :             isstring = true;
    3118           81 :             break;
    3119              :     }
    3120              : 
    3121         1856 :     pfree(extval);
    3122              : 
    3123         1856 :     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         1856 :     switch (node->consttype)
    3134              :     {
    3135         1531 :         case BOOLOID:
    3136              :         case INT4OID:
    3137              :         case UNKNOWNOID:
    3138         1531 :             needlabel = false;
    3139         1531 :             break;
    3140           21 :         case NUMERICOID:
    3141           21 :             needlabel = !isfloat || (node->consttypmod >= 0);
    3142           21 :             break;
    3143          304 :         default:
    3144          304 :             if (showtype == -2)
    3145              :             {
    3146              :                 /* label unless we printed it as an untyped string */
    3147           43 :                 needlabel = !isstring;
    3148              :             }
    3149              :             else
    3150          261 :                 needlabel = true;
    3151          304 :             break;
    3152              :     }
    3153         1856 :     if (needlabel || showtype > 0)
    3154          280 :         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           43 : deparseParam(Param *node, deparse_expr_cxt *context)
    3169              : {
    3170           43 :     if (context->params_list)
    3171              :     {
    3172           23 :         int         pindex = 0;
    3173              :         ListCell   *lc;
    3174              : 
    3175              :         /* find its index in params_list */
    3176           25 :         foreach(lc, *context->params_list)
    3177              :         {
    3178            4 :             pindex++;
    3179            4 :             if (equal(node, (Node *) lfirst(lc)))
    3180            2 :                 break;
    3181              :         }
    3182           23 :         if (lc == NULL)
    3183              :         {
    3184              :             /* not in list, so add it */
    3185           21 :             pindex++;
    3186           21 :             *context->params_list = lappend(*context->params_list, node);
    3187              :         }
    3188              : 
    3189           23 :         printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
    3190              :     }
    3191              :     else
    3192              :     {
    3193           20 :         printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
    3194              :     }
    3195           43 : }
    3196              : 
    3197              : /*
    3198              :  * Deparse a container subscript expression.
    3199              :  */
    3200              : static void
    3201            1 : deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
    3202              : {
    3203            1 :     StringInfo  buf = context->buf;
    3204              :     ListCell   *lowlist_item;
    3205              :     ListCell   *uplist_item;
    3206              : 
    3207              :     /* Always parenthesize the expression. */
    3208            1 :     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            1 :     if (IsA(node->refexpr, Var))
    3217            0 :         deparseExpr(node->refexpr, context);
    3218              :     else
    3219              :     {
    3220            1 :         appendStringInfoChar(buf, '(');
    3221            1 :         deparseExpr(node->refexpr, context);
    3222            1 :         appendStringInfoChar(buf, ')');
    3223              :     }
    3224              : 
    3225              :     /* Deparse subscript expressions. */
    3226            1 :     lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
    3227            2 :     foreach(uplist_item, node->refupperindexpr)
    3228              :     {
    3229            1 :         appendStringInfoChar(buf, '[');
    3230            1 :         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            1 :         deparseExpr(lfirst(uplist_item), context);
    3237            1 :         appendStringInfoChar(buf, ']');
    3238              :     }
    3239              : 
    3240            1 :     appendStringInfoChar(buf, ')');
    3241            1 : }
    3242              : 
    3243              : /*
    3244              :  * Deparse a function call.
    3245              :  */
    3246              : static void
    3247           58 : deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
    3248              : {
    3249           58 :     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           58 :     if (node->funcformat == COERCE_IMPLICIT_CAST)
    3259              :     {
    3260           21 :         deparseExpr((Expr *) linitial(node->args), context);
    3261           21 :         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           37 :     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           37 :     use_variadic = node->funcvariadic;
    3284              : 
    3285              :     /*
    3286              :      * Normal function: display as proname(args).
    3287              :      */
    3288           37 :     appendFunctionName(node->funcid, context);
    3289           37 :     appendStringInfoChar(buf, '(');
    3290              : 
    3291              :     /* ... and all the arguments */
    3292           37 :     first = true;
    3293           78 :     foreach(arg, node->args)
    3294              :     {
    3295           41 :         if (!first)
    3296            4 :             appendStringInfoString(buf, ", ");
    3297           41 :         if (use_variadic && lnext(node->args, arg) == NULL)
    3298            0 :             appendStringInfoString(buf, "VARIADIC ");
    3299           41 :         deparseExpr((Expr *) lfirst(arg), context);
    3300           41 :         first = false;
    3301              :     }
    3302           37 :     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         2811 : deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
    3311              : {
    3312         2811 :     StringInfo  buf = context->buf;
    3313              :     HeapTuple   tuple;
    3314              :     Form_pg_operator form;
    3315              :     Expr       *right;
    3316         2811 :     bool        canSuppressRightConstCast = false;
    3317              :     char        oprkind;
    3318              : 
    3319              :     /* Retrieve information about the operator from system catalog. */
    3320         2811 :     tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
    3321         2811 :     if (!HeapTupleIsValid(tuple))
    3322            0 :         elog(ERROR, "cache lookup failed for operator %u", node->opno);
    3323         2811 :     form = (Form_pg_operator) GETSTRUCT(tuple);
    3324         2811 :     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         2811 :     right = llast(node->args);
    3331              : 
    3332              :     /* Always parenthesize the expression. */
    3333         2811 :     appendStringInfoChar(buf, '(');
    3334              : 
    3335              :     /* Deparse left operand, if any. */
    3336         2811 :     if (oprkind == 'b')
    3337              :     {
    3338         2808 :         Expr       *left = linitial(node->args);
    3339         2808 :         Oid         leftType = exprType((Node *) left);
    3340         2808 :         Oid         rightType = exprType((Node *) right);
    3341         2808 :         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         2808 :         if (leftType == rightType)
    3370              :         {
    3371         2792 :             if (IsA(left, Const))
    3372            3 :                 canSuppressLeftConstCast = isPlainForeignVar(right, context);
    3373         2789 :             else if (IsA(right, Const))
    3374         1547 :                 canSuppressRightConstCast = isPlainForeignVar(left, context);
    3375              :         }
    3376              : 
    3377         2808 :         if (canSuppressLeftConstCast)
    3378            2 :             deparseConst((Const *) left, context, -2);
    3379              :         else
    3380         2806 :             deparseExpr(left, context);
    3381              : 
    3382         2808 :         appendStringInfoChar(buf, ' ');
    3383              :     }
    3384              : 
    3385              :     /* Deparse operator name. */
    3386         2811 :     deparseOperatorName(buf, form);
    3387              : 
    3388              :     /* Deparse right operand. */
    3389         2811 :     appendStringInfoChar(buf, ' ');
    3390              : 
    3391         2811 :     if (canSuppressRightConstCast)
    3392         1290 :         deparseConst((Const *) right, context, -2);
    3393              :     else
    3394         1521 :         deparseExpr(right, context);
    3395              : 
    3396         2811 :     appendStringInfoChar(buf, ')');
    3397              : 
    3398         2811 :     ReleaseSysCache(tuple);
    3399         2811 : }
    3400              : 
    3401              : /*
    3402              :  * Will "node" deparse as a plain foreign Var?
    3403              :  */
    3404              : static bool
    3405         1550 : 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         1550 :     if (IsA(node, RelabelType) &&
    3417            5 :         ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
    3418            5 :         node = ((RelabelType *) node)->arg;
    3419              : 
    3420         1550 :     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         1292 :         Var        *var = (Var *) node;
    3427         1292 :         Relids      relids = context->scanrel->relids;
    3428              : 
    3429         1292 :         if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
    3430         1292 :             return true;
    3431              :     }
    3432              : 
    3433          258 :     return false;
    3434              : }
    3435              : 
    3436              : /*
    3437              :  * Print the name of an operator.
    3438              :  */
    3439              : static void
    3440         2826 : 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         2826 :     opname = NameStr(opform->oprname);
    3446              : 
    3447              :     /* Print schema name only if it's not pg_catalog */
    3448         2826 :     if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
    3449              :     {
    3450              :         const char *opnspname;
    3451              : 
    3452           13 :         opnspname = get_namespace_name(opform->oprnamespace);
    3453              :         /* Print fully qualified operator name. */
    3454           13 :         appendStringInfo(buf, "OPERATOR(%s.%s)",
    3455              :                          quote_identifier(opnspname), opname);
    3456              :     }
    3457              :     else
    3458              :     {
    3459              :         /* Just print operator name. */
    3460         2813 :         appendStringInfoString(buf, opname);
    3461              :     }
    3462         2826 : }
    3463              : 
    3464              : /*
    3465              :  * Deparse IS DISTINCT FROM.
    3466              :  */
    3467              : static void
    3468            1 : deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
    3469              : {
    3470            1 :     StringInfo  buf = context->buf;
    3471              : 
    3472              :     Assert(list_length(node->args) == 2);
    3473              : 
    3474            1 :     appendStringInfoChar(buf, '(');
    3475            1 :     deparseExpr(linitial(node->args), context);
    3476            1 :     appendStringInfoString(buf, " IS DISTINCT FROM ");
    3477            1 :     deparseExpr(lsecond(node->args), context);
    3478            1 :     appendStringInfoChar(buf, ')');
    3479            1 : }
    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            7 : deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
    3487              : {
    3488            7 :     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            7 :     tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
    3496            7 :     if (!HeapTupleIsValid(tuple))
    3497            0 :         elog(ERROR, "cache lookup failed for operator %u", node->opno);
    3498            7 :     form = (Form_pg_operator) GETSTRUCT(tuple);
    3499              : 
    3500              :     /* Sanity check. */
    3501              :     Assert(list_length(node->args) == 2);
    3502              : 
    3503              :     /* Always parenthesize the expression. */
    3504            7 :     appendStringInfoChar(buf, '(');
    3505              : 
    3506              :     /* Deparse left operand. */
    3507            7 :     arg1 = linitial(node->args);
    3508            7 :     deparseExpr(arg1, context);
    3509            7 :     appendStringInfoChar(buf, ' ');
    3510              : 
    3511              :     /* Deparse operator name plus decoration. */
    3512            7 :     deparseOperatorName(buf, form);
    3513            7 :     appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
    3514              : 
    3515              :     /* Deparse right operand. */
    3516            7 :     arg2 = lsecond(node->args);
    3517            7 :     deparseExpr(arg2, context);
    3518              : 
    3519            7 :     appendStringInfoChar(buf, ')');
    3520              : 
    3521              :     /* Always parenthesize the expression. */
    3522            7 :     appendStringInfoChar(buf, ')');
    3523              : 
    3524            7 :     ReleaseSysCache(tuple);
    3525            7 : }
    3526              : 
    3527              : /*
    3528              :  * Deparse a RelabelType (binary-compatible cast) node.
    3529              :  */
    3530              : static void
    3531           36 : deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
    3532              : {
    3533           36 :     deparseExpr(node->arg, context);
    3534           36 :     if (node->relabelformat != COERCE_IMPLICIT_CAST)
    3535            0 :         appendStringInfo(context->buf, "::%s",
    3536              :                          deparse_type_name(node->resulttype,
    3537              :                                            node->resulttypmod));
    3538           36 : }
    3539              : 
    3540              : /*
    3541              :  * Deparse an ArrayCoerceExpr (array-type conversion) node.
    3542              :  */
    3543              : static void
    3544            3 : deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context)
    3545              : {
    3546            3 :     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            3 :     if (node->coerceformat != COERCE_IMPLICIT_CAST)
    3553            0 :         appendStringInfo(context->buf, "::%s",
    3554              :                          deparse_type_name(node->resulttype,
    3555              :                                            node->resulttypmod));
    3556            3 : }
    3557              : 
    3558              : /*
    3559              :  * Deparse a BoolExpr node.
    3560              :  */
    3561              : static void
    3562           38 : deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
    3563              : {
    3564           38 :     StringInfo  buf = context->buf;
    3565           38 :     const char *op = NULL;      /* keep compiler quiet */
    3566              :     bool        first;
    3567              :     ListCell   *lc;
    3568              : 
    3569           38 :     switch (node->boolop)
    3570              :     {
    3571           18 :         case AND_EXPR:
    3572           18 :             op = "AND";
    3573           18 :             break;
    3574           20 :         case OR_EXPR:
    3575           20 :             op = "OR";
    3576           20 :             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           38 :     appendStringInfoChar(buf, '(');
    3585           38 :     first = true;
    3586          114 :     foreach(lc, node->args)
    3587              :     {
    3588           76 :         if (!first)
    3589           38 :             appendStringInfo(buf, " %s ", op);
    3590           76 :         deparseExpr((Expr *) lfirst(lc), context);
    3591           76 :         first = false;
    3592              :     }
    3593           38 :     appendStringInfoChar(buf, ')');
    3594              : }
    3595              : 
    3596              : /*
    3597              :  * Deparse IS [NOT] NULL expression.
    3598              :  */
    3599              : static void
    3600           26 : deparseNullTest(NullTest *node, deparse_expr_cxt *context)
    3601              : {
    3602           26 :     StringInfo  buf = context->buf;
    3603              : 
    3604           26 :     appendStringInfoChar(buf, '(');
    3605           26 :     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           26 :     if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
    3614              :     {
    3615           26 :         if (node->nulltesttype == IS_NULL)
    3616           19 :             appendStringInfoString(buf, " IS NULL)");
    3617              :         else
    3618            7 :             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           26 : }
    3628              : 
    3629              : /*
    3630              :  * Deparse CASE expression
    3631              :  */
    3632              : static void
    3633           21 : deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
    3634              : {
    3635           21 :     StringInfo  buf = context->buf;
    3636              :     ListCell   *lc;
    3637              : 
    3638           21 :     appendStringInfoString(buf, "(CASE");
    3639              : 
    3640              :     /* If this is a CASE arg WHEN then emit the arg expression */
    3641           21 :     if (node->arg != NULL)
    3642              :     {
    3643            9 :         appendStringInfoChar(buf, ' ');
    3644            9 :         deparseExpr(node->arg, context);
    3645              :     }
    3646              : 
    3647              :     /* Add each condition/result of the CASE clause */
    3648           49 :     foreach(lc, node->args)
    3649              :     {
    3650           28 :         CaseWhen   *whenclause = (CaseWhen *) lfirst(lc);
    3651              : 
    3652              :         /* WHEN */
    3653           28 :         appendStringInfoString(buf, " WHEN ");
    3654           28 :         if (node->arg == NULL)   /* CASE WHEN */
    3655           12 :             deparseExpr(whenclause->expr, context);
    3656              :         else                    /* CASE arg WHEN */
    3657              :         {
    3658              :             /* Ignore the CaseTestExpr and equality operator. */
    3659           16 :             deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
    3660              :                         context);
    3661              :         }
    3662              : 
    3663              :         /* THEN */
    3664           28 :         appendStringInfoString(buf, " THEN ");
    3665           28 :         deparseExpr(whenclause->result, context);
    3666              :     }
    3667              : 
    3668              :     /* add ELSE if present */
    3669           21 :     if (node->defresult != NULL)
    3670              :     {
    3671           21 :         appendStringInfoString(buf, " ELSE ");
    3672           21 :         deparseExpr(node->defresult, context);
    3673              :     }
    3674              : 
    3675              :     /* append END */
    3676           21 :     appendStringInfoString(buf, " END)");
    3677           21 : }
    3678              : 
    3679              : /*
    3680              :  * Deparse ARRAY[...] construct.
    3681              :  */
    3682              : static void
    3683            4 : deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
    3684              : {
    3685            4 :     StringInfo  buf = context->buf;
    3686            4 :     bool        first = true;
    3687              :     ListCell   *lc;
    3688              : 
    3689            4 :     appendStringInfoString(buf, "ARRAY[");
    3690           12 :     foreach(lc, node->elements)
    3691              :     {
    3692            8 :         if (!first)
    3693            4 :             appendStringInfoString(buf, ", ");
    3694            8 :         deparseExpr(lfirst(lc), context);
    3695            8 :         first = false;
    3696              :     }
    3697            4 :     appendStringInfoChar(buf, ']');
    3698              : 
    3699              :     /* If the array is empty, we need an explicit cast to the array type. */
    3700            4 :     if (node->elements == NIL)
    3701            0 :         appendStringInfo(buf, "::%s",
    3702              :                          deparse_type_name(node->array_typeid, -1));
    3703            4 : }
    3704              : 
    3705              : /*
    3706              :  * Deparse an Aggref node.
    3707              :  */
    3708              : static void
    3709          263 : deparseAggref(Aggref *node, deparse_expr_cxt *context)
    3710              : {
    3711          263 :     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          263 :     use_variadic = node->aggvariadic;
    3719              : 
    3720              :     /* Find aggregate name from aggfnoid which is a pg_proc entry */
    3721          263 :     appendFunctionName(node->aggfnoid, context);
    3722          263 :     appendStringInfoChar(buf, '(');
    3723              : 
    3724              :     /* Add DISTINCT */
    3725          263 :     appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
    3726              : 
    3727          263 :     if (AGGKIND_IS_ORDERED_SET(node->aggkind))
    3728              :     {
    3729              :         /* Add WITHIN GROUP (ORDER BY ..) */
    3730              :         ListCell   *arg;
    3731            8 :         bool        first = true;
    3732              : 
    3733              :         Assert(!node->aggvariadic);
    3734              :         Assert(node->aggorder != NIL);
    3735              : 
    3736           18 :         foreach(arg, node->aggdirectargs)
    3737              :         {
    3738           10 :             if (!first)
    3739            2 :                 appendStringInfoString(buf, ", ");
    3740           10 :             first = false;
    3741              : 
    3742           10 :             deparseExpr((Expr *) lfirst(arg), context);
    3743              :         }
    3744              : 
    3745            8 :         appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
    3746            8 :         appendAggOrderBy(node->aggorder, node->args, context);
    3747              :     }
    3748              :     else
    3749              :     {
    3750              :         /* aggstar can be set only in zero-argument aggregates */
    3751          255 :         if (node->aggstar)
    3752           76 :             appendStringInfoChar(buf, '*');
    3753              :         else
    3754              :         {
    3755              :             ListCell   *arg;
    3756          179 :             bool        first = true;
    3757              : 
    3758              :             /* Add all the arguments */
    3759          362 :             foreach(arg, node->args)
    3760              :             {
    3761          183 :                 TargetEntry *tle = (TargetEntry *) lfirst(arg);
    3762          183 :                 Node       *n = (Node *) tle->expr;
    3763              : 
    3764          183 :                 if (tle->resjunk)
    3765            4 :                     continue;
    3766              : 
    3767          179 :                 if (!first)
    3768            0 :                     appendStringInfoString(buf, ", ");
    3769          179 :                 first = false;
    3770              : 
    3771              :                 /* Add VARIADIC */
    3772          179 :                 if (use_variadic && lnext(node->args, arg) == NULL)
    3773            2 :                     appendStringInfoString(buf, "VARIADIC ");
    3774              : 
    3775          179 :                 deparseExpr((Expr *) n, context);
    3776              :             }
    3777              :         }
    3778              : 
    3779              :         /* Add ORDER BY */
    3780          255 :         if (node->aggorder != NIL)
    3781              :         {
    3782           22 :             appendStringInfoString(buf, " ORDER BY ");
    3783           22 :             appendAggOrderBy(node->aggorder, node->args, context);
    3784              :         }
    3785              :     }
    3786              : 
    3787              :     /* Add FILTER (WHERE ..) */
    3788          263 :     if (node->aggfilter != NULL)
    3789              :     {
    3790           12 :         appendStringInfoString(buf, ") FILTER (WHERE ");
    3791           12 :         deparseExpr((Expr *) node->aggfilter, context);
    3792              :     }
    3793              : 
    3794          263 :     appendStringInfoChar(buf, ')');
    3795          263 : }
    3796              : 
    3797              : /*
    3798              :  * Append ORDER BY within aggregate function.
    3799              :  */
    3800              : static void
    3801           30 : appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
    3802              : {
    3803           30 :     StringInfo  buf = context->buf;
    3804              :     ListCell   *lc;
    3805           30 :     bool        first = true;
    3806              : 
    3807           62 :     foreach(lc, orderList)
    3808              :     {
    3809           32 :         SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
    3810              :         Node       *sortexpr;
    3811              : 
    3812           32 :         if (!first)
    3813            2 :             appendStringInfoString(buf, ", ");
    3814           32 :         first = false;
    3815              : 
    3816              :         /* Deparse the sort expression proper. */
    3817           32 :         sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
    3818              :                                           false, context);
    3819              :         /* Add decoration as needed. */
    3820           32 :         appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
    3821              :                             context);
    3822              :     }
    3823           30 : }
    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          909 : appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first,
    3831              :                     deparse_expr_cxt *context)
    3832              : {
    3833          909 :     StringInfo  buf = context->buf;
    3834              :     TypeCacheEntry *typentry;
    3835              : 
    3836              :     /* See whether operator is default < or > for sort expr's datatype. */
    3837          909 :     typentry = lookup_type_cache(sortcoltype,
    3838              :                                  TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
    3839              : 
    3840          909 :     if (sortop == typentry->lt_opr)
    3841          886 :         appendStringInfoString(buf, " ASC");
    3842           23 :     else if (sortop == typentry->gt_opr)
    3843           15 :         appendStringInfoString(buf, " DESC");
    3844              :     else
    3845              :     {
    3846              :         HeapTuple   opertup;
    3847              :         Form_pg_operator operform;
    3848              : 
    3849            8 :         appendStringInfoString(buf, " USING ");
    3850              : 
    3851              :         /* Append operator name. */
    3852            8 :         opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(sortop));
    3853            8 :         if (!HeapTupleIsValid(opertup))
    3854            0 :             elog(ERROR, "cache lookup failed for operator %u", sortop);
    3855            8 :         operform = (Form_pg_operator) GETSTRUCT(opertup);
    3856            8 :         deparseOperatorName(buf, operform);
    3857            8 :         ReleaseSysCache(opertup);
    3858              :     }
    3859              : 
    3860          909 :     if (nulls_first)
    3861           11 :         appendStringInfoString(buf, " NULLS FIRST");
    3862              :     else
    3863          898 :         appendStringInfoString(buf, " NULLS LAST");
    3864          909 : }
    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           36 : printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
    3876              :                  deparse_expr_cxt *context)
    3877              : {
    3878           36 :     StringInfo  buf = context->buf;
    3879           36 :     char       *ptypename = deparse_type_name(paramtype, paramtypmod);
    3880              : 
    3881           36 :     appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
    3882           36 : }
    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          234 : printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
    3902              :                        deparse_expr_cxt *context)
    3903              : {
    3904          234 :     StringInfo  buf = context->buf;
    3905          234 :     char       *ptypename = deparse_type_name(paramtype, paramtypmod);
    3906              : 
    3907          234 :     appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
    3908          234 : }
    3909              : 
    3910              : /*
    3911              :  * Deparse GROUP BY clause.
    3912              :  */
    3913              : static void
    3914          166 : appendGroupByClause(List *tlist, deparse_expr_cxt *context)
    3915              : {
    3916          166 :     StringInfo  buf = context->buf;
    3917          166 :     Query      *query = context->root->parse;
    3918              :     ListCell   *lc;
    3919          166 :     bool        first = true;
    3920              : 
    3921              :     /* Nothing to be done, if there's no GROUP BY clause in the query. */
    3922          166 :     if (!query->groupClause)
    3923           65 :         return;
    3924              : 
    3925          101 :     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          214 :     foreach(lc, query->groupClause)
    3941              :     {
    3942          113 :         SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
    3943              : 
    3944          113 :         if (!first)
    3945           12 :             appendStringInfoString(buf, ", ");
    3946          113 :         first = false;
    3947              : 
    3948          113 :         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          750 : appendOrderByClause(List *pathkeys, bool has_final_sort,
    3963              :                     deparse_expr_cxt *context)
    3964              : {
    3965              :     ListCell   *lcell;
    3966              :     int         nestlevel;
    3967          750 :     StringInfo  buf = context->buf;
    3968          750 :     bool        gotone = false;
    3969              : 
    3970              :     /* Make sure any constants in the exprs are printed portably */
    3971          750 :     nestlevel = set_transmission_modes();
    3972              : 
    3973         1633 :     foreach(lcell, pathkeys)
    3974              :     {
    3975          883 :         PathKey    *pathkey = lfirst(lcell);
    3976              :         EquivalenceMember *em;
    3977              :         Expr       *em_expr;
    3978              :         Oid         oprid;
    3979              : 
    3980          883 :         if (has_final_sort)
    3981              :         {
    3982              :             /*
    3983              :              * By construction, context->foreignrel is the input relation to
    3984              :              * the final sort.
    3985              :              */
    3986          207 :             em = find_em_for_rel_target(context->root,
    3987              :                                         pathkey->pk_eclass,
    3988              :                                         context->foreignrel);
    3989              :         }
    3990              :         else
    3991          676 :             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          883 :         if (em == NULL)
    4001            0 :             elog(ERROR, "could not find pathkey item to sort");
    4002              : 
    4003          883 :         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          883 :         if (IsA(em_expr, Const))
    4015            6 :             continue;
    4016              : 
    4017          877 :         if (!gotone)
    4018              :         {
    4019          747 :             appendStringInfoString(buf, " ORDER BY ");
    4020          747 :             gotone = true;
    4021              :         }
    4022              :         else
    4023          130 :             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          877 :         oprid = get_opfamily_member_for_cmptype(pathkey->pk_opfamily,
    4031              :                                                 em->em_datatype,
    4032              :                                                 em->em_datatype,
    4033              :                                                 pathkey->pk_cmptype);
    4034          877 :         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          877 :         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          877 :         appendOrderBySuffix(oprid, exprType((Node *) em_expr),
    4046          877 :                             pathkey->pk_nulls_first, context);
    4047              : 
    4048              :     }
    4049          750 :     reset_transmission_modes(nestlevel);
    4050          750 : }
    4051              : 
    4052              : /*
    4053              :  * Deparse LIMIT/OFFSET clause.
    4054              :  */
    4055              : static void
    4056          146 : appendLimitClause(deparse_expr_cxt *context)
    4057              : {
    4058          146 :     PlannerInfo *root = context->root;
    4059          146 :     StringInfo  buf = context->buf;
    4060              :     int         nestlevel;
    4061              : 
    4062              :     /* Make sure any constants in the exprs are printed portably */
    4063          146 :     nestlevel = set_transmission_modes();
    4064              : 
    4065          146 :     if (root->parse->limitCount)
    4066              :     {
    4067          146 :         appendStringInfoString(buf, " LIMIT ");
    4068          146 :         deparseExpr((Expr *) root->parse->limitCount, context);
    4069              :     }
    4070          146 :     if (root->parse->limitOffset)
    4071              :     {
    4072           75 :         appendStringInfoString(buf, " OFFSET ");
    4073           75 :         deparseExpr((Expr *) root->parse->limitOffset, context);
    4074              :     }
    4075              : 
    4076          146 :     reset_transmission_modes(nestlevel);
    4077          146 : }
    4078              : 
    4079              : /*
    4080              :  * appendFunctionName
    4081              :  *      Deparses function name from given function oid.
    4082              :  */
    4083              : static void
    4084          300 : appendFunctionName(Oid funcid, deparse_expr_cxt *context)
    4085              : {
    4086          300 :     StringInfo  buf = context->buf;
    4087              :     HeapTuple   proctup;
    4088              :     Form_pg_proc procform;
    4089              :     const char *proname;
    4090              : 
    4091          300 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    4092          300 :     if (!HeapTupleIsValid(proctup))
    4093            0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    4094          300 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
    4095              : 
    4096              :     /* Print schema name only if it's not pg_catalog */
    4097          300 :     if (procform->pronamespace != PG_CATALOG_NAMESPACE)
    4098              :     {
    4099              :         const char *schemaname;
    4100              : 
    4101            6 :         schemaname = get_namespace_name(procform->pronamespace);
    4102            6 :         appendStringInfo(buf, "%s.", quote_identifier(schemaname));
    4103              :     }
    4104              : 
    4105              :     /* Always print the function name */
    4106          300 :     proname = NameStr(procform->proname);
    4107          300 :     appendStringInfoString(buf, quote_identifier(proname));
    4108              : 
    4109          300 :     ReleaseSysCache(proctup);
    4110          300 : }
    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          145 : deparseSortGroupClause(Index ref, List *tlist, bool force_colno,
    4120              :                        deparse_expr_cxt *context)
    4121              : {
    4122          145 :     StringInfo  buf = context->buf;
    4123              :     TargetEntry *tle;
    4124              :     Expr       *expr;
    4125              : 
    4126          145 :     tle = get_sortgroupref_tle(ref, tlist);
    4127          145 :     expr = tle->expr;
    4128              : 
    4129          145 :     if (force_colno)
    4130              :     {
    4131              :         /* Use column-number form when requested by caller. */
    4132              :         Assert(!tle->resjunk);
    4133          113 :         appendStringInfo(buf, "%d", tle->resno);
    4134              :     }
    4135           32 :     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           32 :     else if (!expr || IsA(expr, Var))
    4145           18 :         deparseExpr(expr, context);
    4146              :     else
    4147              :     {
    4148              :         /* Always parenthesize the expression. */
    4149           14 :         appendStringInfoChar(buf, '(');
    4150           14 :         deparseExpr(expr, context);
    4151           14 :         appendStringInfoChar(buf, ')');
    4152              :     }
    4153              : 
    4154          145 :     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         8707 : is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
    4165              : {
    4166         8707 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    4167         8707 :     RelOptInfo *outerrel = fpinfo->outerrel;
    4168         8707 :     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         8707 :     if (!IS_JOIN_REL(foreignrel))
    4178         2094 :         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         6613 :     if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
    4185         6447 :         return false;
    4186              : 
    4187          166 :     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           56 :         if (fpinfo->make_outerrel_subquery)
    4194              :         {
    4195           42 :             get_relation_column_alias_ids(node, outerrel, relno, colno);
    4196           42 :             return true;
    4197              :         }
    4198              : 
    4199              :         /* Otherwise, recurse into the outer relation. */
    4200           14 :         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          110 :         if (fpinfo->make_innerrel_subquery)
    4211              :         {
    4212          110 :             get_relation_column_alias_ids(node, innerrel, relno, colno);
    4213          110 :             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          152 : get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
    4227              :                               int *relno, int *colno)
    4228              : {
    4229          152 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    4230              :     int         i;
    4231              :     ListCell   *lc;
    4232              : 
    4233              :     /* Get the relation alias ID */
    4234          152 :     *relno = fpinfo->relation_index;
    4235              : 
    4236              :     /* Get the column alias ID */
    4237          152 :     i = 1;
    4238          188 :     foreach(lc, foreignrel->reltarget->exprs)
    4239              :     {
    4240          188 :         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          188 :         if (IsA(tlvar, Var) &&
    4249          188 :             tlvar->varno == node->varno &&
    4250          180 :             tlvar->varattno == node->varattno)
    4251              :         {
    4252          152 :             *colno = i;
    4253          152 :             return;
    4254              :         }
    4255           36 :         i++;
    4256              :     }
    4257              : 
    4258              :     /* Shouldn't get here */
    4259            0 :     elog(ERROR, "unexpected expression in subquery output");
    4260              : }
        

Generated by: LCOV version 2.0-1