LCOV - code coverage report
Current view: top level - contrib/postgres_fdw - deparse.c (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 1006 1119 89.9 %
Date: 2018-05-21 18:20:01 Functions: 51 51 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13