LCOV - code coverage report
Current view: top level - contrib/postgres_fdw - postgres_fdw.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 2106 2278 92.4 %
Date: 2025-07-08 19:18:10 Functions: 88 89 98.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * postgres_fdw.c
       4             :  *        Foreign-data wrapper for remote PostgreSQL servers
       5             :  *
       6             :  * Portions Copyright (c) 2012-2025, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *        contrib/postgres_fdw/postgres_fdw.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include <limits.h>
      16             : 
      17             : #include "access/htup_details.h"
      18             : #include "access/sysattr.h"
      19             : #include "access/table.h"
      20             : #include "catalog/pg_opfamily.h"
      21             : #include "commands/defrem.h"
      22             : #include "commands/explain_format.h"
      23             : #include "commands/explain_state.h"
      24             : #include "executor/execAsync.h"
      25             : #include "foreign/fdwapi.h"
      26             : #include "funcapi.h"
      27             : #include "miscadmin.h"
      28             : #include "nodes/makefuncs.h"
      29             : #include "nodes/nodeFuncs.h"
      30             : #include "optimizer/appendinfo.h"
      31             : #include "optimizer/cost.h"
      32             : #include "optimizer/inherit.h"
      33             : #include "optimizer/optimizer.h"
      34             : #include "optimizer/pathnode.h"
      35             : #include "optimizer/paths.h"
      36             : #include "optimizer/planmain.h"
      37             : #include "optimizer/prep.h"
      38             : #include "optimizer/restrictinfo.h"
      39             : #include "optimizer/tlist.h"
      40             : #include "parser/parsetree.h"
      41             : #include "postgres_fdw.h"
      42             : #include "storage/latch.h"
      43             : #include "utils/builtins.h"
      44             : #include "utils/float.h"
      45             : #include "utils/guc.h"
      46             : #include "utils/lsyscache.h"
      47             : #include "utils/memutils.h"
      48             : #include "utils/rel.h"
      49             : #include "utils/sampling.h"
      50             : #include "utils/selfuncs.h"
      51             : 
      52          28 : PG_MODULE_MAGIC_EXT(
      53             :                     .name = "postgres_fdw",
      54             :                     .version = PG_VERSION
      55             : );
      56             : 
      57             : /* Default CPU cost to start up a foreign query. */
      58             : #define DEFAULT_FDW_STARTUP_COST    100.0
      59             : 
      60             : /* Default CPU cost to process 1 row (above and beyond cpu_tuple_cost). */
      61             : #define DEFAULT_FDW_TUPLE_COST      0.2
      62             : 
      63             : /* If no remote estimates, assume a sort costs 20% extra */
      64             : #define DEFAULT_FDW_SORT_MULTIPLIER 1.2
      65             : 
      66             : /*
      67             :  * Indexes of FDW-private information stored in fdw_private lists.
      68             :  *
      69             :  * These items are indexed with the enum FdwScanPrivateIndex, so an item
      70             :  * can be fetched with list_nth().  For example, to get the SELECT statement:
      71             :  *      sql = strVal(list_nth(fdw_private, FdwScanPrivateSelectSql));
      72             :  */
      73             : enum FdwScanPrivateIndex
      74             : {
      75             :     /* SQL statement to execute remotely (as a String node) */
      76             :     FdwScanPrivateSelectSql,
      77             :     /* Integer list of attribute numbers retrieved by the SELECT */
      78             :     FdwScanPrivateRetrievedAttrs,
      79             :     /* Integer representing the desired fetch_size */
      80             :     FdwScanPrivateFetchSize,
      81             : 
      82             :     /*
      83             :      * String describing join i.e. names of relations being joined and types
      84             :      * of join, added when the scan is join
      85             :      */
      86             :     FdwScanPrivateRelations,
      87             : };
      88             : 
      89             : /*
      90             :  * Similarly, this enum describes what's kept in the fdw_private list for
      91             :  * a ModifyTable node referencing a postgres_fdw foreign table.  We store:
      92             :  *
      93             :  * 1) INSERT/UPDATE/DELETE statement text to be sent to the remote server
      94             :  * 2) Integer list of target attribute numbers for INSERT/UPDATE
      95             :  *    (NIL for a DELETE)
      96             :  * 3) Length till the end of VALUES clause for INSERT
      97             :  *    (-1 for a DELETE/UPDATE)
      98             :  * 4) Boolean flag showing if the remote query has a RETURNING clause
      99             :  * 5) Integer list of attribute numbers retrieved by RETURNING, if any
     100             :  */
     101             : enum FdwModifyPrivateIndex
     102             : {
     103             :     /* SQL statement to execute remotely (as a String node) */
     104             :     FdwModifyPrivateUpdateSql,
     105             :     /* Integer list of target attribute numbers for INSERT/UPDATE */
     106             :     FdwModifyPrivateTargetAttnums,
     107             :     /* Length till the end of VALUES clause (as an Integer node) */
     108             :     FdwModifyPrivateLen,
     109             :     /* has-returning flag (as a Boolean node) */
     110             :     FdwModifyPrivateHasReturning,
     111             :     /* Integer list of attribute numbers retrieved by RETURNING */
     112             :     FdwModifyPrivateRetrievedAttrs,
     113             : };
     114             : 
     115             : /*
     116             :  * Similarly, this enum describes what's kept in the fdw_private list for
     117             :  * a ForeignScan node that modifies a foreign table directly.  We store:
     118             :  *
     119             :  * 1) UPDATE/DELETE statement text to be sent to the remote server
     120             :  * 2) Boolean flag showing if the remote query has a RETURNING clause
     121             :  * 3) Integer list of attribute numbers retrieved by RETURNING, if any
     122             :  * 4) Boolean flag showing if we set the command es_processed
     123             :  */
     124             : enum FdwDirectModifyPrivateIndex
     125             : {
     126             :     /* SQL statement to execute remotely (as a String node) */
     127             :     FdwDirectModifyPrivateUpdateSql,
     128             :     /* has-returning flag (as a Boolean node) */
     129             :     FdwDirectModifyPrivateHasReturning,
     130             :     /* Integer list of attribute numbers retrieved by RETURNING */
     131             :     FdwDirectModifyPrivateRetrievedAttrs,
     132             :     /* set-processed flag (as a Boolean node) */
     133             :     FdwDirectModifyPrivateSetProcessed,
     134             : };
     135             : 
     136             : /*
     137             :  * Execution state of a foreign scan using postgres_fdw.
     138             :  */
     139             : typedef struct PgFdwScanState
     140             : {
     141             :     Relation    rel;            /* relcache entry for the foreign table. NULL
     142             :                                  * for a foreign join scan. */
     143             :     TupleDesc   tupdesc;        /* tuple descriptor of scan */
     144             :     AttInMetadata *attinmeta;   /* attribute datatype conversion metadata */
     145             : 
     146             :     /* extracted fdw_private data */
     147             :     char       *query;          /* text of SELECT command */
     148             :     List       *retrieved_attrs;    /* list of retrieved attribute numbers */
     149             : 
     150             :     /* for remote query execution */
     151             :     PGconn     *conn;           /* connection for the scan */
     152             :     PgFdwConnState *conn_state; /* extra per-connection state */
     153             :     unsigned int cursor_number; /* quasi-unique ID for my cursor */
     154             :     bool        cursor_exists;  /* have we created the cursor? */
     155             :     int         numParams;      /* number of parameters passed to query */
     156             :     FmgrInfo   *param_flinfo;   /* output conversion functions for them */
     157             :     List       *param_exprs;    /* executable expressions for param values */
     158             :     const char **param_values;  /* textual values of query parameters */
     159             : 
     160             :     /* for storing result tuples */
     161             :     HeapTuple  *tuples;         /* array of currently-retrieved tuples */
     162             :     int         num_tuples;     /* # of tuples in array */
     163             :     int         next_tuple;     /* index of next one to return */
     164             : 
     165             :     /* batch-level state, for optimizing rewinds and avoiding useless fetch */
     166             :     int         fetch_ct_2;     /* Min(# of fetches done, 2) */
     167             :     bool        eof_reached;    /* true if last fetch reached EOF */
     168             : 
     169             :     /* for asynchronous execution */
     170             :     bool        async_capable;  /* engage asynchronous-capable logic? */
     171             : 
     172             :     /* working memory contexts */
     173             :     MemoryContext batch_cxt;    /* context holding current batch of tuples */
     174             :     MemoryContext temp_cxt;     /* context for per-tuple temporary data */
     175             : 
     176             :     int         fetch_size;     /* number of tuples per fetch */
     177             : } PgFdwScanState;
     178             : 
     179             : /*
     180             :  * Execution state of a foreign insert/update/delete operation.
     181             :  */
     182             : typedef struct PgFdwModifyState
     183             : {
     184             :     Relation    rel;            /* relcache entry for the foreign table */
     185             :     AttInMetadata *attinmeta;   /* attribute datatype conversion metadata */
     186             : 
     187             :     /* for remote query execution */
     188             :     PGconn     *conn;           /* connection for the scan */
     189             :     PgFdwConnState *conn_state; /* extra per-connection state */
     190             :     char       *p_name;         /* name of prepared statement, if created */
     191             : 
     192             :     /* extracted fdw_private data */
     193             :     char       *query;          /* text of INSERT/UPDATE/DELETE command */
     194             :     char       *orig_query;     /* original text of INSERT command */
     195             :     List       *target_attrs;   /* list of target attribute numbers */
     196             :     int         values_end;     /* length up to the end of VALUES */
     197             :     int         batch_size;     /* value of FDW option "batch_size" */
     198             :     bool        has_returning;  /* is there a RETURNING clause? */
     199             :     List       *retrieved_attrs;    /* attr numbers retrieved by RETURNING */
     200             : 
     201             :     /* info about parameters for prepared statement */
     202             :     AttrNumber  ctidAttno;      /* attnum of input resjunk ctid column */
     203             :     int         p_nums;         /* number of parameters to transmit */
     204             :     FmgrInfo   *p_flinfo;       /* output conversion functions for them */
     205             : 
     206             :     /* batch operation stuff */
     207             :     int         num_slots;      /* number of slots to insert */
     208             : 
     209             :     /* working memory context */
     210             :     MemoryContext temp_cxt;     /* context for per-tuple temporary data */
     211             : 
     212             :     /* for update row movement if subplan result rel */
     213             :     struct PgFdwModifyState *aux_fmstate;   /* foreign-insert state, if
     214             :                                              * created */
     215             : } PgFdwModifyState;
     216             : 
     217             : /*
     218             :  * Execution state of a foreign scan that modifies a foreign table directly.
     219             :  */
     220             : typedef struct PgFdwDirectModifyState
     221             : {
     222             :     Relation    rel;            /* relcache entry for the foreign table */
     223             :     AttInMetadata *attinmeta;   /* attribute datatype conversion metadata */
     224             : 
     225             :     /* extracted fdw_private data */
     226             :     char       *query;          /* text of UPDATE/DELETE command */
     227             :     bool        has_returning;  /* is there a RETURNING clause? */
     228             :     List       *retrieved_attrs;    /* attr numbers retrieved by RETURNING */
     229             :     bool        set_processed;  /* do we set the command es_processed? */
     230             : 
     231             :     /* for remote query execution */
     232             :     PGconn     *conn;           /* connection for the update */
     233             :     PgFdwConnState *conn_state; /* extra per-connection state */
     234             :     int         numParams;      /* number of parameters passed to query */
     235             :     FmgrInfo   *param_flinfo;   /* output conversion functions for them */
     236             :     List       *param_exprs;    /* executable expressions for param values */
     237             :     const char **param_values;  /* textual values of query parameters */
     238             : 
     239             :     /* for storing result tuples */
     240             :     PGresult   *result;         /* result for query */
     241             :     int         num_tuples;     /* # of result tuples */
     242             :     int         next_tuple;     /* index of next one to return */
     243             :     MemoryContextCallback result_cb;    /* ensures result will get freed */
     244             :     Relation    resultRel;      /* relcache entry for the target relation */
     245             :     AttrNumber *attnoMap;       /* array of attnums of input user columns */
     246             :     AttrNumber  ctidAttno;      /* attnum of input ctid column */
     247             :     AttrNumber  oidAttno;       /* attnum of input oid column */
     248             :     bool        hasSystemCols;  /* are there system columns of resultRel? */
     249             : 
     250             :     /* working memory context */
     251             :     MemoryContext temp_cxt;     /* context for per-tuple temporary data */
     252             : } PgFdwDirectModifyState;
     253             : 
     254             : /*
     255             :  * Workspace for analyzing a foreign table.
     256             :  */
     257             : typedef struct PgFdwAnalyzeState
     258             : {
     259             :     Relation    rel;            /* relcache entry for the foreign table */
     260             :     AttInMetadata *attinmeta;   /* attribute datatype conversion metadata */
     261             :     List       *retrieved_attrs;    /* attr numbers retrieved by query */
     262             : 
     263             :     /* collected sample rows */
     264             :     HeapTuple  *rows;           /* array of size targrows */
     265             :     int         targrows;       /* target # of sample rows */
     266             :     int         numrows;        /* # of sample rows collected */
     267             : 
     268             :     /* for random sampling */
     269             :     double      samplerows;     /* # of rows fetched */
     270             :     double      rowstoskip;     /* # of rows to skip before next sample */
     271             :     ReservoirStateData rstate;  /* state for reservoir sampling */
     272             : 
     273             :     /* working memory contexts */
     274             :     MemoryContext anl_cxt;      /* context for per-analyze lifespan data */
     275             :     MemoryContext temp_cxt;     /* context for per-tuple temporary data */
     276             : } PgFdwAnalyzeState;
     277             : 
     278             : /*
     279             :  * This enum describes what's kept in the fdw_private list for a ForeignPath.
     280             :  * We store:
     281             :  *
     282             :  * 1) Boolean flag showing if the remote query has the final sort
     283             :  * 2) Boolean flag showing if the remote query has the LIMIT clause
     284             :  */
     285             : enum FdwPathPrivateIndex
     286             : {
     287             :     /* has-final-sort flag (as a Boolean node) */
     288             :     FdwPathPrivateHasFinalSort,
     289             :     /* has-limit flag (as a Boolean node) */
     290             :     FdwPathPrivateHasLimit,
     291             : };
     292             : 
     293             : /* Struct for extra information passed to estimate_path_cost_size() */
     294             : typedef struct
     295             : {
     296             :     PathTarget *target;
     297             :     bool        has_final_sort;
     298             :     bool        has_limit;
     299             :     double      limit_tuples;
     300             :     int64       count_est;
     301             :     int64       offset_est;
     302             : } PgFdwPathExtraData;
     303             : 
     304             : /*
     305             :  * Identify the attribute where data conversion fails.
     306             :  */
     307             : typedef struct ConversionLocation
     308             : {
     309             :     AttrNumber  cur_attno;      /* attribute number being processed, or 0 */
     310             :     Relation    rel;            /* foreign table being processed, or NULL */
     311             :     ForeignScanState *fsstate;  /* plan node being processed, or NULL */
     312             : } ConversionLocation;
     313             : 
     314             : /* Callback argument for ec_member_matches_foreign */
     315             : typedef struct
     316             : {
     317             :     Expr       *current;        /* current expr, or NULL if not yet found */
     318             :     List       *already_used;   /* expressions already dealt with */
     319             : } ec_member_foreign_arg;
     320             : 
     321             : /*
     322             :  * SQL functions
     323             :  */
     324          22 : PG_FUNCTION_INFO_V1(postgres_fdw_handler);
     325             : 
     326             : /*
     327             :  * FDW callback routines
     328             :  */
     329             : static void postgresGetForeignRelSize(PlannerInfo *root,
     330             :                                       RelOptInfo *baserel,
     331             :                                       Oid foreigntableid);
     332             : static void postgresGetForeignPaths(PlannerInfo *root,
     333             :                                     RelOptInfo *baserel,
     334             :                                     Oid foreigntableid);
     335             : static ForeignScan *postgresGetForeignPlan(PlannerInfo *root,
     336             :                                            RelOptInfo *foreignrel,
     337             :                                            Oid foreigntableid,
     338             :                                            ForeignPath *best_path,
     339             :                                            List *tlist,
     340             :                                            List *scan_clauses,
     341             :                                            Plan *outer_plan);
     342             : static void postgresBeginForeignScan(ForeignScanState *node, int eflags);
     343             : static TupleTableSlot *postgresIterateForeignScan(ForeignScanState *node);
     344             : static void postgresReScanForeignScan(ForeignScanState *node);
     345             : static void postgresEndForeignScan(ForeignScanState *node);
     346             : static void postgresAddForeignUpdateTargets(PlannerInfo *root,
     347             :                                             Index rtindex,
     348             :                                             RangeTblEntry *target_rte,
     349             :                                             Relation target_relation);
     350             : static List *postgresPlanForeignModify(PlannerInfo *root,
     351             :                                        ModifyTable *plan,
     352             :                                        Index resultRelation,
     353             :                                        int subplan_index);
     354             : static void postgresBeginForeignModify(ModifyTableState *mtstate,
     355             :                                        ResultRelInfo *resultRelInfo,
     356             :                                        List *fdw_private,
     357             :                                        int subplan_index,
     358             :                                        int eflags);
     359             : static TupleTableSlot *postgresExecForeignInsert(EState *estate,
     360             :                                                  ResultRelInfo *resultRelInfo,
     361             :                                                  TupleTableSlot *slot,
     362             :                                                  TupleTableSlot *planSlot);
     363             : static TupleTableSlot **postgresExecForeignBatchInsert(EState *estate,
     364             :                                                        ResultRelInfo *resultRelInfo,
     365             :                                                        TupleTableSlot **slots,
     366             :                                                        TupleTableSlot **planSlots,
     367             :                                                        int *numSlots);
     368             : static int  postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo);
     369             : static TupleTableSlot *postgresExecForeignUpdate(EState *estate,
     370             :                                                  ResultRelInfo *resultRelInfo,
     371             :                                                  TupleTableSlot *slot,
     372             :                                                  TupleTableSlot *planSlot);
     373             : static TupleTableSlot *postgresExecForeignDelete(EState *estate,
     374             :                                                  ResultRelInfo *resultRelInfo,
     375             :                                                  TupleTableSlot *slot,
     376             :                                                  TupleTableSlot *planSlot);
     377             : static void postgresEndForeignModify(EState *estate,
     378             :                                      ResultRelInfo *resultRelInfo);
     379             : static void postgresBeginForeignInsert(ModifyTableState *mtstate,
     380             :                                        ResultRelInfo *resultRelInfo);
     381             : static void postgresEndForeignInsert(EState *estate,
     382             :                                      ResultRelInfo *resultRelInfo);
     383             : static int  postgresIsForeignRelUpdatable(Relation rel);
     384             : static bool postgresPlanDirectModify(PlannerInfo *root,
     385             :                                      ModifyTable *plan,
     386             :                                      Index resultRelation,
     387             :                                      int subplan_index);
     388             : static void postgresBeginDirectModify(ForeignScanState *node, int eflags);
     389             : static TupleTableSlot *postgresIterateDirectModify(ForeignScanState *node);
     390             : static void postgresEndDirectModify(ForeignScanState *node);
     391             : static void postgresExplainForeignScan(ForeignScanState *node,
     392             :                                        ExplainState *es);
     393             : static void postgresExplainForeignModify(ModifyTableState *mtstate,
     394             :                                          ResultRelInfo *rinfo,
     395             :                                          List *fdw_private,
     396             :                                          int subplan_index,
     397             :                                          ExplainState *es);
     398             : static void postgresExplainDirectModify(ForeignScanState *node,
     399             :                                         ExplainState *es);
     400             : static void postgresExecForeignTruncate(List *rels,
     401             :                                         DropBehavior behavior,
     402             :                                         bool restart_seqs);
     403             : static bool postgresAnalyzeForeignTable(Relation relation,
     404             :                                         AcquireSampleRowsFunc *func,
     405             :                                         BlockNumber *totalpages);
     406             : static List *postgresImportForeignSchema(ImportForeignSchemaStmt *stmt,
     407             :                                          Oid serverOid);
     408             : static void postgresGetForeignJoinPaths(PlannerInfo *root,
     409             :                                         RelOptInfo *joinrel,
     410             :                                         RelOptInfo *outerrel,
     411             :                                         RelOptInfo *innerrel,
     412             :                                         JoinType jointype,
     413             :                                         JoinPathExtraData *extra);
     414             : static bool postgresRecheckForeignScan(ForeignScanState *node,
     415             :                                        TupleTableSlot *slot);
     416             : static void postgresGetForeignUpperPaths(PlannerInfo *root,
     417             :                                          UpperRelationKind stage,
     418             :                                          RelOptInfo *input_rel,
     419             :                                          RelOptInfo *output_rel,
     420             :                                          void *extra);
     421             : static bool postgresIsForeignPathAsyncCapable(ForeignPath *path);
     422             : static void postgresForeignAsyncRequest(AsyncRequest *areq);
     423             : static void postgresForeignAsyncConfigureWait(AsyncRequest *areq);
     424             : static void postgresForeignAsyncNotify(AsyncRequest *areq);
     425             : 
     426             : /*
     427             :  * Helper functions
     428             :  */
     429             : static void estimate_path_cost_size(PlannerInfo *root,
     430             :                                     RelOptInfo *foreignrel,
     431             :                                     List *param_join_conds,
     432             :                                     List *pathkeys,
     433             :                                     PgFdwPathExtraData *fpextra,
     434             :                                     double *p_rows, int *p_width,
     435             :                                     int *p_disabled_nodes,
     436             :                                     Cost *p_startup_cost, Cost *p_total_cost);
     437             : static void get_remote_estimate(const char *sql,
     438             :                                 PGconn *conn,
     439             :                                 double *rows,
     440             :                                 int *width,
     441             :                                 Cost *startup_cost,
     442             :                                 Cost *total_cost);
     443             : static void adjust_foreign_grouping_path_cost(PlannerInfo *root,
     444             :                                               List *pathkeys,
     445             :                                               double retrieved_rows,
     446             :                                               double width,
     447             :                                               double limit_tuples,
     448             :                                               int *p_disabled_nodes,
     449             :                                               Cost *p_startup_cost,
     450             :                                               Cost *p_run_cost);
     451             : static bool ec_member_matches_foreign(PlannerInfo *root, RelOptInfo *rel,
     452             :                                       EquivalenceClass *ec, EquivalenceMember *em,
     453             :                                       void *arg);
     454             : static void create_cursor(ForeignScanState *node);
     455             : static void fetch_more_data(ForeignScanState *node);
     456             : static void close_cursor(PGconn *conn, unsigned int cursor_number,
     457             :                          PgFdwConnState *conn_state);
     458             : static PgFdwModifyState *create_foreign_modify(EState *estate,
     459             :                                                RangeTblEntry *rte,
     460             :                                                ResultRelInfo *resultRelInfo,
     461             :                                                CmdType operation,
     462             :                                                Plan *subplan,
     463             :                                                char *query,
     464             :                                                List *target_attrs,
     465             :                                                int values_end,
     466             :                                                bool has_returning,
     467             :                                                List *retrieved_attrs);
     468             : static TupleTableSlot **execute_foreign_modify(EState *estate,
     469             :                                                ResultRelInfo *resultRelInfo,
     470             :                                                CmdType operation,
     471             :                                                TupleTableSlot **slots,
     472             :                                                TupleTableSlot **planSlots,
     473             :                                                int *numSlots);
     474             : static void prepare_foreign_modify(PgFdwModifyState *fmstate);
     475             : static const char **convert_prep_stmt_params(PgFdwModifyState *fmstate,
     476             :                                              ItemPointer tupleid,
     477             :                                              TupleTableSlot **slots,
     478             :                                              int numSlots);
     479             : static void store_returning_result(PgFdwModifyState *fmstate,
     480             :                                    TupleTableSlot *slot, PGresult *res);
     481             : static void finish_foreign_modify(PgFdwModifyState *fmstate);
     482             : static void deallocate_query(PgFdwModifyState *fmstate);
     483             : static List *build_remote_returning(Index rtindex, Relation rel,
     484             :                                     List *returningList);
     485             : static void rebuild_fdw_scan_tlist(ForeignScan *fscan, List *tlist);
     486             : static void execute_dml_stmt(ForeignScanState *node);
     487             : static TupleTableSlot *get_returning_data(ForeignScanState *node);
     488             : static void init_returning_filter(PgFdwDirectModifyState *dmstate,
     489             :                                   List *fdw_scan_tlist,
     490             :                                   Index rtindex);
     491             : static TupleTableSlot *apply_returning_filter(PgFdwDirectModifyState *dmstate,
     492             :                                               ResultRelInfo *resultRelInfo,
     493             :                                               TupleTableSlot *slot,
     494             :                                               EState *estate);
     495             : static void prepare_query_params(PlanState *node,
     496             :                                  List *fdw_exprs,
     497             :                                  int numParams,
     498             :                                  FmgrInfo **param_flinfo,
     499             :                                  List **param_exprs,
     500             :                                  const char ***param_values);
     501             : static void process_query_params(ExprContext *econtext,
     502             :                                  FmgrInfo *param_flinfo,
     503             :                                  List *param_exprs,
     504             :                                  const char **param_values);
     505             : static int  postgresAcquireSampleRowsFunc(Relation relation, int elevel,
     506             :                                           HeapTuple *rows, int targrows,
     507             :                                           double *totalrows,
     508             :                                           double *totaldeadrows);
     509             : static void analyze_row_processor(PGresult *res, int row,
     510             :                                   PgFdwAnalyzeState *astate);
     511             : static void produce_tuple_asynchronously(AsyncRequest *areq, bool fetch);
     512             : static void fetch_more_data_begin(AsyncRequest *areq);
     513             : static void complete_pending_request(AsyncRequest *areq);
     514             : static HeapTuple make_tuple_from_result_row(PGresult *res,
     515             :                                             int row,
     516             :                                             Relation rel,
     517             :                                             AttInMetadata *attinmeta,
     518             :                                             List *retrieved_attrs,
     519             :                                             ForeignScanState *fsstate,
     520             :                                             MemoryContext temp_context);
     521             : static void conversion_error_callback(void *arg);
     522             : static bool foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel,
     523             :                             JoinType jointype, RelOptInfo *outerrel, RelOptInfo *innerrel,
     524             :                             JoinPathExtraData *extra);
     525             : static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
     526             :                                 Node *havingQual);
     527             : static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
     528             :                                               RelOptInfo *rel);
     529             : static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
     530             : static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
     531             :                                             Path *epq_path, List *restrictlist);
     532             : static void add_foreign_grouping_paths(PlannerInfo *root,
     533             :                                        RelOptInfo *input_rel,
     534             :                                        RelOptInfo *grouped_rel,
     535             :                                        GroupPathExtraData *extra);
     536             : static void add_foreign_ordered_paths(PlannerInfo *root,
     537             :                                       RelOptInfo *input_rel,
     538             :                                       RelOptInfo *ordered_rel);
     539             : static void add_foreign_final_paths(PlannerInfo *root,
     540             :                                     RelOptInfo *input_rel,
     541             :                                     RelOptInfo *final_rel,
     542             :                                     FinalPathExtraData *extra);
     543             : static void apply_server_options(PgFdwRelationInfo *fpinfo);
     544             : static void apply_table_options(PgFdwRelationInfo *fpinfo);
     545             : static void merge_fdw_options(PgFdwRelationInfo *fpinfo,
     546             :                               const PgFdwRelationInfo *fpinfo_o,
     547             :                               const PgFdwRelationInfo *fpinfo_i);
     548             : static int  get_batch_size_option(Relation rel);
     549             : 
     550             : 
     551             : /*
     552             :  * Foreign-data wrapper handler function: return a struct with pointers
     553             :  * to my callback routines.
     554             :  */
     555             : Datum
     556        1336 : postgres_fdw_handler(PG_FUNCTION_ARGS)
     557             : {
     558        1336 :     FdwRoutine *routine = makeNode(FdwRoutine);
     559             : 
     560             :     /* Functions for scanning foreign tables */
     561        1336 :     routine->GetForeignRelSize = postgresGetForeignRelSize;
     562        1336 :     routine->GetForeignPaths = postgresGetForeignPaths;
     563        1336 :     routine->GetForeignPlan = postgresGetForeignPlan;
     564        1336 :     routine->BeginForeignScan = postgresBeginForeignScan;
     565        1336 :     routine->IterateForeignScan = postgresIterateForeignScan;
     566        1336 :     routine->ReScanForeignScan = postgresReScanForeignScan;
     567        1336 :     routine->EndForeignScan = postgresEndForeignScan;
     568             : 
     569             :     /* Functions for updating foreign tables */
     570        1336 :     routine->AddForeignUpdateTargets = postgresAddForeignUpdateTargets;
     571        1336 :     routine->PlanForeignModify = postgresPlanForeignModify;
     572        1336 :     routine->BeginForeignModify = postgresBeginForeignModify;
     573        1336 :     routine->ExecForeignInsert = postgresExecForeignInsert;
     574        1336 :     routine->ExecForeignBatchInsert = postgresExecForeignBatchInsert;
     575        1336 :     routine->GetForeignModifyBatchSize = postgresGetForeignModifyBatchSize;
     576        1336 :     routine->ExecForeignUpdate = postgresExecForeignUpdate;
     577        1336 :     routine->ExecForeignDelete = postgresExecForeignDelete;
     578        1336 :     routine->EndForeignModify = postgresEndForeignModify;
     579        1336 :     routine->BeginForeignInsert = postgresBeginForeignInsert;
     580        1336 :     routine->EndForeignInsert = postgresEndForeignInsert;
     581        1336 :     routine->IsForeignRelUpdatable = postgresIsForeignRelUpdatable;
     582        1336 :     routine->PlanDirectModify = postgresPlanDirectModify;
     583        1336 :     routine->BeginDirectModify = postgresBeginDirectModify;
     584        1336 :     routine->IterateDirectModify = postgresIterateDirectModify;
     585        1336 :     routine->EndDirectModify = postgresEndDirectModify;
     586             : 
     587             :     /* Function for EvalPlanQual rechecks */
     588        1336 :     routine->RecheckForeignScan = postgresRecheckForeignScan;
     589             :     /* Support functions for EXPLAIN */
     590        1336 :     routine->ExplainForeignScan = postgresExplainForeignScan;
     591        1336 :     routine->ExplainForeignModify = postgresExplainForeignModify;
     592        1336 :     routine->ExplainDirectModify = postgresExplainDirectModify;
     593             : 
     594             :     /* Support function for TRUNCATE */
     595        1336 :     routine->ExecForeignTruncate = postgresExecForeignTruncate;
     596             : 
     597             :     /* Support functions for ANALYZE */
     598        1336 :     routine->AnalyzeForeignTable = postgresAnalyzeForeignTable;
     599             : 
     600             :     /* Support functions for IMPORT FOREIGN SCHEMA */
     601        1336 :     routine->ImportForeignSchema = postgresImportForeignSchema;
     602             : 
     603             :     /* Support functions for join push-down */
     604        1336 :     routine->GetForeignJoinPaths = postgresGetForeignJoinPaths;
     605             : 
     606             :     /* Support functions for upper relation push-down */
     607        1336 :     routine->GetForeignUpperPaths = postgresGetForeignUpperPaths;
     608             : 
     609             :     /* Support functions for asynchronous execution */
     610        1336 :     routine->IsForeignPathAsyncCapable = postgresIsForeignPathAsyncCapable;
     611        1336 :     routine->ForeignAsyncRequest = postgresForeignAsyncRequest;
     612        1336 :     routine->ForeignAsyncConfigureWait = postgresForeignAsyncConfigureWait;
     613        1336 :     routine->ForeignAsyncNotify = postgresForeignAsyncNotify;
     614             : 
     615        1336 :     PG_RETURN_POINTER(routine);
     616             : }
     617             : 
     618             : /*
     619             :  * postgresGetForeignRelSize
     620             :  *      Estimate # of rows and width of the result of the scan
     621             :  *
     622             :  * We should consider the effect of all baserestrictinfo clauses here, but
     623             :  * not any join clauses.
     624             :  */
     625             : static void
     626        2340 : postgresGetForeignRelSize(PlannerInfo *root,
     627             :                           RelOptInfo *baserel,
     628             :                           Oid foreigntableid)
     629             : {
     630             :     PgFdwRelationInfo *fpinfo;
     631             :     ListCell   *lc;
     632             : 
     633             :     /*
     634             :      * We use PgFdwRelationInfo to pass various information to subsequent
     635             :      * functions.
     636             :      */
     637        2340 :     fpinfo = (PgFdwRelationInfo *) palloc0(sizeof(PgFdwRelationInfo));
     638        2340 :     baserel->fdw_private = fpinfo;
     639             : 
     640             :     /* Base foreign tables need to be pushed down always. */
     641        2340 :     fpinfo->pushdown_safe = true;
     642             : 
     643             :     /* Look up foreign-table catalog info. */
     644        2340 :     fpinfo->table = GetForeignTable(foreigntableid);
     645        2340 :     fpinfo->server = GetForeignServer(fpinfo->table->serverid);
     646             : 
     647             :     /*
     648             :      * Extract user-settable option values.  Note that per-table settings of
     649             :      * use_remote_estimate, fetch_size and async_capable override per-server
     650             :      * settings of them, respectively.
     651             :      */
     652        2340 :     fpinfo->use_remote_estimate = false;
     653        2340 :     fpinfo->fdw_startup_cost = DEFAULT_FDW_STARTUP_COST;
     654        2340 :     fpinfo->fdw_tuple_cost = DEFAULT_FDW_TUPLE_COST;
     655        2340 :     fpinfo->shippable_extensions = NIL;
     656        2340 :     fpinfo->fetch_size = 100;
     657        2340 :     fpinfo->async_capable = false;
     658             : 
     659        2340 :     apply_server_options(fpinfo);
     660        2340 :     apply_table_options(fpinfo);
     661             : 
     662             :     /*
     663             :      * If the table or the server is configured to use remote estimates,
     664             :      * identify which user to do remote access as during planning.  This
     665             :      * should match what ExecCheckPermissions() does.  If we fail due to lack
     666             :      * of permissions, the query would have failed at runtime anyway.
     667             :      */
     668        2340 :     if (fpinfo->use_remote_estimate)
     669             :     {
     670             :         Oid         userid;
     671             : 
     672         604 :         userid = OidIsValid(baserel->userid) ? baserel->userid : GetUserId();
     673         604 :         fpinfo->user = GetUserMapping(userid, fpinfo->server->serverid);
     674             :     }
     675             :     else
     676        1736 :         fpinfo->user = NULL;
     677             : 
     678             :     /*
     679             :      * Identify which baserestrictinfo clauses can be sent to the remote
     680             :      * server and which can't.
     681             :      */
     682        2336 :     classifyConditions(root, baserel, baserel->baserestrictinfo,
     683             :                        &fpinfo->remote_conds, &fpinfo->local_conds);
     684             : 
     685             :     /*
     686             :      * Identify which attributes will need to be retrieved from the remote
     687             :      * server.  These include all attrs needed for joins or final output, plus
     688             :      * all attrs used in the local_conds.  (Note: if we end up using a
     689             :      * parameterized scan, it's possible that some of the join clauses will be
     690             :      * sent to the remote and thus we wouldn't really need to retrieve the
     691             :      * columns used in them.  Doesn't seem worth detecting that case though.)
     692             :      */
     693        2336 :     fpinfo->attrs_used = NULL;
     694        2336 :     pull_varattnos((Node *) baserel->reltarget->exprs, baserel->relid,
     695             :                    &fpinfo->attrs_used);
     696        2486 :     foreach(lc, fpinfo->local_conds)
     697             :     {
     698         150 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
     699             : 
     700         150 :         pull_varattnos((Node *) rinfo->clause, baserel->relid,
     701             :                        &fpinfo->attrs_used);
     702             :     }
     703             : 
     704             :     /*
     705             :      * Compute the selectivity and cost of the local_conds, so we don't have
     706             :      * to do it over again for each path.  The best we can do for these
     707             :      * conditions is to estimate selectivity on the basis of local statistics.
     708             :      */
     709        4672 :     fpinfo->local_conds_sel = clauselist_selectivity(root,
     710             :                                                      fpinfo->local_conds,
     711        2336 :                                                      baserel->relid,
     712             :                                                      JOIN_INNER,
     713             :                                                      NULL);
     714             : 
     715        2336 :     cost_qual_eval(&fpinfo->local_conds_cost, fpinfo->local_conds, root);
     716             : 
     717             :     /*
     718             :      * Set # of retrieved rows and cached relation costs to some negative
     719             :      * value, so that we can detect when they are set to some sensible values,
     720             :      * during one (usually the first) of the calls to estimate_path_cost_size.
     721             :      */
     722        2336 :     fpinfo->retrieved_rows = -1;
     723        2336 :     fpinfo->rel_startup_cost = -1;
     724        2336 :     fpinfo->rel_total_cost = -1;
     725             : 
     726             :     /*
     727             :      * If the table or the server is configured to use remote estimates,
     728             :      * connect to the foreign server and execute EXPLAIN to estimate the
     729             :      * number of rows selected by the restriction clauses, as well as the
     730             :      * average row width.  Otherwise, estimate using whatever statistics we
     731             :      * have locally, in a way similar to ordinary tables.
     732             :      */
     733        2336 :     if (fpinfo->use_remote_estimate)
     734             :     {
     735             :         /*
     736             :          * Get cost/size estimates with help of remote server.  Save the
     737             :          * values in fpinfo so we don't need to do it again to generate the
     738             :          * basic foreign path.
     739             :          */
     740         600 :         estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
     741             :                                 &fpinfo->rows, &fpinfo->width,
     742             :                                 &fpinfo->disabled_nodes,
     743             :                                 &fpinfo->startup_cost, &fpinfo->total_cost);
     744             : 
     745             :         /* Report estimated baserel size to planner. */
     746         600 :         baserel->rows = fpinfo->rows;
     747         600 :         baserel->reltarget->width = fpinfo->width;
     748             :     }
     749             :     else
     750             :     {
     751             :         /*
     752             :          * If the foreign table has never been ANALYZEd, it will have
     753             :          * reltuples < 0, meaning "unknown".  We can't do much if we're not
     754             :          * allowed to consult the remote server, but we can use a hack similar
     755             :          * to plancat.c's treatment of empty relations: use a minimum size
     756             :          * estimate of 10 pages, and divide by the column-datatype-based width
     757             :          * estimate to get the corresponding number of tuples.
     758             :          */
     759        1736 :         if (baserel->tuples < 0)
     760             :         {
     761         544 :             baserel->pages = 10;
     762         544 :             baserel->tuples =
     763         544 :                 (10 * BLCKSZ) / (baserel->reltarget->width +
     764             :                                  MAXALIGN(SizeofHeapTupleHeader));
     765             :         }
     766             : 
     767             :         /* Estimate baserel size as best we can with local statistics. */
     768        1736 :         set_baserel_size_estimates(root, baserel);
     769             : 
     770             :         /* Fill in basically-bogus cost estimates for use later. */
     771        1736 :         estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
     772             :                                 &fpinfo->rows, &fpinfo->width,
     773             :                                 &fpinfo->disabled_nodes,
     774             :                                 &fpinfo->startup_cost, &fpinfo->total_cost);
     775             :     }
     776             : 
     777             :     /*
     778             :      * fpinfo->relation_name gets the numeric rangetable index of the foreign
     779             :      * table RTE.  (If this query gets EXPLAIN'd, we'll convert that to a
     780             :      * human-readable string at that time.)
     781             :      */
     782        2336 :     fpinfo->relation_name = psprintf("%u", baserel->relid);
     783             : 
     784             :     /* No outer and inner relations. */
     785        2336 :     fpinfo->make_outerrel_subquery = false;
     786        2336 :     fpinfo->make_innerrel_subquery = false;
     787        2336 :     fpinfo->lower_subquery_rels = NULL;
     788        2336 :     fpinfo->hidden_subquery_rels = NULL;
     789             :     /* Set the relation index. */
     790        2336 :     fpinfo->relation_index = baserel->relid;
     791        2336 : }
     792             : 
     793             : /*
     794             :  * get_useful_ecs_for_relation
     795             :  *      Determine which EquivalenceClasses might be involved in useful
     796             :  *      orderings of this relation.
     797             :  *
     798             :  * This function is in some respects a mirror image of the core function
     799             :  * pathkeys_useful_for_merging: for a regular table, we know what indexes
     800             :  * we have and want to test whether any of them are useful.  For a foreign
     801             :  * table, we don't know what indexes are present on the remote side but
     802             :  * want to speculate about which ones we'd like to use if they existed.
     803             :  *
     804             :  * This function returns a list of potentially-useful equivalence classes,
     805             :  * but it does not guarantee that an EquivalenceMember exists which contains
     806             :  * Vars only from the given relation.  For example, given ft1 JOIN t1 ON
     807             :  * ft1.x + t1.x = 0, this function will say that the equivalence class
     808             :  * containing ft1.x + t1.x is potentially useful.  Supposing ft1 is remote and
     809             :  * t1 is local (or on a different server), it will turn out that no useful
     810             :  * ORDER BY clause can be generated.  It's not our job to figure that out
     811             :  * here; we're only interested in identifying relevant ECs.
     812             :  */
     813             : static List *
     814        1042 : get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel)
     815             : {
     816        1042 :     List       *useful_eclass_list = NIL;
     817             :     ListCell   *lc;
     818             :     Relids      relids;
     819             : 
     820             :     /*
     821             :      * First, consider whether any active EC is potentially useful for a merge
     822             :      * join against this relation.
     823             :      */
     824        1042 :     if (rel->has_eclass_joins)
     825             :     {
     826        1340 :         foreach(lc, root->eq_classes)
     827             :         {
     828         926 :             EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc);
     829             : 
     830         926 :             if (eclass_useful_for_merging(root, cur_ec, rel))
     831         494 :                 useful_eclass_list = lappend(useful_eclass_list, cur_ec);
     832             :         }
     833             :     }
     834             : 
     835             :     /*
     836             :      * Next, consider whether there are any non-EC derivable join clauses that
     837             :      * are merge-joinable.  If the joininfo list is empty, we can exit
     838             :      * quickly.
     839             :      */
     840        1042 :     if (rel->joininfo == NIL)
     841         758 :         return useful_eclass_list;
     842             : 
     843             :     /* If this is a child rel, we must use the topmost parent rel to search. */
     844         284 :     if (IS_OTHER_REL(rel))
     845             :     {
     846             :         Assert(!bms_is_empty(rel->top_parent_relids));
     847          40 :         relids = rel->top_parent_relids;
     848             :     }
     849             :     else
     850         244 :         relids = rel->relids;
     851             : 
     852             :     /* Check each join clause in turn. */
     853         690 :     foreach(lc, rel->joininfo)
     854             :     {
     855         406 :         RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(lc);
     856             : 
     857             :         /* Consider only mergejoinable clauses */
     858         406 :         if (restrictinfo->mergeopfamilies == NIL)
     859          28 :             continue;
     860             : 
     861             :         /* Make sure we've got canonical ECs. */
     862         378 :         update_mergeclause_eclasses(root, restrictinfo);
     863             : 
     864             :         /*
     865             :          * restrictinfo->mergeopfamilies != NIL is sufficient to guarantee
     866             :          * that left_ec and right_ec will be initialized, per comments in
     867             :          * distribute_qual_to_rels.
     868             :          *
     869             :          * We want to identify which side of this merge-joinable clause
     870             :          * contains columns from the relation produced by this RelOptInfo. We
     871             :          * test for overlap, not containment, because there could be extra
     872             :          * relations on either side.  For example, suppose we've got something
     873             :          * like ((A JOIN B ON A.x = B.x) JOIN C ON A.y = C.y) LEFT JOIN D ON
     874             :          * A.y = D.y.  The input rel might be the joinrel between A and B, and
     875             :          * we'll consider the join clause A.y = D.y. relids contains a
     876             :          * relation not involved in the join class (B) and the equivalence
     877             :          * class for the left-hand side of the clause contains a relation not
     878             :          * involved in the input rel (C).  Despite the fact that we have only
     879             :          * overlap and not containment in either direction, A.y is potentially
     880             :          * useful as a sort column.
     881             :          *
     882             :          * Note that it's even possible that relids overlaps neither side of
     883             :          * the join clause.  For example, consider A LEFT JOIN B ON A.x = B.x
     884             :          * AND A.x = 1.  The clause A.x = 1 will appear in B's joininfo list,
     885             :          * but overlaps neither side of B.  In that case, we just skip this
     886             :          * join clause, since it doesn't suggest a useful sort order for this
     887             :          * relation.
     888             :          */
     889         378 :         if (bms_overlap(relids, restrictinfo->right_ec->ec_relids))
     890         172 :             useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
     891         172 :                                                         restrictinfo->right_ec);
     892         206 :         else if (bms_overlap(relids, restrictinfo->left_ec->ec_relids))
     893         188 :             useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
     894         188 :                                                         restrictinfo->left_ec);
     895             :     }
     896             : 
     897         284 :     return useful_eclass_list;
     898             : }
     899             : 
     900             : /*
     901             :  * get_useful_pathkeys_for_relation
     902             :  *      Determine which orderings of a relation might be useful.
     903             :  *
     904             :  * Getting data in sorted order can be useful either because the requested
     905             :  * order matches the final output ordering for the overall query we're
     906             :  * planning, or because it enables an efficient merge join.  Here, we try
     907             :  * to figure out which pathkeys to consider.
     908             :  */
     909             : static List *
     910        3002 : get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
     911             : {
     912        3002 :     List       *useful_pathkeys_list = NIL;
     913             :     List       *useful_eclass_list;
     914        3002 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
     915        3002 :     EquivalenceClass *query_ec = NULL;
     916             :     ListCell   *lc;
     917             : 
     918             :     /*
     919             :      * Pushing the query_pathkeys to the remote server is always worth
     920             :      * considering, because it might let us avoid a local sort.
     921             :      */
     922        3002 :     fpinfo->qp_is_pushdown_safe = false;
     923        3002 :     if (root->query_pathkeys)
     924             :     {
     925        1212 :         bool        query_pathkeys_ok = true;
     926             : 
     927        2288 :         foreach(lc, root->query_pathkeys)
     928             :         {
     929        1550 :             PathKey    *pathkey = (PathKey *) lfirst(lc);
     930             : 
     931             :             /*
     932             :              * The planner and executor don't have any clever strategy for
     933             :              * taking data sorted by a prefix of the query's pathkeys and
     934             :              * getting it to be sorted by all of those pathkeys. We'll just
     935             :              * end up resorting the entire data set.  So, unless we can push
     936             :              * down all of the query pathkeys, forget it.
     937             :              */
     938        1550 :             if (!is_foreign_pathkey(root, rel, pathkey))
     939             :             {
     940         474 :                 query_pathkeys_ok = false;
     941         474 :                 break;
     942             :             }
     943             :         }
     944             : 
     945        1212 :         if (query_pathkeys_ok)
     946             :         {
     947         738 :             useful_pathkeys_list = list_make1(list_copy(root->query_pathkeys));
     948         738 :             fpinfo->qp_is_pushdown_safe = true;
     949             :         }
     950             :     }
     951             : 
     952             :     /*
     953             :      * Even if we're not using remote estimates, having the remote side do the
     954             :      * sort generally won't be any worse than doing it locally, and it might
     955             :      * be much better if the remote side can generate data in the right order
     956             :      * without needing a sort at all.  However, what we're going to do next is
     957             :      * try to generate pathkeys that seem promising for possible merge joins,
     958             :      * and that's more speculative.  A wrong choice might hurt quite a bit, so
     959             :      * bail out if we can't use remote estimates.
     960             :      */
     961        3002 :     if (!fpinfo->use_remote_estimate)
     962        1960 :         return useful_pathkeys_list;
     963             : 
     964             :     /* Get the list of interesting EquivalenceClasses. */
     965        1042 :     useful_eclass_list = get_useful_ecs_for_relation(root, rel);
     966             : 
     967             :     /* Extract unique EC for query, if any, so we don't consider it again. */
     968        1042 :     if (list_length(root->query_pathkeys) == 1)
     969             :     {
     970         354 :         PathKey    *query_pathkey = linitial(root->query_pathkeys);
     971             : 
     972         354 :         query_ec = query_pathkey->pk_eclass;
     973             :     }
     974             : 
     975             :     /*
     976             :      * As a heuristic, the only pathkeys we consider here are those of length
     977             :      * one.  It's surely possible to consider more, but since each one we
     978             :      * choose to consider will generate a round-trip to the remote side, we
     979             :      * need to be a bit cautious here.  It would sure be nice to have a local
     980             :      * cache of information about remote index definitions...
     981             :      */
     982        1842 :     foreach(lc, useful_eclass_list)
     983             :     {
     984         800 :         EquivalenceClass *cur_ec = lfirst(lc);
     985             :         PathKey    *pathkey;
     986             : 
     987             :         /* If redundant with what we did above, skip it. */
     988         800 :         if (cur_ec == query_ec)
     989         162 :             continue;
     990             : 
     991             :         /* Can't push down the sort if the EC's opfamily is not shippable. */
     992         738 :         if (!is_shippable(linitial_oid(cur_ec->ec_opfamilies),
     993             :                           OperatorFamilyRelationId, fpinfo))
     994           0 :             continue;
     995             : 
     996             :         /* If no pushable expression for this rel, skip it. */
     997         738 :         if (find_em_for_rel(root, cur_ec, rel) == NULL)
     998         100 :             continue;
     999             : 
    1000             :         /* Looks like we can generate a pathkey, so let's do it. */
    1001         638 :         pathkey = make_canonical_pathkey(root, cur_ec,
    1002         638 :                                          linitial_oid(cur_ec->ec_opfamilies),
    1003             :                                          COMPARE_LT,
    1004             :                                          false);
    1005         638 :         useful_pathkeys_list = lappend(useful_pathkeys_list,
    1006         638 :                                        list_make1(pathkey));
    1007             :     }
    1008             : 
    1009        1042 :     return useful_pathkeys_list;
    1010             : }
    1011             : 
    1012             : /*
    1013             :  * postgresGetForeignPaths
    1014             :  *      Create possible scan paths for a scan on the foreign table
    1015             :  */
    1016             : static void
    1017        2336 : postgresGetForeignPaths(PlannerInfo *root,
    1018             :                         RelOptInfo *baserel,
    1019             :                         Oid foreigntableid)
    1020             : {
    1021        2336 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) baserel->fdw_private;
    1022             :     ForeignPath *path;
    1023             :     List       *ppi_list;
    1024             :     ListCell   *lc;
    1025             : 
    1026             :     /*
    1027             :      * Create simplest ForeignScan path node and add it to baserel.  This path
    1028             :      * corresponds to SeqScan path of regular tables (though depending on what
    1029             :      * baserestrict conditions we were able to send to remote, there might
    1030             :      * actually be an indexscan happening there).  We already did all the work
    1031             :      * to estimate cost and size of this path.
    1032             :      *
    1033             :      * Although this path uses no join clauses, it could still have required
    1034             :      * parameterization due to LATERAL refs in its tlist.
    1035             :      */
    1036        2336 :     path = create_foreignscan_path(root, baserel,
    1037             :                                    NULL,    /* default pathtarget */
    1038             :                                    fpinfo->rows,
    1039             :                                    fpinfo->disabled_nodes,
    1040             :                                    fpinfo->startup_cost,
    1041             :                                    fpinfo->total_cost,
    1042             :                                    NIL, /* no pathkeys */
    1043             :                                    baserel->lateral_relids,
    1044             :                                    NULL,    /* no extra plan */
    1045             :                                    NIL, /* no fdw_restrictinfo list */
    1046             :                                    NIL);    /* no fdw_private list */
    1047        2336 :     add_path(baserel, (Path *) path);
    1048             : 
    1049             :     /* Add paths with pathkeys */
    1050        2336 :     add_paths_with_pathkeys_for_rel(root, baserel, NULL, NIL);
    1051             : 
    1052             :     /*
    1053             :      * If we're not using remote estimates, stop here.  We have no way to
    1054             :      * estimate whether any join clauses would be worth sending across, so
    1055             :      * don't bother building parameterized paths.
    1056             :      */
    1057        2336 :     if (!fpinfo->use_remote_estimate)
    1058        1736 :         return;
    1059             : 
    1060             :     /*
    1061             :      * Thumb through all join clauses for the rel to identify which outer
    1062             :      * relations could supply one or more safe-to-send-to-remote join clauses.
    1063             :      * We'll build a parameterized path for each such outer relation.
    1064             :      *
    1065             :      * It's convenient to manage this by representing each candidate outer
    1066             :      * relation by the ParamPathInfo node for it.  We can then use the
    1067             :      * ppi_clauses list in the ParamPathInfo node directly as a list of the
    1068             :      * interesting join clauses for that rel.  This takes care of the
    1069             :      * possibility that there are multiple safe join clauses for such a rel,
    1070             :      * and also ensures that we account for unsafe join clauses that we'll
    1071             :      * still have to enforce locally (since the parameterized-path machinery
    1072             :      * insists that we handle all movable clauses).
    1073             :      */
    1074         600 :     ppi_list = NIL;
    1075         882 :     foreach(lc, baserel->joininfo)
    1076             :     {
    1077         282 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1078             :         Relids      required_outer;
    1079             :         ParamPathInfo *param_info;
    1080             : 
    1081             :         /* Check if clause can be moved to this rel */
    1082         282 :         if (!join_clause_is_movable_to(rinfo, baserel))
    1083         192 :             continue;
    1084             : 
    1085             :         /* See if it is safe to send to remote */
    1086          90 :         if (!is_foreign_expr(root, baserel, rinfo->clause))
    1087          14 :             continue;
    1088             : 
    1089             :         /* Calculate required outer rels for the resulting path */
    1090          76 :         required_outer = bms_union(rinfo->clause_relids,
    1091          76 :                                    baserel->lateral_relids);
    1092             :         /* We do not want the foreign rel itself listed in required_outer */
    1093          76 :         required_outer = bms_del_member(required_outer, baserel->relid);
    1094             : 
    1095             :         /*
    1096             :          * required_outer probably can't be empty here, but if it were, we
    1097             :          * couldn't make a parameterized path.
    1098             :          */
    1099          76 :         if (bms_is_empty(required_outer))
    1100           0 :             continue;
    1101             : 
    1102             :         /* Get the ParamPathInfo */
    1103          76 :         param_info = get_baserel_parampathinfo(root, baserel,
    1104             :                                                required_outer);
    1105             :         Assert(param_info != NULL);
    1106             : 
    1107             :         /*
    1108             :          * Add it to list unless we already have it.  Testing pointer equality
    1109             :          * is OK since get_baserel_parampathinfo won't make duplicates.
    1110             :          */
    1111          76 :         ppi_list = list_append_unique_ptr(ppi_list, param_info);
    1112             :     }
    1113             : 
    1114             :     /*
    1115             :      * The above scan examined only "generic" join clauses, not those that
    1116             :      * were absorbed into EquivalenceClauses.  See if we can make anything out
    1117             :      * of EquivalenceClauses.
    1118             :      */
    1119         600 :     if (baserel->has_eclass_joins)
    1120             :     {
    1121             :         /*
    1122             :          * We repeatedly scan the eclass list looking for column references
    1123             :          * (or expressions) belonging to the foreign rel.  Each time we find
    1124             :          * one, we generate a list of equivalence joinclauses for it, and then
    1125             :          * see if any are safe to send to the remote.  Repeat till there are
    1126             :          * no more candidate EC members.
    1127             :          */
    1128             :         ec_member_foreign_arg arg;
    1129             : 
    1130         266 :         arg.already_used = NIL;
    1131             :         for (;;)
    1132         282 :         {
    1133             :             List       *clauses;
    1134             : 
    1135             :             /* Make clauses, skipping any that join to lateral_referencers */
    1136         548 :             arg.current = NULL;
    1137         548 :             clauses = generate_implied_equalities_for_column(root,
    1138             :                                                              baserel,
    1139             :                                                              ec_member_matches_foreign,
    1140             :                                                              &arg,
    1141             :                                                              baserel->lateral_referencers);
    1142             : 
    1143             :             /* Done if there are no more expressions in the foreign rel */
    1144         548 :             if (arg.current == NULL)
    1145             :             {
    1146             :                 Assert(clauses == NIL);
    1147         266 :                 break;
    1148             :             }
    1149             : 
    1150             :             /* Scan the extracted join clauses */
    1151         628 :             foreach(lc, clauses)
    1152             :             {
    1153         346 :                 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1154             :                 Relids      required_outer;
    1155             :                 ParamPathInfo *param_info;
    1156             : 
    1157             :                 /* Check if clause can be moved to this rel */
    1158         346 :                 if (!join_clause_is_movable_to(rinfo, baserel))
    1159           0 :                     continue;
    1160             : 
    1161             :                 /* See if it is safe to send to remote */
    1162         346 :                 if (!is_foreign_expr(root, baserel, rinfo->clause))
    1163          14 :                     continue;
    1164             : 
    1165             :                 /* Calculate required outer rels for the resulting path */
    1166         332 :                 required_outer = bms_union(rinfo->clause_relids,
    1167         332 :                                            baserel->lateral_relids);
    1168         332 :                 required_outer = bms_del_member(required_outer, baserel->relid);
    1169         332 :                 if (bms_is_empty(required_outer))
    1170           0 :                     continue;
    1171             : 
    1172             :                 /* Get the ParamPathInfo */
    1173         332 :                 param_info = get_baserel_parampathinfo(root, baserel,
    1174             :                                                        required_outer);
    1175             :                 Assert(param_info != NULL);
    1176             : 
    1177             :                 /* Add it to list unless we already have it */
    1178         332 :                 ppi_list = list_append_unique_ptr(ppi_list, param_info);
    1179             :             }
    1180             : 
    1181             :             /* Try again, now ignoring the expression we found this time */
    1182         282 :             arg.already_used = lappend(arg.already_used, arg.current);
    1183             :         }
    1184             :     }
    1185             : 
    1186             :     /*
    1187             :      * Now build a path for each useful outer relation.
    1188             :      */
    1189         988 :     foreach(lc, ppi_list)
    1190             :     {
    1191         388 :         ParamPathInfo *param_info = (ParamPathInfo *) lfirst(lc);
    1192             :         double      rows;
    1193             :         int         width;
    1194             :         int         disabled_nodes;
    1195             :         Cost        startup_cost;
    1196             :         Cost        total_cost;
    1197             : 
    1198             :         /* Get a cost estimate from the remote */
    1199         388 :         estimate_path_cost_size(root, baserel,
    1200             :                                 param_info->ppi_clauses, NIL, NULL,
    1201             :                                 &rows, &width, &disabled_nodes,
    1202             :                                 &startup_cost, &total_cost);
    1203             : 
    1204             :         /*
    1205             :          * ppi_rows currently won't get looked at by anything, but still we
    1206             :          * may as well ensure that it matches our idea of the rowcount.
    1207             :          */
    1208         388 :         param_info->ppi_rows = rows;
    1209             : 
    1210             :         /* Make the path */
    1211         388 :         path = create_foreignscan_path(root, baserel,
    1212             :                                        NULL,    /* default pathtarget */
    1213             :                                        rows,
    1214             :                                        disabled_nodes,
    1215             :                                        startup_cost,
    1216             :                                        total_cost,
    1217             :                                        NIL, /* no pathkeys */
    1218             :                                        param_info->ppi_req_outer,
    1219             :                                        NULL,
    1220             :                                        NIL, /* no fdw_restrictinfo list */
    1221             :                                        NIL);    /* no fdw_private list */
    1222         388 :         add_path(baserel, (Path *) path);
    1223             :     }
    1224             : }
    1225             : 
    1226             : /*
    1227             :  * postgresGetForeignPlan
    1228             :  *      Create ForeignScan plan node which implements selected best path
    1229             :  */
    1230             : static ForeignScan *
    1231        1964 : postgresGetForeignPlan(PlannerInfo *root,
    1232             :                        RelOptInfo *foreignrel,
    1233             :                        Oid foreigntableid,
    1234             :                        ForeignPath *best_path,
    1235             :                        List *tlist,
    1236             :                        List *scan_clauses,
    1237             :                        Plan *outer_plan)
    1238             : {
    1239        1964 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    1240             :     Index       scan_relid;
    1241             :     List       *fdw_private;
    1242        1964 :     List       *remote_exprs = NIL;
    1243        1964 :     List       *local_exprs = NIL;
    1244        1964 :     List       *params_list = NIL;
    1245        1964 :     List       *fdw_scan_tlist = NIL;
    1246        1964 :     List       *fdw_recheck_quals = NIL;
    1247             :     List       *retrieved_attrs;
    1248             :     StringInfoData sql;
    1249        1964 :     bool        has_final_sort = false;
    1250        1964 :     bool        has_limit = false;
    1251             :     ListCell   *lc;
    1252             : 
    1253             :     /*
    1254             :      * Get FDW private data created by postgresGetForeignUpperPaths(), if any.
    1255             :      */
    1256        1964 :     if (best_path->fdw_private)
    1257             :     {
    1258         302 :         has_final_sort = boolVal(list_nth(best_path->fdw_private,
    1259             :                                           FdwPathPrivateHasFinalSort));
    1260         302 :         has_limit = boolVal(list_nth(best_path->fdw_private,
    1261             :                                      FdwPathPrivateHasLimit));
    1262             :     }
    1263             : 
    1264        1964 :     if (IS_SIMPLE_REL(foreignrel))
    1265             :     {
    1266             :         /*
    1267             :          * For base relations, set scan_relid as the relid of the relation.
    1268             :          */
    1269        1404 :         scan_relid = foreignrel->relid;
    1270             : 
    1271             :         /*
    1272             :          * In a base-relation scan, we must apply the given scan_clauses.
    1273             :          *
    1274             :          * Separate the scan_clauses into those that can be executed remotely
    1275             :          * and those that can't.  baserestrictinfo clauses that were
    1276             :          * previously determined to be safe or unsafe by classifyConditions
    1277             :          * are found in fpinfo->remote_conds and fpinfo->local_conds. Anything
    1278             :          * else in the scan_clauses list will be a join clause, which we have
    1279             :          * to check for remote-safety.
    1280             :          *
    1281             :          * Note: the join clauses we see here should be the exact same ones
    1282             :          * previously examined by postgresGetForeignPaths.  Possibly it'd be
    1283             :          * worth passing forward the classification work done then, rather
    1284             :          * than repeating it here.
    1285             :          *
    1286             :          * This code must match "extract_actual_clauses(scan_clauses, false)"
    1287             :          * except for the additional decision about remote versus local
    1288             :          * execution.
    1289             :          */
    1290        2118 :         foreach(lc, scan_clauses)
    1291             :         {
    1292         714 :             RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    1293             : 
    1294             :             /* Ignore any pseudoconstants, they're dealt with elsewhere */
    1295         714 :             if (rinfo->pseudoconstant)
    1296           8 :                 continue;
    1297             : 
    1298         706 :             if (list_member_ptr(fpinfo->remote_conds, rinfo))
    1299         538 :                 remote_exprs = lappend(remote_exprs, rinfo->clause);
    1300         168 :             else if (list_member_ptr(fpinfo->local_conds, rinfo))
    1301         142 :                 local_exprs = lappend(local_exprs, rinfo->clause);
    1302          26 :             else if (is_foreign_expr(root, foreignrel, rinfo->clause))
    1303          22 :                 remote_exprs = lappend(remote_exprs, rinfo->clause);
    1304             :             else
    1305           4 :                 local_exprs = lappend(local_exprs, rinfo->clause);
    1306             :         }
    1307             : 
    1308             :         /*
    1309             :          * For a base-relation scan, we have to support EPQ recheck, which
    1310             :          * should recheck all the remote quals.
    1311             :          */
    1312        1404 :         fdw_recheck_quals = remote_exprs;
    1313             :     }
    1314             :     else
    1315             :     {
    1316             :         /*
    1317             :          * Join relation or upper relation - set scan_relid to 0.
    1318             :          */
    1319         560 :         scan_relid = 0;
    1320             : 
    1321             :         /*
    1322             :          * For a join rel, baserestrictinfo is NIL and we are not considering
    1323             :          * parameterization right now, so there should be no scan_clauses for
    1324             :          * a joinrel or an upper rel either.
    1325             :          */
    1326             :         Assert(!scan_clauses);
    1327             : 
    1328             :         /*
    1329             :          * Instead we get the conditions to apply from the fdw_private
    1330             :          * structure.
    1331             :          */
    1332         560 :         remote_exprs = extract_actual_clauses(fpinfo->remote_conds, false);
    1333         560 :         local_exprs = extract_actual_clauses(fpinfo->local_conds, false);
    1334             : 
    1335             :         /*
    1336             :          * We leave fdw_recheck_quals empty in this case, since we never need
    1337             :          * to apply EPQ recheck clauses.  In the case of a joinrel, EPQ
    1338             :          * recheck is handled elsewhere --- see postgresGetForeignJoinPaths().
    1339             :          * If we're planning an upperrel (ie, remote grouping or aggregation)
    1340             :          * then there's no EPQ to do because SELECT FOR UPDATE wouldn't be
    1341             :          * allowed, and indeed we *can't* put the remote clauses into
    1342             :          * fdw_recheck_quals because the unaggregated Vars won't be available
    1343             :          * locally.
    1344             :          */
    1345             : 
    1346             :         /* Build the list of columns to be fetched from the foreign server. */
    1347         560 :         fdw_scan_tlist = build_tlist_to_deparse(foreignrel);
    1348             : 
    1349             :         /*
    1350             :          * Ensure that the outer plan produces a tuple whose descriptor
    1351             :          * matches our scan tuple slot.  Also, remove the local conditions
    1352             :          * from outer plan's quals, lest they be evaluated twice, once by the
    1353             :          * local plan and once by the scan.
    1354             :          */
    1355         560 :         if (outer_plan)
    1356             :         {
    1357             :             /*
    1358             :              * Right now, we only consider grouping and aggregation beyond
    1359             :              * joins. Queries involving aggregates or grouping do not require
    1360             :              * EPQ mechanism, hence should not have an outer plan here.
    1361             :              */
    1362             :             Assert(!IS_UPPER_REL(foreignrel));
    1363             : 
    1364             :             /*
    1365             :              * First, update the plan's qual list if possible.  In some cases
    1366             :              * the quals might be enforced below the topmost plan level, in
    1367             :              * which case we'll fail to remove them; it's not worth working
    1368             :              * harder than this.
    1369             :              */
    1370          54 :             foreach(lc, local_exprs)
    1371             :             {
    1372           6 :                 Node       *qual = lfirst(lc);
    1373             : 
    1374           6 :                 outer_plan->qual = list_delete(outer_plan->qual, qual);
    1375             : 
    1376             :                 /*
    1377             :                  * For an inner join the local conditions of foreign scan plan
    1378             :                  * can be part of the joinquals as well.  (They might also be
    1379             :                  * in the mergequals or hashquals, but we can't touch those
    1380             :                  * without breaking the plan.)
    1381             :                  */
    1382           6 :                 if (IsA(outer_plan, NestLoop) ||
    1383           2 :                     IsA(outer_plan, MergeJoin) ||
    1384           2 :                     IsA(outer_plan, HashJoin))
    1385             :                 {
    1386           4 :                     Join       *join_plan = (Join *) outer_plan;
    1387             : 
    1388           4 :                     if (join_plan->jointype == JOIN_INNER)
    1389           4 :                         join_plan->joinqual = list_delete(join_plan->joinqual,
    1390             :                                                           qual);
    1391             :                 }
    1392             :             }
    1393             : 
    1394             :             /*
    1395             :              * Now fix the subplan's tlist --- this might result in inserting
    1396             :              * a Result node atop the plan tree.
    1397             :              */
    1398          48 :             outer_plan = change_plan_targetlist(outer_plan, fdw_scan_tlist,
    1399          48 :                                                 best_path->path.parallel_safe);
    1400             :         }
    1401             :     }
    1402             : 
    1403             :     /*
    1404             :      * Build the query string to be sent for execution, and identify
    1405             :      * expressions to be sent as parameters.
    1406             :      */
    1407        1964 :     initStringInfo(&sql);
    1408        1964 :     deparseSelectStmtForRel(&sql, root, foreignrel, fdw_scan_tlist,
    1409             :                             remote_exprs, best_path->path.pathkeys,
    1410             :                             has_final_sort, has_limit, false,
    1411             :                             &retrieved_attrs, &params_list);
    1412             : 
    1413             :     /* Remember remote_exprs for possible use by postgresPlanDirectModify */
    1414        1964 :     fpinfo->final_remote_exprs = remote_exprs;
    1415             : 
    1416             :     /*
    1417             :      * Build the fdw_private list that will be available to the executor.
    1418             :      * Items in the list must match order in enum FdwScanPrivateIndex.
    1419             :      */
    1420        1964 :     fdw_private = list_make3(makeString(sql.data),
    1421             :                              retrieved_attrs,
    1422             :                              makeInteger(fpinfo->fetch_size));
    1423        1964 :     if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
    1424         560 :         fdw_private = lappend(fdw_private,
    1425         560 :                               makeString(fpinfo->relation_name));
    1426             : 
    1427             :     /*
    1428             :      * Create the ForeignScan node for the given relation.
    1429             :      *
    1430             :      * Note that the remote parameter expressions are stored in the fdw_exprs
    1431             :      * field of the finished plan node; we can't keep them in private state
    1432             :      * because then they wouldn't be subject to later planner processing.
    1433             :      */
    1434        1964 :     return make_foreignscan(tlist,
    1435             :                             local_exprs,
    1436             :                             scan_relid,
    1437             :                             params_list,
    1438             :                             fdw_private,
    1439             :                             fdw_scan_tlist,
    1440             :                             fdw_recheck_quals,
    1441             :                             outer_plan);
    1442             : }
    1443             : 
    1444             : /*
    1445             :  * Construct a tuple descriptor for the scan tuples handled by a foreign join.
    1446             :  */
    1447             : static TupleDesc
    1448         318 : get_tupdesc_for_join_scan_tuples(ForeignScanState *node)
    1449             : {
    1450         318 :     ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
    1451         318 :     EState     *estate = node->ss.ps.state;
    1452             :     TupleDesc   tupdesc;
    1453             : 
    1454             :     /*
    1455             :      * The core code has already set up a scan tuple slot based on
    1456             :      * fsplan->fdw_scan_tlist, and this slot's tupdesc is mostly good enough,
    1457             :      * but there's one case where it isn't.  If we have any whole-row row
    1458             :      * identifier Vars, they may have vartype RECORD, and we need to replace
    1459             :      * that with the associated table's actual composite type.  This ensures
    1460             :      * that when we read those ROW() expression values from the remote server,
    1461             :      * we can convert them to a composite type the local server knows.
    1462             :      */
    1463         318 :     tupdesc = CreateTupleDescCopy(node->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
    1464        1342 :     for (int i = 0; i < tupdesc->natts; i++)
    1465             :     {
    1466        1024 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    1467             :         Var        *var;
    1468             :         RangeTblEntry *rte;
    1469             :         Oid         reltype;
    1470             : 
    1471             :         /* Nothing to do if it's not a generic RECORD attribute */
    1472        1024 :         if (att->atttypid != RECORDOID || att->atttypmod >= 0)
    1473        1018 :             continue;
    1474             : 
    1475             :         /*
    1476             :          * If we can't identify the referenced table, do nothing.  This'll
    1477             :          * likely lead to failure later, but perhaps we can muddle through.
    1478             :          */
    1479           6 :         var = (Var *) list_nth_node(TargetEntry, fsplan->fdw_scan_tlist,
    1480             :                                     i)->expr;
    1481           6 :         if (!IsA(var, Var) || var->varattno != 0)
    1482           0 :             continue;
    1483           6 :         rte = list_nth(estate->es_range_table, var->varno - 1);
    1484           6 :         if (rte->rtekind != RTE_RELATION)
    1485           0 :             continue;
    1486           6 :         reltype = get_rel_type_id(rte->relid);
    1487           6 :         if (!OidIsValid(reltype))
    1488           0 :             continue;
    1489           6 :         att->atttypid = reltype;
    1490             :         /* shouldn't need to change anything else */
    1491             :     }
    1492         318 :     return tupdesc;
    1493             : }
    1494             : 
    1495             : /*
    1496             :  * postgresBeginForeignScan
    1497             :  *      Initiate an executor scan of a foreign PostgreSQL table.
    1498             :  */
    1499             : static void
    1500        1738 : postgresBeginForeignScan(ForeignScanState *node, int eflags)
    1501             : {
    1502        1738 :     ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
    1503        1738 :     EState     *estate = node->ss.ps.state;
    1504             :     PgFdwScanState *fsstate;
    1505             :     RangeTblEntry *rte;
    1506             :     Oid         userid;
    1507             :     ForeignTable *table;
    1508             :     UserMapping *user;
    1509             :     int         rtindex;
    1510             :     int         numParams;
    1511             : 
    1512             :     /*
    1513             :      * Do nothing in EXPLAIN (no ANALYZE) case.  node->fdw_state stays NULL.
    1514             :      */
    1515        1738 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
    1516         750 :         return;
    1517             : 
    1518             :     /*
    1519             :      * We'll save private state in node->fdw_state.
    1520             :      */
    1521         988 :     fsstate = (PgFdwScanState *) palloc0(sizeof(PgFdwScanState));
    1522         988 :     node->fdw_state = fsstate;
    1523             : 
    1524             :     /*
    1525             :      * Identify which user to do the remote access as.  This should match what
    1526             :      * ExecCheckPermissions() does.
    1527             :      */
    1528         988 :     userid = OidIsValid(fsplan->checkAsUser) ? fsplan->checkAsUser : GetUserId();
    1529         988 :     if (fsplan->scan.scanrelid > 0)
    1530         672 :         rtindex = fsplan->scan.scanrelid;
    1531             :     else
    1532         316 :         rtindex = bms_next_member(fsplan->fs_base_relids, -1);
    1533         988 :     rte = exec_rt_fetch(rtindex, estate);
    1534             : 
    1535             :     /* Get info about foreign table. */
    1536         988 :     table = GetForeignTable(rte->relid);
    1537         988 :     user = GetUserMapping(userid, table->serverid);
    1538             : 
    1539             :     /*
    1540             :      * Get connection to the foreign server.  Connection manager will
    1541             :      * establish new connection if necessary.
    1542             :      */
    1543         988 :     fsstate->conn = GetConnection(user, false, &fsstate->conn_state);
    1544             : 
    1545             :     /* Assign a unique ID for my cursor */
    1546         974 :     fsstate->cursor_number = GetCursorNumber(fsstate->conn);
    1547         974 :     fsstate->cursor_exists = false;
    1548             : 
    1549             :     /* Get private info created by planner functions. */
    1550         974 :     fsstate->query = strVal(list_nth(fsplan->fdw_private,
    1551             :                                      FdwScanPrivateSelectSql));
    1552         974 :     fsstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
    1553             :                                                  FdwScanPrivateRetrievedAttrs);
    1554         974 :     fsstate->fetch_size = intVal(list_nth(fsplan->fdw_private,
    1555             :                                           FdwScanPrivateFetchSize));
    1556             : 
    1557             :     /* Create contexts for batches of tuples and per-tuple temp workspace. */
    1558         974 :     fsstate->batch_cxt = AllocSetContextCreate(estate->es_query_cxt,
    1559             :                                                "postgres_fdw tuple data",
    1560             :                                                ALLOCSET_DEFAULT_SIZES);
    1561         974 :     fsstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
    1562             :                                               "postgres_fdw temporary data",
    1563             :                                               ALLOCSET_SMALL_SIZES);
    1564             : 
    1565             :     /*
    1566             :      * Get info we'll need for converting data fetched from the foreign server
    1567             :      * into local representation and error reporting during that process.
    1568             :      */
    1569         974 :     if (fsplan->scan.scanrelid > 0)
    1570             :     {
    1571         658 :         fsstate->rel = node->ss.ss_currentRelation;
    1572         658 :         fsstate->tupdesc = RelationGetDescr(fsstate->rel);
    1573             :     }
    1574             :     else
    1575             :     {
    1576         316 :         fsstate->rel = NULL;
    1577         316 :         fsstate->tupdesc = get_tupdesc_for_join_scan_tuples(node);
    1578             :     }
    1579             : 
    1580         974 :     fsstate->attinmeta = TupleDescGetAttInMetadata(fsstate->tupdesc);
    1581             : 
    1582             :     /*
    1583             :      * Prepare for processing of parameters used in remote query, if any.
    1584             :      */
    1585         974 :     numParams = list_length(fsplan->fdw_exprs);
    1586         974 :     fsstate->numParams = numParams;
    1587         974 :     if (numParams > 0)
    1588          36 :         prepare_query_params((PlanState *) node,
    1589             :                              fsplan->fdw_exprs,
    1590             :                              numParams,
    1591             :                              &fsstate->param_flinfo,
    1592             :                              &fsstate->param_exprs,
    1593             :                              &fsstate->param_values);
    1594             : 
    1595             :     /* Set the async-capable flag */
    1596         974 :     fsstate->async_capable = node->ss.ps.async_capable;
    1597             : }
    1598             : 
    1599             : /*
    1600             :  * postgresIterateForeignScan
    1601             :  *      Retrieve next row from the result set, or clear tuple slot to indicate
    1602             :  *      EOF.
    1603             :  */
    1604             : static TupleTableSlot *
    1605      141752 : postgresIterateForeignScan(ForeignScanState *node)
    1606             : {
    1607      141752 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    1608      141752 :     TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
    1609             : 
    1610             :     /*
    1611             :      * In sync mode, if this is the first call after Begin or ReScan, we need
    1612             :      * to create the cursor on the remote side.  In async mode, we would have
    1613             :      * already created the cursor before we get here, even if this is the
    1614             :      * first call after Begin or ReScan.
    1615             :      */
    1616      141752 :     if (!fsstate->cursor_exists)
    1617        1508 :         create_cursor(node);
    1618             : 
    1619             :     /*
    1620             :      * Get some more tuples, if we've run out.
    1621             :      */
    1622      141746 :     if (fsstate->next_tuple >= fsstate->num_tuples)
    1623             :     {
    1624             :         /* In async mode, just clear tuple slot. */
    1625        4062 :         if (fsstate->async_capable)
    1626          64 :             return ExecClearTuple(slot);
    1627             :         /* No point in another fetch if we already detected EOF, though. */
    1628        3998 :         if (!fsstate->eof_reached)
    1629        2662 :             fetch_more_data(node);
    1630             :         /* If we didn't get any tuples, must be end of data. */
    1631        3988 :         if (fsstate->next_tuple >= fsstate->num_tuples)
    1632        1476 :             return ExecClearTuple(slot);
    1633             :     }
    1634             : 
    1635             :     /*
    1636             :      * Return the next tuple.
    1637             :      */
    1638      140196 :     ExecStoreHeapTuple(fsstate->tuples[fsstate->next_tuple++],
    1639             :                        slot,
    1640             :                        false);
    1641             : 
    1642      140196 :     return slot;
    1643             : }
    1644             : 
    1645             : /*
    1646             :  * postgresReScanForeignScan
    1647             :  *      Restart the scan.
    1648             :  */
    1649             : static void
    1650         802 : postgresReScanForeignScan(ForeignScanState *node)
    1651             : {
    1652         802 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    1653             :     char        sql[64];
    1654             :     PGresult   *res;
    1655             : 
    1656             :     /* If we haven't created the cursor yet, nothing to do. */
    1657         802 :     if (!fsstate->cursor_exists)
    1658          88 :         return;
    1659             : 
    1660             :     /*
    1661             :      * If the node is async-capable, and an asynchronous fetch for it has
    1662             :      * begun, the asynchronous fetch might not have yet completed.  Check if
    1663             :      * the node is async-capable, and an asynchronous fetch for it is still in
    1664             :      * progress; if so, complete the asynchronous fetch before restarting the
    1665             :      * scan.
    1666             :      */
    1667         738 :     if (fsstate->async_capable &&
    1668          42 :         fsstate->conn_state->pendingAreq &&
    1669           4 :         fsstate->conn_state->pendingAreq->requestee == (PlanState *) node)
    1670           2 :         fetch_more_data(node);
    1671             : 
    1672             :     /*
    1673             :      * If any internal parameters affecting this node have changed, we'd
    1674             :      * better destroy and recreate the cursor.  Otherwise, if the remote
    1675             :      * server is v14 or older, rewinding it should be good enough; if not,
    1676             :      * rewind is only allowed for scrollable cursors, but we don't have a way
    1677             :      * to check the scrollability of it, so destroy and recreate it in any
    1678             :      * case.  If we've only fetched zero or one batch, we needn't even rewind
    1679             :      * the cursor, just rescan what we have.
    1680             :      */
    1681         738 :     if (node->ss.ps.chgParam != NULL)
    1682             :     {
    1683         676 :         fsstate->cursor_exists = false;
    1684         676 :         snprintf(sql, sizeof(sql), "CLOSE c%u",
    1685             :                  fsstate->cursor_number);
    1686             :     }
    1687          62 :     else if (fsstate->fetch_ct_2 > 1)
    1688             :     {
    1689          38 :         if (PQserverVersion(fsstate->conn) < 150000)
    1690           0 :             snprintf(sql, sizeof(sql), "MOVE BACKWARD ALL IN c%u",
    1691             :                      fsstate->cursor_number);
    1692             :         else
    1693             :         {
    1694          38 :             fsstate->cursor_exists = false;
    1695          38 :             snprintf(sql, sizeof(sql), "CLOSE c%u",
    1696             :                      fsstate->cursor_number);
    1697             :         }
    1698             :     }
    1699             :     else
    1700             :     {
    1701             :         /* Easy: just rescan what we already have in memory, if anything */
    1702          24 :         fsstate->next_tuple = 0;
    1703          24 :         return;
    1704             :     }
    1705             : 
    1706             :     /*
    1707             :      * We don't use a PG_TRY block here, so be careful not to throw error
    1708             :      * without releasing the PGresult.
    1709             :      */
    1710         714 :     res = pgfdw_exec_query(fsstate->conn, sql, fsstate->conn_state);
    1711         714 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    1712           0 :         pgfdw_report_error(ERROR, res, fsstate->conn, true, sql);
    1713         714 :     PQclear(res);
    1714             : 
    1715             :     /* Now force a fresh FETCH. */
    1716         714 :     fsstate->tuples = NULL;
    1717         714 :     fsstate->num_tuples = 0;
    1718         714 :     fsstate->next_tuple = 0;
    1719         714 :     fsstate->fetch_ct_2 = 0;
    1720         714 :     fsstate->eof_reached = false;
    1721             : }
    1722             : 
    1723             : /*
    1724             :  * postgresEndForeignScan
    1725             :  *      Finish scanning foreign table and dispose objects used for this scan
    1726             :  */
    1727             : static void
    1728        1690 : postgresEndForeignScan(ForeignScanState *node)
    1729             : {
    1730        1690 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    1731             : 
    1732             :     /* if fsstate is NULL, we are in EXPLAIN; nothing to do */
    1733        1690 :     if (fsstate == NULL)
    1734         750 :         return;
    1735             : 
    1736             :     /* Close the cursor if open, to prevent accumulation of cursors */
    1737         940 :     if (fsstate->cursor_exists)
    1738         898 :         close_cursor(fsstate->conn, fsstate->cursor_number,
    1739             :                      fsstate->conn_state);
    1740             : 
    1741             :     /* Release remote connection */
    1742         940 :     ReleaseConnection(fsstate->conn);
    1743         940 :     fsstate->conn = NULL;
    1744             : 
    1745             :     /* MemoryContexts will be deleted automatically. */
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * postgresAddForeignUpdateTargets
    1750             :  *      Add resjunk column(s) needed for update/delete on a foreign table
    1751             :  */
    1752             : static void
    1753         362 : postgresAddForeignUpdateTargets(PlannerInfo *root,
    1754             :                                 Index rtindex,
    1755             :                                 RangeTblEntry *target_rte,
    1756             :                                 Relation target_relation)
    1757             : {
    1758             :     Var        *var;
    1759             : 
    1760             :     /*
    1761             :      * In postgres_fdw, what we need is the ctid, same as for a regular table.
    1762             :      */
    1763             : 
    1764             :     /* Make a Var representing the desired value */
    1765         362 :     var = makeVar(rtindex,
    1766             :                   SelfItemPointerAttributeNumber,
    1767             :                   TIDOID,
    1768             :                   -1,
    1769             :                   InvalidOid,
    1770             :                   0);
    1771             : 
    1772             :     /* Register it as a row-identity column needed by this target rel */
    1773         362 :     add_row_identity_var(root, var, rtindex, "ctid");
    1774         362 : }
    1775             : 
    1776             : /*
    1777             :  * postgresPlanForeignModify
    1778             :  *      Plan an insert/update/delete operation on a foreign table
    1779             :  */
    1780             : static List *
    1781         322 : postgresPlanForeignModify(PlannerInfo *root,
    1782             :                           ModifyTable *plan,
    1783             :                           Index resultRelation,
    1784             :                           int subplan_index)
    1785             : {
    1786         322 :     CmdType     operation = plan->operation;
    1787         322 :     RangeTblEntry *rte = planner_rt_fetch(resultRelation, root);
    1788             :     Relation    rel;
    1789             :     StringInfoData sql;
    1790         322 :     List       *targetAttrs = NIL;
    1791         322 :     List       *withCheckOptionList = NIL;
    1792         322 :     List       *returningList = NIL;
    1793         322 :     List       *retrieved_attrs = NIL;
    1794         322 :     bool        doNothing = false;
    1795         322 :     int         values_end_len = -1;
    1796             : 
    1797         322 :     initStringInfo(&sql);
    1798             : 
    1799             :     /*
    1800             :      * Core code already has some lock on each rel being planned, so we can
    1801             :      * use NoLock here.
    1802             :      */
    1803         322 :     rel = table_open(rte->relid, NoLock);
    1804             : 
    1805             :     /*
    1806             :      * In an INSERT, we transmit all columns that are defined in the foreign
    1807             :      * table.  In an UPDATE, if there are BEFORE ROW UPDATE triggers on the
    1808             :      * foreign table, we transmit all columns like INSERT; else we transmit
    1809             :      * only columns that were explicitly targets of the UPDATE, so as to avoid
    1810             :      * unnecessary data transmission.  (We can't do that for INSERT since we
    1811             :      * would miss sending default values for columns not listed in the source
    1812             :      * statement, and for UPDATE if there are BEFORE ROW UPDATE triggers since
    1813             :      * those triggers might change values for non-target columns, in which
    1814             :      * case we would miss sending changed values for those columns.)
    1815             :      */
    1816         322 :     if (operation == CMD_INSERT ||
    1817         112 :         (operation == CMD_UPDATE &&
    1818         112 :          rel->trigdesc &&
    1819          36 :          rel->trigdesc->trig_update_before_row))
    1820         204 :     {
    1821         204 :         TupleDesc   tupdesc = RelationGetDescr(rel);
    1822             :         int         attnum;
    1823             : 
    1824         862 :         for (attnum = 1; attnum <= tupdesc->natts; attnum++)
    1825             :         {
    1826         658 :             CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    1827             : 
    1828         658 :             if (!attr->attisdropped)
    1829         624 :                 targetAttrs = lappend_int(targetAttrs, attnum);
    1830             :         }
    1831             :     }
    1832         118 :     else if (operation == CMD_UPDATE)
    1833             :     {
    1834             :         int         col;
    1835          82 :         RelOptInfo *rel = find_base_rel(root, resultRelation);
    1836          82 :         Bitmapset  *allUpdatedCols = get_rel_all_updated_cols(root, rel);
    1837             : 
    1838          82 :         col = -1;
    1839         184 :         while ((col = bms_next_member(allUpdatedCols, col)) >= 0)
    1840             :         {
    1841             :             /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
    1842         102 :             AttrNumber  attno = col + FirstLowInvalidHeapAttributeNumber;
    1843             : 
    1844         102 :             if (attno <= InvalidAttrNumber) /* shouldn't happen */
    1845           0 :                 elog(ERROR, "system-column update is not supported");
    1846         102 :             targetAttrs = lappend_int(targetAttrs, attno);
    1847             :         }
    1848             :     }
    1849             : 
    1850             :     /*
    1851             :      * Extract the relevant WITH CHECK OPTION list if any.
    1852             :      */
    1853         322 :     if (plan->withCheckOptionLists)
    1854          32 :         withCheckOptionList = (List *) list_nth(plan->withCheckOptionLists,
    1855             :                                                 subplan_index);
    1856             : 
    1857             :     /*
    1858             :      * Extract the relevant RETURNING list if any.
    1859             :      */
    1860         322 :     if (plan->returningLists)
    1861          64 :         returningList = (List *) list_nth(plan->returningLists, subplan_index);
    1862             : 
    1863             :     /*
    1864             :      * ON CONFLICT DO UPDATE and DO NOTHING case with inference specification
    1865             :      * should have already been rejected in the optimizer, as presently there
    1866             :      * is no way to recognize an arbiter index on a foreign table.  Only DO
    1867             :      * NOTHING is supported without an inference specification.
    1868             :      */
    1869         322 :     if (plan->onConflictAction == ONCONFLICT_NOTHING)
    1870           2 :         doNothing = true;
    1871         320 :     else if (plan->onConflictAction != ONCONFLICT_NONE)
    1872           0 :         elog(ERROR, "unexpected ON CONFLICT specification: %d",
    1873             :              (int) plan->onConflictAction);
    1874             : 
    1875             :     /*
    1876             :      * Construct the SQL command string.
    1877             :      */
    1878         322 :     switch (operation)
    1879             :     {
    1880         174 :         case CMD_INSERT:
    1881         174 :             deparseInsertSql(&sql, rte, resultRelation, rel,
    1882             :                              targetAttrs, doNothing,
    1883             :                              withCheckOptionList, returningList,
    1884             :                              &retrieved_attrs, &values_end_len);
    1885         174 :             break;
    1886         112 :         case CMD_UPDATE:
    1887         112 :             deparseUpdateSql(&sql, rte, resultRelation, rel,
    1888             :                              targetAttrs,
    1889             :                              withCheckOptionList, returningList,
    1890             :                              &retrieved_attrs);
    1891         112 :             break;
    1892          36 :         case CMD_DELETE:
    1893          36 :             deparseDeleteSql(&sql, rte, resultRelation, rel,
    1894             :                              returningList,
    1895             :                              &retrieved_attrs);
    1896          36 :             break;
    1897           0 :         default:
    1898           0 :             elog(ERROR, "unexpected operation: %d", (int) operation);
    1899             :             break;
    1900             :     }
    1901             : 
    1902         322 :     table_close(rel, NoLock);
    1903             : 
    1904             :     /*
    1905             :      * Build the fdw_private list that will be available to the executor.
    1906             :      * Items in the list must match enum FdwModifyPrivateIndex, above.
    1907             :      */
    1908         322 :     return list_make5(makeString(sql.data),
    1909             :                       targetAttrs,
    1910             :                       makeInteger(values_end_len),
    1911             :                       makeBoolean((retrieved_attrs != NIL)),
    1912             :                       retrieved_attrs);
    1913             : }
    1914             : 
    1915             : /*
    1916             :  * postgresBeginForeignModify
    1917             :  *      Begin an insert/update/delete operation on a foreign table
    1918             :  */
    1919             : static void
    1920         322 : postgresBeginForeignModify(ModifyTableState *mtstate,
    1921             :                            ResultRelInfo *resultRelInfo,
    1922             :                            List *fdw_private,
    1923             :                            int subplan_index,
    1924             :                            int eflags)
    1925             : {
    1926             :     PgFdwModifyState *fmstate;
    1927             :     char       *query;
    1928             :     List       *target_attrs;
    1929             :     bool        has_returning;
    1930             :     int         values_end_len;
    1931             :     List       *retrieved_attrs;
    1932             :     RangeTblEntry *rte;
    1933             : 
    1934             :     /*
    1935             :      * Do nothing in EXPLAIN (no ANALYZE) case.  resultRelInfo->ri_FdwState
    1936             :      * stays NULL.
    1937             :      */
    1938         322 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
    1939          84 :         return;
    1940             : 
    1941             :     /* Deconstruct fdw_private data. */
    1942         238 :     query = strVal(list_nth(fdw_private,
    1943             :                             FdwModifyPrivateUpdateSql));
    1944         238 :     target_attrs = (List *) list_nth(fdw_private,
    1945             :                                      FdwModifyPrivateTargetAttnums);
    1946         238 :     values_end_len = intVal(list_nth(fdw_private,
    1947             :                                      FdwModifyPrivateLen));
    1948         238 :     has_returning = boolVal(list_nth(fdw_private,
    1949             :                                      FdwModifyPrivateHasReturning));
    1950         238 :     retrieved_attrs = (List *) list_nth(fdw_private,
    1951             :                                         FdwModifyPrivateRetrievedAttrs);
    1952             : 
    1953             :     /* Find RTE. */
    1954         238 :     rte = exec_rt_fetch(resultRelInfo->ri_RangeTableIndex,
    1955             :                         mtstate->ps.state);
    1956             : 
    1957             :     /* Construct an execution state. */
    1958         238 :     fmstate = create_foreign_modify(mtstate->ps.state,
    1959             :                                     rte,
    1960             :                                     resultRelInfo,
    1961             :                                     mtstate->operation,
    1962         238 :                                     outerPlanState(mtstate)->plan,
    1963             :                                     query,
    1964             :                                     target_attrs,
    1965             :                                     values_end_len,
    1966             :                                     has_returning,
    1967             :                                     retrieved_attrs);
    1968             : 
    1969         238 :     resultRelInfo->ri_FdwState = fmstate;
    1970             : }
    1971             : 
    1972             : /*
    1973             :  * postgresExecForeignInsert
    1974             :  *      Insert one row into a foreign table
    1975             :  */
    1976             : static TupleTableSlot *
    1977        1776 : postgresExecForeignInsert(EState *estate,
    1978             :                           ResultRelInfo *resultRelInfo,
    1979             :                           TupleTableSlot *slot,
    1980             :                           TupleTableSlot *planSlot)
    1981             : {
    1982        1776 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    1983             :     TupleTableSlot **rslot;
    1984        1776 :     int         numSlots = 1;
    1985             : 
    1986             :     /*
    1987             :      * If the fmstate has aux_fmstate set, use the aux_fmstate (see
    1988             :      * postgresBeginForeignInsert())
    1989             :      */
    1990        1776 :     if (fmstate->aux_fmstate)
    1991           0 :         resultRelInfo->ri_FdwState = fmstate->aux_fmstate;
    1992        1776 :     rslot = execute_foreign_modify(estate, resultRelInfo, CMD_INSERT,
    1993             :                                    &slot, &planSlot, &numSlots);
    1994             :     /* Revert that change */
    1995        1768 :     if (fmstate->aux_fmstate)
    1996           0 :         resultRelInfo->ri_FdwState = fmstate;
    1997             : 
    1998        1768 :     return rslot ? *rslot : NULL;
    1999             : }
    2000             : 
    2001             : /*
    2002             :  * postgresExecForeignBatchInsert
    2003             :  *      Insert multiple rows into a foreign table
    2004             :  */
    2005             : static TupleTableSlot **
    2006          82 : postgresExecForeignBatchInsert(EState *estate,
    2007             :                                ResultRelInfo *resultRelInfo,
    2008             :                                TupleTableSlot **slots,
    2009             :                                TupleTableSlot **planSlots,
    2010             :                                int *numSlots)
    2011             : {
    2012          82 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    2013             :     TupleTableSlot **rslot;
    2014             : 
    2015             :     /*
    2016             :      * If the fmstate has aux_fmstate set, use the aux_fmstate (see
    2017             :      * postgresBeginForeignInsert())
    2018             :      */
    2019          82 :     if (fmstate->aux_fmstate)
    2020           0 :         resultRelInfo->ri_FdwState = fmstate->aux_fmstate;
    2021          82 :     rslot = execute_foreign_modify(estate, resultRelInfo, CMD_INSERT,
    2022             :                                    slots, planSlots, numSlots);
    2023             :     /* Revert that change */
    2024          80 :     if (fmstate->aux_fmstate)
    2025           0 :         resultRelInfo->ri_FdwState = fmstate;
    2026             : 
    2027          80 :     return rslot;
    2028             : }
    2029             : 
    2030             : /*
    2031             :  * postgresGetForeignModifyBatchSize
    2032             :  *      Determine the maximum number of tuples that can be inserted in bulk
    2033             :  *
    2034             :  * Returns the batch size specified for server or table. When batching is not
    2035             :  * allowed (e.g. for tables with BEFORE/AFTER ROW triggers or with RETURNING
    2036             :  * clause), returns 1.
    2037             :  */
    2038             : static int
    2039         282 : postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
    2040             : {
    2041             :     int         batch_size;
    2042         282 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    2043             : 
    2044             :     /* should be called only once */
    2045             :     Assert(resultRelInfo->ri_BatchSize == 0);
    2046             : 
    2047             :     /*
    2048             :      * Should never get called when the insert is being performed on a table
    2049             :      * that is also among the target relations of an UPDATE operation, because
    2050             :      * postgresBeginForeignInsert() currently rejects such insert attempts.
    2051             :      */
    2052             :     Assert(fmstate == NULL || fmstate->aux_fmstate == NULL);
    2053             : 
    2054             :     /*
    2055             :      * In EXPLAIN without ANALYZE, ri_FdwState is NULL, so we have to lookup
    2056             :      * the option directly in server/table options. Otherwise just use the
    2057             :      * value we determined earlier.
    2058             :      */
    2059         282 :     if (fmstate)
    2060         256 :         batch_size = fmstate->batch_size;
    2061             :     else
    2062          26 :         batch_size = get_batch_size_option(resultRelInfo->ri_RelationDesc);
    2063             : 
    2064             :     /*
    2065             :      * Disable batching when we have to use RETURNING, there are any
    2066             :      * BEFORE/AFTER ROW INSERT triggers on the foreign table, or there are any
    2067             :      * WITH CHECK OPTION constraints from parent views.
    2068             :      *
    2069             :      * When there are any BEFORE ROW INSERT triggers on the table, we can't
    2070             :      * support it, because such triggers might query the table we're inserting
    2071             :      * into and act differently if the tuples that have already been processed
    2072             :      * and prepared for insertion are not there.
    2073             :      */
    2074         282 :     if (resultRelInfo->ri_projectReturning != NULL ||
    2075         240 :         resultRelInfo->ri_WithCheckOptions != NIL ||
    2076         222 :         (resultRelInfo->ri_TrigDesc &&
    2077          28 :          (resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
    2078           2 :           resultRelInfo->ri_TrigDesc->trig_insert_after_row)))
    2079          88 :         return 1;
    2080             : 
    2081             :     /*
    2082             :      * If the foreign table has no columns, disable batching as the INSERT
    2083             :      * syntax doesn't allow batching multiple empty rows into a zero-column
    2084             :      * table in a single statement.  This is needed for COPY FROM, in which
    2085             :      * case fmstate must be non-NULL.
    2086             :      */
    2087         194 :     if (fmstate && list_length(fmstate->target_attrs) == 0)
    2088           2 :         return 1;
    2089             : 
    2090             :     /*
    2091             :      * Otherwise use the batch size specified for server/table. The number of
    2092             :      * parameters in a batch is limited to 65535 (uint16), so make sure we
    2093             :      * don't exceed this limit by using the maximum batch_size possible.
    2094             :      */
    2095         192 :     if (fmstate && fmstate->p_nums > 0)
    2096         176 :         batch_size = Min(batch_size, PQ_QUERY_PARAM_MAX_LIMIT / fmstate->p_nums);
    2097             : 
    2098         192 :     return batch_size;
    2099             : }
    2100             : 
    2101             : /*
    2102             :  * postgresExecForeignUpdate
    2103             :  *      Update one row in a foreign table
    2104             :  */
    2105             : static TupleTableSlot *
    2106         186 : postgresExecForeignUpdate(EState *estate,
    2107             :                           ResultRelInfo *resultRelInfo,
    2108             :                           TupleTableSlot *slot,
    2109             :                           TupleTableSlot *planSlot)
    2110             : {
    2111             :     TupleTableSlot **rslot;
    2112         186 :     int         numSlots = 1;
    2113             : 
    2114         186 :     rslot = execute_foreign_modify(estate, resultRelInfo, CMD_UPDATE,
    2115             :                                    &slot, &planSlot, &numSlots);
    2116             : 
    2117         186 :     return rslot ? rslot[0] : NULL;
    2118             : }
    2119             : 
    2120             : /*
    2121             :  * postgresExecForeignDelete
    2122             :  *      Delete one row from a foreign table
    2123             :  */
    2124             : static TupleTableSlot *
    2125          42 : postgresExecForeignDelete(EState *estate,
    2126             :                           ResultRelInfo *resultRelInfo,
    2127             :                           TupleTableSlot *slot,
    2128             :                           TupleTableSlot *planSlot)
    2129             : {
    2130             :     TupleTableSlot **rslot;
    2131          42 :     int         numSlots = 1;
    2132             : 
    2133          42 :     rslot = execute_foreign_modify(estate, resultRelInfo, CMD_DELETE,
    2134             :                                    &slot, &planSlot, &numSlots);
    2135             : 
    2136          42 :     return rslot ? rslot[0] : NULL;
    2137             : }
    2138             : 
    2139             : /*
    2140             :  * postgresEndForeignModify
    2141             :  *      Finish an insert/update/delete operation on a foreign table
    2142             :  */
    2143             : static void
    2144         302 : postgresEndForeignModify(EState *estate,
    2145             :                          ResultRelInfo *resultRelInfo)
    2146             : {
    2147         302 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    2148             : 
    2149             :     /* If fmstate is NULL, we are in EXPLAIN; nothing to do */
    2150         302 :     if (fmstate == NULL)
    2151          84 :         return;
    2152             : 
    2153             :     /* Destroy the execution state */
    2154         218 :     finish_foreign_modify(fmstate);
    2155             : }
    2156             : 
    2157             : /*
    2158             :  * postgresBeginForeignInsert
    2159             :  *      Begin an insert operation on a foreign table
    2160             :  */
    2161             : static void
    2162         120 : postgresBeginForeignInsert(ModifyTableState *mtstate,
    2163             :                            ResultRelInfo *resultRelInfo)
    2164             : {
    2165             :     PgFdwModifyState *fmstate;
    2166         120 :     ModifyTable *plan = castNode(ModifyTable, mtstate->ps.plan);
    2167         120 :     EState     *estate = mtstate->ps.state;
    2168             :     Index       resultRelation;
    2169         120 :     Relation    rel = resultRelInfo->ri_RelationDesc;
    2170             :     RangeTblEntry *rte;
    2171         120 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    2172             :     int         attnum;
    2173             :     int         values_end_len;
    2174             :     StringInfoData sql;
    2175         120 :     List       *targetAttrs = NIL;
    2176         120 :     List       *retrieved_attrs = NIL;
    2177         120 :     bool        doNothing = false;
    2178             : 
    2179             :     /*
    2180             :      * If the foreign table we are about to insert routed rows into is also an
    2181             :      * UPDATE subplan result rel that will be updated later, proceeding with
    2182             :      * the INSERT will result in the later UPDATE incorrectly modifying those
    2183             :      * routed rows, so prevent the INSERT --- it would be nice if we could
    2184             :      * handle this case; but for now, throw an error for safety.
    2185             :      */
    2186         120 :     if (plan && plan->operation == CMD_UPDATE &&
    2187          18 :         (resultRelInfo->ri_usesFdwDirectModify ||
    2188          10 :          resultRelInfo->ri_FdwState))
    2189          12 :         ereport(ERROR,
    2190             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2191             :                  errmsg("cannot route tuples into foreign table to be updated \"%s\"",
    2192             :                         RelationGetRelationName(rel))));
    2193             : 
    2194         108 :     initStringInfo(&sql);
    2195             : 
    2196             :     /* We transmit all columns that are defined in the foreign table. */
    2197         322 :     for (attnum = 1; attnum <= tupdesc->natts; attnum++)
    2198             :     {
    2199         214 :         CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    2200             : 
    2201         214 :         if (!attr->attisdropped)
    2202         210 :             targetAttrs = lappend_int(targetAttrs, attnum);
    2203             :     }
    2204             : 
    2205             :     /* Check if we add the ON CONFLICT clause to the remote query. */
    2206         108 :     if (plan)
    2207             :     {
    2208          64 :         OnConflictAction onConflictAction = plan->onConflictAction;
    2209             : 
    2210             :         /* We only support DO NOTHING without an inference specification. */
    2211          64 :         if (onConflictAction == ONCONFLICT_NOTHING)
    2212           4 :             doNothing = true;
    2213          60 :         else if (onConflictAction != ONCONFLICT_NONE)
    2214           0 :             elog(ERROR, "unexpected ON CONFLICT specification: %d",
    2215             :                  (int) onConflictAction);
    2216             :     }
    2217             : 
    2218             :     /*
    2219             :      * If the foreign table is a partition that doesn't have a corresponding
    2220             :      * RTE entry, we need to create a new RTE describing the foreign table for
    2221             :      * use by deparseInsertSql and create_foreign_modify() below, after first
    2222             :      * copying the parent's RTE and modifying some fields to describe the
    2223             :      * foreign partition to work on. However, if this is invoked by UPDATE,
    2224             :      * the existing RTE may already correspond to this partition if it is one
    2225             :      * of the UPDATE subplan target rels; in that case, we can just use the
    2226             :      * existing RTE as-is.
    2227             :      */
    2228         108 :     if (resultRelInfo->ri_RangeTableIndex == 0)
    2229             :     {
    2230          72 :         ResultRelInfo *rootResultRelInfo = resultRelInfo->ri_RootResultRelInfo;
    2231             : 
    2232          72 :         rte = exec_rt_fetch(rootResultRelInfo->ri_RangeTableIndex, estate);
    2233          72 :         rte = copyObject(rte);
    2234          72 :         rte->relid = RelationGetRelid(rel);
    2235          72 :         rte->relkind = RELKIND_FOREIGN_TABLE;
    2236             : 
    2237             :         /*
    2238             :          * For UPDATE, we must use the RT index of the first subplan target
    2239             :          * rel's RTE, because the core code would have built expressions for
    2240             :          * the partition, such as RETURNING, using that RT index as varno of
    2241             :          * Vars contained in those expressions.
    2242             :          */
    2243          72 :         if (plan && plan->operation == CMD_UPDATE &&
    2244           6 :             rootResultRelInfo->ri_RangeTableIndex == plan->rootRelation)
    2245           6 :             resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
    2246             :         else
    2247          66 :             resultRelation = rootResultRelInfo->ri_RangeTableIndex;
    2248             :     }
    2249             :     else
    2250             :     {
    2251          36 :         resultRelation = resultRelInfo->ri_RangeTableIndex;
    2252          36 :         rte = exec_rt_fetch(resultRelation, estate);
    2253             :     }
    2254             : 
    2255             :     /* Construct the SQL command string. */
    2256         108 :     deparseInsertSql(&sql, rte, resultRelation, rel, targetAttrs, doNothing,
    2257             :                      resultRelInfo->ri_WithCheckOptions,
    2258             :                      resultRelInfo->ri_returningList,
    2259             :                      &retrieved_attrs, &values_end_len);
    2260             : 
    2261             :     /* Construct an execution state. */
    2262         108 :     fmstate = create_foreign_modify(mtstate->ps.state,
    2263             :                                     rte,
    2264             :                                     resultRelInfo,
    2265             :                                     CMD_INSERT,
    2266             :                                     NULL,
    2267             :                                     sql.data,
    2268             :                                     targetAttrs,
    2269             :                                     values_end_len,
    2270             :                                     retrieved_attrs != NIL,
    2271             :                                     retrieved_attrs);
    2272             : 
    2273             :     /*
    2274             :      * If the given resultRelInfo already has PgFdwModifyState set, it means
    2275             :      * the foreign table is an UPDATE subplan result rel; in which case, store
    2276             :      * the resulting state into the aux_fmstate of the PgFdwModifyState.
    2277             :      */
    2278         108 :     if (resultRelInfo->ri_FdwState)
    2279             :     {
    2280             :         Assert(plan && plan->operation == CMD_UPDATE);
    2281             :         Assert(resultRelInfo->ri_usesFdwDirectModify == false);
    2282           0 :         ((PgFdwModifyState *) resultRelInfo->ri_FdwState)->aux_fmstate = fmstate;
    2283             :     }
    2284             :     else
    2285         108 :         resultRelInfo->ri_FdwState = fmstate;
    2286         108 : }
    2287             : 
    2288             : /*
    2289             :  * postgresEndForeignInsert
    2290             :  *      Finish an insert operation on a foreign table
    2291             :  */
    2292             : static void
    2293         100 : postgresEndForeignInsert(EState *estate,
    2294             :                          ResultRelInfo *resultRelInfo)
    2295             : {
    2296         100 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    2297             : 
    2298             :     Assert(fmstate != NULL);
    2299             : 
    2300             :     /*
    2301             :      * If the fmstate has aux_fmstate set, get the aux_fmstate (see
    2302             :      * postgresBeginForeignInsert())
    2303             :      */
    2304         100 :     if (fmstate->aux_fmstate)
    2305           0 :         fmstate = fmstate->aux_fmstate;
    2306             : 
    2307             :     /* Destroy the execution state */
    2308         100 :     finish_foreign_modify(fmstate);
    2309         100 : }
    2310             : 
    2311             : /*
    2312             :  * postgresIsForeignRelUpdatable
    2313             :  *      Determine whether a foreign table supports INSERT, UPDATE and/or
    2314             :  *      DELETE.
    2315             :  */
    2316             : static int
    2317         650 : postgresIsForeignRelUpdatable(Relation rel)
    2318             : {
    2319             :     bool        updatable;
    2320             :     ForeignTable *table;
    2321             :     ForeignServer *server;
    2322             :     ListCell   *lc;
    2323             : 
    2324             :     /*
    2325             :      * By default, all postgres_fdw foreign tables are assumed updatable. This
    2326             :      * can be overridden by a per-server setting, which in turn can be
    2327             :      * overridden by a per-table setting.
    2328             :      */
    2329         650 :     updatable = true;
    2330             : 
    2331         650 :     table = GetForeignTable(RelationGetRelid(rel));
    2332         650 :     server = GetForeignServer(table->serverid);
    2333             : 
    2334        2914 :     foreach(lc, server->options)
    2335             :     {
    2336        2264 :         DefElem    *def = (DefElem *) lfirst(lc);
    2337             : 
    2338        2264 :         if (strcmp(def->defname, "updatable") == 0)
    2339           0 :             updatable = defGetBoolean(def);
    2340             :     }
    2341        1576 :     foreach(lc, table->options)
    2342             :     {
    2343         926 :         DefElem    *def = (DefElem *) lfirst(lc);
    2344             : 
    2345         926 :         if (strcmp(def->defname, "updatable") == 0)
    2346           0 :             updatable = defGetBoolean(def);
    2347             :     }
    2348             : 
    2349             :     /*
    2350             :      * Currently "updatable" means support for INSERT, UPDATE and DELETE.
    2351             :      */
    2352             :     return updatable ?
    2353         650 :         (1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE) : 0;
    2354             : }
    2355             : 
    2356             : /*
    2357             :  * postgresRecheckForeignScan
    2358             :  *      Execute a local join execution plan for a foreign join
    2359             :  */
    2360             : static bool
    2361           0 : postgresRecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot)
    2362             : {
    2363           0 :     Index       scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
    2364           0 :     PlanState  *outerPlan = outerPlanState(node);
    2365             :     TupleTableSlot *result;
    2366             : 
    2367             :     /* For base foreign relations, it suffices to set fdw_recheck_quals */
    2368           0 :     if (scanrelid > 0)
    2369           0 :         return true;
    2370             : 
    2371             :     Assert(outerPlan != NULL);
    2372             : 
    2373             :     /* Execute a local join execution plan */
    2374           0 :     result = ExecProcNode(outerPlan);
    2375           0 :     if (TupIsNull(result))
    2376           0 :         return false;
    2377             : 
    2378             :     /* Store result in the given slot */
    2379           0 :     ExecCopySlot(slot, result);
    2380             : 
    2381           0 :     return true;
    2382             : }
    2383             : 
    2384             : /*
    2385             :  * find_modifytable_subplan
    2386             :  *      Helper routine for postgresPlanDirectModify to find the
    2387             :  *      ModifyTable subplan node that scans the specified RTI.
    2388             :  *
    2389             :  * Returns NULL if the subplan couldn't be identified.  That's not a fatal
    2390             :  * error condition, we just abandon trying to do the update directly.
    2391             :  */
    2392             : static ForeignScan *
    2393         262 : find_modifytable_subplan(PlannerInfo *root,
    2394             :                          ModifyTable *plan,
    2395             :                          Index rtindex,
    2396             :                          int subplan_index)
    2397             : {
    2398         262 :     Plan       *subplan = outerPlan(plan);
    2399             : 
    2400             :     /*
    2401             :      * The cases we support are (1) the desired ForeignScan is the immediate
    2402             :      * child of ModifyTable, or (2) it is the subplan_index'th child of an
    2403             :      * Append node that is the immediate child of ModifyTable.  There is no
    2404             :      * point in looking further down, as that would mean that local joins are
    2405             :      * involved, so we can't do the update directly.
    2406             :      *
    2407             :      * There could be a Result atop the Append too, acting to compute the
    2408             :      * UPDATE targetlist values.  We ignore that here; the tlist will be
    2409             :      * checked by our caller.
    2410             :      *
    2411             :      * In principle we could examine all the children of the Append, but it's
    2412             :      * currently unlikely that the core planner would generate such a plan
    2413             :      * with the children out-of-order.  Moreover, such a search risks costing
    2414             :      * O(N^2) time when there are a lot of children.
    2415             :      */
    2416         262 :     if (IsA(subplan, Append))
    2417             :     {
    2418          66 :         Append     *appendplan = (Append *) subplan;
    2419             : 
    2420          66 :         if (subplan_index < list_length(appendplan->appendplans))
    2421          66 :             subplan = (Plan *) list_nth(appendplan->appendplans, subplan_index);
    2422             :     }
    2423         196 :     else if (IsA(subplan, Result) &&
    2424          12 :              outerPlan(subplan) != NULL &&
    2425          10 :              IsA(outerPlan(subplan), Append))
    2426             :     {
    2427          10 :         Append     *appendplan = (Append *) outerPlan(subplan);
    2428             : 
    2429          10 :         if (subplan_index < list_length(appendplan->appendplans))
    2430          10 :             subplan = (Plan *) list_nth(appendplan->appendplans, subplan_index);
    2431             :     }
    2432             : 
    2433             :     /* Now, have we got a ForeignScan on the desired rel? */
    2434         262 :     if (IsA(subplan, ForeignScan))
    2435             :     {
    2436         228 :         ForeignScan *fscan = (ForeignScan *) subplan;
    2437             : 
    2438         228 :         if (bms_is_member(rtindex, fscan->fs_base_relids))
    2439         228 :             return fscan;
    2440             :     }
    2441             : 
    2442          34 :     return NULL;
    2443             : }
    2444             : 
    2445             : /*
    2446             :  * postgresPlanDirectModify
    2447             :  *      Consider a direct foreign table modification
    2448             :  *
    2449             :  * Decide whether it is safe to modify a foreign table directly, and if so,
    2450             :  * rewrite subplan accordingly.
    2451             :  */
    2452             : static bool
    2453         388 : postgresPlanDirectModify(PlannerInfo *root,
    2454             :                          ModifyTable *plan,
    2455             :                          Index resultRelation,
    2456             :                          int subplan_index)
    2457             : {
    2458         388 :     CmdType     operation = plan->operation;
    2459             :     RelOptInfo *foreignrel;
    2460             :     RangeTblEntry *rte;
    2461             :     PgFdwRelationInfo *fpinfo;
    2462             :     Relation    rel;
    2463             :     StringInfoData sql;
    2464             :     ForeignScan *fscan;
    2465         388 :     List       *processed_tlist = NIL;
    2466         388 :     List       *targetAttrs = NIL;
    2467             :     List       *remote_exprs;
    2468         388 :     List       *params_list = NIL;
    2469         388 :     List       *returningList = NIL;
    2470         388 :     List       *retrieved_attrs = NIL;
    2471             : 
    2472             :     /*
    2473             :      * Decide whether it is safe to modify a foreign table directly.
    2474             :      */
    2475             : 
    2476             :     /*
    2477             :      * The table modification must be an UPDATE or DELETE.
    2478             :      */
    2479         388 :     if (operation != CMD_UPDATE && operation != CMD_DELETE)
    2480         126 :         return false;
    2481             : 
    2482             :     /*
    2483             :      * Try to locate the ForeignScan subplan that's scanning resultRelation.
    2484             :      */
    2485         262 :     fscan = find_modifytable_subplan(root, plan, resultRelation, subplan_index);
    2486         262 :     if (!fscan)
    2487          34 :         return false;
    2488             : 
    2489             :     /*
    2490             :      * It's unsafe to modify a foreign table directly if there are any quals
    2491             :      * that should be evaluated locally.
    2492             :      */
    2493         228 :     if (fscan->scan.plan.qual != NIL)
    2494          10 :         return false;
    2495             : 
    2496             :     /* Safe to fetch data about the target foreign rel */
    2497         218 :     if (fscan->scan.scanrelid == 0)
    2498             :     {
    2499          20 :         foreignrel = find_join_rel(root, fscan->fs_relids);
    2500             :         /* We should have a rel for this foreign join. */
    2501             :         Assert(foreignrel);
    2502             :     }
    2503             :     else
    2504         198 :         foreignrel = root->simple_rel_array[resultRelation];
    2505         218 :     rte = root->simple_rte_array[resultRelation];
    2506         218 :     fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    2507             : 
    2508             :     /*
    2509             :      * It's unsafe to update a foreign table directly, if any expressions to
    2510             :      * assign to the target columns are unsafe to evaluate remotely.
    2511             :      */
    2512         218 :     if (operation == CMD_UPDATE)
    2513             :     {
    2514             :         ListCell   *lc,
    2515             :                    *lc2;
    2516             : 
    2517             :         /*
    2518             :          * The expressions of concern are the first N columns of the processed
    2519             :          * targetlist, where N is the length of the rel's update_colnos.
    2520             :          */
    2521         100 :         get_translated_update_targetlist(root, resultRelation,
    2522             :                                          &processed_tlist, &targetAttrs);
    2523         206 :         forboth(lc, processed_tlist, lc2, targetAttrs)
    2524             :         {
    2525         116 :             TargetEntry *tle = lfirst_node(TargetEntry, lc);
    2526         116 :             AttrNumber  attno = lfirst_int(lc2);
    2527             : 
    2528             :             /* update's new-value expressions shouldn't be resjunk */
    2529             :             Assert(!tle->resjunk);
    2530             : 
    2531         116 :             if (attno <= InvalidAttrNumber) /* shouldn't happen */
    2532           0 :                 elog(ERROR, "system-column update is not supported");
    2533             : 
    2534         116 :             if (!is_foreign_expr(root, foreignrel, (Expr *) tle->expr))
    2535          10 :                 return false;
    2536             :         }
    2537             :     }
    2538             : 
    2539             :     /*
    2540             :      * Ok, rewrite subplan so as to modify the foreign table directly.
    2541             :      */
    2542         208 :     initStringInfo(&sql);
    2543             : 
    2544             :     /*
    2545             :      * Core code already has some lock on each rel being planned, so we can
    2546             :      * use NoLock here.
    2547             :      */
    2548         208 :     rel = table_open(rte->relid, NoLock);
    2549             : 
    2550             :     /*
    2551             :      * Recall the qual clauses that must be evaluated remotely.  (These are
    2552             :      * bare clauses not RestrictInfos, but deparse.c's appendConditions()
    2553             :      * doesn't care.)
    2554             :      */
    2555         208 :     remote_exprs = fpinfo->final_remote_exprs;
    2556             : 
    2557             :     /*
    2558             :      * Extract the relevant RETURNING list if any.
    2559             :      */
    2560         208 :     if (plan->returningLists)
    2561             :     {
    2562          70 :         returningList = (List *) list_nth(plan->returningLists, subplan_index);
    2563             : 
    2564             :         /*
    2565             :          * When performing an UPDATE/DELETE .. RETURNING on a join directly,
    2566             :          * we fetch from the foreign server any Vars specified in RETURNING
    2567             :          * that refer not only to the target relation but to non-target
    2568             :          * relations.  So we'll deparse them into the RETURNING clause of the
    2569             :          * remote query; use a targetlist consisting of them instead, which
    2570             :          * will be adjusted to be new fdw_scan_tlist of the foreign-scan plan
    2571             :          * node below.
    2572             :          */
    2573          70 :         if (fscan->scan.scanrelid == 0)
    2574           8 :             returningList = build_remote_returning(resultRelation, rel,
    2575             :                                                    returningList);
    2576             :     }
    2577             : 
    2578             :     /*
    2579             :      * Construct the SQL command string.
    2580             :      */
    2581         208 :     switch (operation)
    2582             :     {
    2583          90 :         case CMD_UPDATE:
    2584          90 :             deparseDirectUpdateSql(&sql, root, resultRelation, rel,
    2585             :                                    foreignrel,
    2586             :                                    processed_tlist,
    2587             :                                    targetAttrs,
    2588             :                                    remote_exprs, &params_list,
    2589             :                                    returningList, &retrieved_attrs);
    2590          90 :             break;
    2591         118 :         case CMD_DELETE:
    2592         118 :             deparseDirectDeleteSql(&sql, root, resultRelation, rel,
    2593             :                                    foreignrel,
    2594             :                                    remote_exprs, &params_list,
    2595             :                                    returningList, &retrieved_attrs);
    2596         118 :             break;
    2597           0 :         default:
    2598           0 :             elog(ERROR, "unexpected operation: %d", (int) operation);
    2599             :             break;
    2600             :     }
    2601             : 
    2602             :     /*
    2603             :      * Update the operation and target relation info.
    2604             :      */
    2605         208 :     fscan->operation = operation;
    2606         208 :     fscan->resultRelation = resultRelation;
    2607             : 
    2608             :     /*
    2609             :      * Update the fdw_exprs list that will be available to the executor.
    2610             :      */
    2611         208 :     fscan->fdw_exprs = params_list;
    2612             : 
    2613             :     /*
    2614             :      * Update the fdw_private list that will be available to the executor.
    2615             :      * Items in the list must match enum FdwDirectModifyPrivateIndex, above.
    2616             :      */
    2617         208 :     fscan->fdw_private = list_make4(makeString(sql.data),
    2618             :                                     makeBoolean((retrieved_attrs != NIL)),
    2619             :                                     retrieved_attrs,
    2620             :                                     makeBoolean(plan->canSetTag));
    2621             : 
    2622             :     /*
    2623             :      * Update the foreign-join-related fields.
    2624             :      */
    2625         208 :     if (fscan->scan.scanrelid == 0)
    2626             :     {
    2627             :         /* No need for the outer subplan. */
    2628          16 :         fscan->scan.plan.lefttree = NULL;
    2629             : 
    2630             :         /* Build new fdw_scan_tlist if UPDATE/DELETE .. RETURNING. */
    2631          16 :         if (returningList)
    2632           4 :             rebuild_fdw_scan_tlist(fscan, returningList);
    2633             :     }
    2634             : 
    2635             :     /*
    2636             :      * Finally, unset the async-capable flag if it is set, as we currently
    2637             :      * don't support asynchronous execution of direct modifications.
    2638             :      */
    2639         208 :     if (fscan->scan.plan.async_capable)
    2640          16 :         fscan->scan.plan.async_capable = false;
    2641             : 
    2642         208 :     table_close(rel, NoLock);
    2643         208 :     return true;
    2644             : }
    2645             : 
    2646             : /*
    2647             :  * postgresBeginDirectModify
    2648             :  *      Prepare a direct foreign table modification
    2649             :  */
    2650             : static void
    2651         208 : postgresBeginDirectModify(ForeignScanState *node, int eflags)
    2652             : {
    2653         208 :     ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
    2654         208 :     EState     *estate = node->ss.ps.state;
    2655             :     PgFdwDirectModifyState *dmstate;
    2656             :     Index       rtindex;
    2657             :     Oid         userid;
    2658             :     ForeignTable *table;
    2659             :     UserMapping *user;
    2660             :     int         numParams;
    2661             : 
    2662             :     /*
    2663             :      * Do nothing in EXPLAIN (no ANALYZE) case.  node->fdw_state stays NULL.
    2664             :      */
    2665         208 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
    2666          64 :         return;
    2667             : 
    2668             :     /*
    2669             :      * We'll save private state in node->fdw_state.
    2670             :      */
    2671         144 :     dmstate = (PgFdwDirectModifyState *) palloc0(sizeof(PgFdwDirectModifyState));
    2672         144 :     node->fdw_state = dmstate;
    2673             : 
    2674             :     /*
    2675             :      * We use a memory context callback to ensure that the dmstate's PGresult
    2676             :      * (if any) will be released, even if the query fails somewhere that's
    2677             :      * outside our control.  The callback is always armed for the duration of
    2678             :      * the query; this relies on PQclear(NULL) being a no-op.
    2679             :      */
    2680         144 :     dmstate->result_cb.func = (MemoryContextCallbackFunction) PQclear;
    2681         144 :     dmstate->result_cb.arg = NULL;
    2682         144 :     MemoryContextRegisterResetCallback(CurrentMemoryContext,
    2683             :                                        &dmstate->result_cb);
    2684             : 
    2685             :     /*
    2686             :      * Identify which user to do the remote access as.  This should match what
    2687             :      * ExecCheckPermissions() does.
    2688             :      */
    2689         144 :     userid = OidIsValid(fsplan->checkAsUser) ? fsplan->checkAsUser : GetUserId();
    2690             : 
    2691             :     /* Get info about foreign table. */
    2692         144 :     rtindex = node->resultRelInfo->ri_RangeTableIndex;
    2693         144 :     if (fsplan->scan.scanrelid == 0)
    2694           8 :         dmstate->rel = ExecOpenScanRelation(estate, rtindex, eflags);
    2695             :     else
    2696         136 :         dmstate->rel = node->ss.ss_currentRelation;
    2697         144 :     table = GetForeignTable(RelationGetRelid(dmstate->rel));
    2698         144 :     user = GetUserMapping(userid, table->serverid);
    2699             : 
    2700             :     /*
    2701             :      * Get connection to the foreign server.  Connection manager will
    2702             :      * establish new connection if necessary.
    2703             :      */
    2704         144 :     dmstate->conn = GetConnection(user, false, &dmstate->conn_state);
    2705             : 
    2706             :     /* Update the foreign-join-related fields. */
    2707         144 :     if (fsplan->scan.scanrelid == 0)
    2708             :     {
    2709             :         /* Save info about foreign table. */
    2710           8 :         dmstate->resultRel = dmstate->rel;
    2711             : 
    2712             :         /*
    2713             :          * Set dmstate->rel to NULL to teach get_returning_data() and
    2714             :          * make_tuple_from_result_row() that columns fetched from the remote
    2715             :          * server are described by fdw_scan_tlist of the foreign-scan plan
    2716             :          * node, not the tuple descriptor for the target relation.
    2717             :          */
    2718           8 :         dmstate->rel = NULL;
    2719             :     }
    2720             : 
    2721             :     /* Initialize state variable */
    2722         144 :     dmstate->num_tuples = -1;    /* -1 means not set yet */
    2723             : 
    2724             :     /* Get private info created by planner functions. */
    2725         144 :     dmstate->query = strVal(list_nth(fsplan->fdw_private,
    2726             :                                      FdwDirectModifyPrivateUpdateSql));
    2727         144 :     dmstate->has_returning = boolVal(list_nth(fsplan->fdw_private,
    2728             :                                               FdwDirectModifyPrivateHasReturning));
    2729         144 :     dmstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
    2730             :                                                  FdwDirectModifyPrivateRetrievedAttrs);
    2731         144 :     dmstate->set_processed = boolVal(list_nth(fsplan->fdw_private,
    2732             :                                               FdwDirectModifyPrivateSetProcessed));
    2733             : 
    2734             :     /* Create context for per-tuple temp workspace. */
    2735         144 :     dmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
    2736             :                                               "postgres_fdw temporary data",
    2737             :                                               ALLOCSET_SMALL_SIZES);
    2738             : 
    2739             :     /* Prepare for input conversion of RETURNING results. */
    2740         144 :     if (dmstate->has_returning)
    2741             :     {
    2742             :         TupleDesc   tupdesc;
    2743             : 
    2744          32 :         if (fsplan->scan.scanrelid == 0)
    2745           2 :             tupdesc = get_tupdesc_for_join_scan_tuples(node);
    2746             :         else
    2747          30 :             tupdesc = RelationGetDescr(dmstate->rel);
    2748             : 
    2749          32 :         dmstate->attinmeta = TupleDescGetAttInMetadata(tupdesc);
    2750             : 
    2751             :         /*
    2752             :          * When performing an UPDATE/DELETE .. RETURNING on a join directly,
    2753             :          * initialize a filter to extract an updated/deleted tuple from a scan
    2754             :          * tuple.
    2755             :          */
    2756          32 :         if (fsplan->scan.scanrelid == 0)
    2757           2 :             init_returning_filter(dmstate, fsplan->fdw_scan_tlist, rtindex);
    2758             :     }
    2759             : 
    2760             :     /*
    2761             :      * Prepare for processing of parameters used in remote query, if any.
    2762             :      */
    2763         144 :     numParams = list_length(fsplan->fdw_exprs);
    2764         144 :     dmstate->numParams = numParams;
    2765         144 :     if (numParams > 0)
    2766           0 :         prepare_query_params((PlanState *) node,
    2767             :                              fsplan->fdw_exprs,
    2768             :                              numParams,
    2769             :                              &dmstate->param_flinfo,
    2770             :                              &dmstate->param_exprs,
    2771             :                              &dmstate->param_values);
    2772             : }
    2773             : 
    2774             : /*
    2775             :  * postgresIterateDirectModify
    2776             :  *      Execute a direct foreign table modification
    2777             :  */
    2778             : static TupleTableSlot *
    2779         836 : postgresIterateDirectModify(ForeignScanState *node)
    2780             : {
    2781         836 :     PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
    2782         836 :     EState     *estate = node->ss.ps.state;
    2783         836 :     ResultRelInfo *resultRelInfo = node->resultRelInfo;
    2784             : 
    2785             :     /*
    2786             :      * If this is the first call after Begin, execute the statement.
    2787             :      */
    2788         836 :     if (dmstate->num_tuples == -1)
    2789         142 :         execute_dml_stmt(node);
    2790             : 
    2791             :     /*
    2792             :      * If the local query doesn't specify RETURNING, just clear tuple slot.
    2793             :      */
    2794         828 :     if (!resultRelInfo->ri_projectReturning)
    2795             :     {
    2796         100 :         TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
    2797         100 :         Instrumentation *instr = node->ss.ps.instrument;
    2798             : 
    2799             :         Assert(!dmstate->has_returning);
    2800             : 
    2801             :         /* Increment the command es_processed count if necessary. */
    2802         100 :         if (dmstate->set_processed)
    2803         100 :             estate->es_processed += dmstate->num_tuples;
    2804             : 
    2805             :         /* Increment the tuple count for EXPLAIN ANALYZE if necessary. */
    2806         100 :         if (instr)
    2807           0 :             instr->tuplecount += dmstate->num_tuples;
    2808             : 
    2809         100 :         return ExecClearTuple(slot);
    2810             :     }
    2811             : 
    2812             :     /*
    2813             :      * Get the next RETURNING tuple.
    2814             :      */
    2815         728 :     return get_returning_data(node);
    2816             : }
    2817             : 
    2818             : /*
    2819             :  * postgresEndDirectModify
    2820             :  *      Finish a direct foreign table modification
    2821             :  */
    2822             : static void
    2823         192 : postgresEndDirectModify(ForeignScanState *node)
    2824             : {
    2825         192 :     PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
    2826             : 
    2827             :     /* if dmstate is NULL, we are in EXPLAIN; nothing to do */
    2828         192 :     if (dmstate == NULL)
    2829          64 :         return;
    2830             : 
    2831             :     /* Release PGresult */
    2832         128 :     if (dmstate->result)
    2833             :     {
    2834         128 :         PQclear(dmstate->result);
    2835         128 :         dmstate->result = NULL;
    2836             :         /* ... and don't forget to disable the callback */
    2837         128 :         dmstate->result_cb.arg = NULL;
    2838             :     }
    2839             : 
    2840             :     /* Release remote connection */
    2841         128 :     ReleaseConnection(dmstate->conn);
    2842         128 :     dmstate->conn = NULL;
    2843             : 
    2844             :     /* MemoryContext will be deleted automatically. */
    2845             : }
    2846             : 
    2847             : /*
    2848             :  * postgresExplainForeignScan
    2849             :  *      Produce extra output for EXPLAIN of a ForeignScan on a foreign table
    2850             :  */
    2851             : static void
    2852         770 : postgresExplainForeignScan(ForeignScanState *node, ExplainState *es)
    2853             : {
    2854         770 :     ForeignScan *plan = castNode(ForeignScan, node->ss.ps.plan);
    2855         770 :     List       *fdw_private = plan->fdw_private;
    2856             : 
    2857             :     /*
    2858             :      * Identify foreign scans that are really joins or upper relations.  The
    2859             :      * input looks something like "(1) LEFT JOIN (2)", and we must replace the
    2860             :      * digit string(s), which are RT indexes, with the correct relation names.
    2861             :      * We do that here, not when the plan is created, because we can't know
    2862             :      * what aliases ruleutils.c will assign at plan creation time.
    2863             :      */
    2864         770 :     if (list_length(fdw_private) > FdwScanPrivateRelations)
    2865             :     {
    2866             :         StringInfo  relations;
    2867             :         char       *rawrelations;
    2868             :         char       *ptr;
    2869             :         int         minrti,
    2870             :                     rtoffset;
    2871             : 
    2872         240 :         rawrelations = strVal(list_nth(fdw_private, FdwScanPrivateRelations));
    2873             : 
    2874             :         /*
    2875             :          * A difficulty with using a string representation of RT indexes is
    2876             :          * that setrefs.c won't update the string when flattening the
    2877             :          * rangetable.  To find out what rtoffset was applied, identify the
    2878             :          * minimum RT index appearing in the string and compare it to the
    2879             :          * minimum member of plan->fs_base_relids.  (We expect all the relids
    2880             :          * in the join will have been offset by the same amount; the Asserts
    2881             :          * below should catch it if that ever changes.)
    2882             :          */
    2883         240 :         minrti = INT_MAX;
    2884         240 :         ptr = rawrelations;
    2885        5720 :         while (*ptr)
    2886             :         {
    2887        5480 :             if (isdigit((unsigned char) *ptr))
    2888             :             {
    2889         476 :                 int         rti = strtol(ptr, &ptr, 10);
    2890             : 
    2891         476 :                 if (rti < minrti)
    2892         264 :                     minrti = rti;
    2893             :             }
    2894             :             else
    2895        5004 :                 ptr++;
    2896             :         }
    2897         240 :         rtoffset = bms_next_member(plan->fs_base_relids, -1) - minrti;
    2898             : 
    2899             :         /* Now we can translate the string */
    2900         240 :         relations = makeStringInfo();
    2901         240 :         ptr = rawrelations;
    2902        5720 :         while (*ptr)
    2903             :         {
    2904        5480 :             if (isdigit((unsigned char) *ptr))
    2905             :             {
    2906         476 :                 int         rti = strtol(ptr, &ptr, 10);
    2907             :                 RangeTblEntry *rte;
    2908             :                 char       *relname;
    2909             :                 char       *refname;
    2910             : 
    2911         476 :                 rti += rtoffset;
    2912             :                 Assert(bms_is_member(rti, plan->fs_base_relids));
    2913         476 :                 rte = rt_fetch(rti, es->rtable);
    2914             :                 Assert(rte->rtekind == RTE_RELATION);
    2915             :                 /* This logic should agree with explain.c's ExplainTargetRel */
    2916         476 :                 relname = get_rel_name(rte->relid);
    2917         476 :                 if (es->verbose)
    2918             :                 {
    2919             :                     char       *namespace;
    2920             : 
    2921         450 :                     namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid));
    2922         450 :                     appendStringInfo(relations, "%s.%s",
    2923             :                                      quote_identifier(namespace),
    2924             :                                      quote_identifier(relname));
    2925             :                 }
    2926             :                 else
    2927          26 :                     appendStringInfoString(relations,
    2928             :                                            quote_identifier(relname));
    2929         476 :                 refname = (char *) list_nth(es->rtable_names, rti - 1);
    2930         476 :                 if (refname == NULL)
    2931           0 :                     refname = rte->eref->aliasname;
    2932         476 :                 if (strcmp(refname, relname) != 0)
    2933         298 :                     appendStringInfo(relations, " %s",
    2934             :                                      quote_identifier(refname));
    2935             :             }
    2936             :             else
    2937        5004 :                 appendStringInfoChar(relations, *ptr++);
    2938             :         }
    2939         240 :         ExplainPropertyText("Relations", relations->data, es);
    2940             :     }
    2941             : 
    2942             :     /*
    2943             :      * Add remote query, when VERBOSE option is specified.
    2944             :      */
    2945         770 :     if (es->verbose)
    2946             :     {
    2947             :         char       *sql;
    2948             : 
    2949         698 :         sql = strVal(list_nth(fdw_private, FdwScanPrivateSelectSql));
    2950         698 :         ExplainPropertyText("Remote SQL", sql, es);
    2951             :     }
    2952         770 : }
    2953             : 
    2954             : /*
    2955             :  * postgresExplainForeignModify
    2956             :  *      Produce extra output for EXPLAIN of a ModifyTable on a foreign table
    2957             :  */
    2958             : static void
    2959          84 : postgresExplainForeignModify(ModifyTableState *mtstate,
    2960             :                              ResultRelInfo *rinfo,
    2961             :                              List *fdw_private,
    2962             :                              int subplan_index,
    2963             :                              ExplainState *es)
    2964             : {
    2965          84 :     if (es->verbose)
    2966             :     {
    2967          84 :         char       *sql = strVal(list_nth(fdw_private,
    2968             :                                           FdwModifyPrivateUpdateSql));
    2969             : 
    2970          84 :         ExplainPropertyText("Remote SQL", sql, es);
    2971             : 
    2972             :         /*
    2973             :          * For INSERT we should always have batch size >= 1, but UPDATE and
    2974             :          * DELETE don't support batching so don't show the property.
    2975             :          */
    2976          84 :         if (rinfo->ri_BatchSize > 0)
    2977          26 :             ExplainPropertyInteger("Batch Size", NULL, rinfo->ri_BatchSize, es);
    2978             :     }
    2979          84 : }
    2980             : 
    2981             : /*
    2982             :  * postgresExplainDirectModify
    2983             :  *      Produce extra output for EXPLAIN of a ForeignScan that modifies a
    2984             :  *      foreign table directly
    2985             :  */
    2986             : static void
    2987          64 : postgresExplainDirectModify(ForeignScanState *node, ExplainState *es)
    2988             : {
    2989             :     List       *fdw_private;
    2990             :     char       *sql;
    2991             : 
    2992          64 :     if (es->verbose)
    2993             :     {
    2994          64 :         fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private;
    2995          64 :         sql = strVal(list_nth(fdw_private, FdwDirectModifyPrivateUpdateSql));
    2996          64 :         ExplainPropertyText("Remote SQL", sql, es);
    2997             :     }
    2998          64 : }
    2999             : 
    3000             : /*
    3001             :  * postgresExecForeignTruncate
    3002             :  *      Truncate one or more foreign tables
    3003             :  */
    3004             : static void
    3005          30 : postgresExecForeignTruncate(List *rels,
    3006             :                             DropBehavior behavior,
    3007             :                             bool restart_seqs)
    3008             : {
    3009          30 :     Oid         serverid = InvalidOid;
    3010          30 :     UserMapping *user = NULL;
    3011          30 :     PGconn     *conn = NULL;
    3012             :     StringInfoData sql;
    3013             :     ListCell   *lc;
    3014          30 :     bool        server_truncatable = true;
    3015             : 
    3016             :     /*
    3017             :      * By default, all postgres_fdw foreign tables are assumed truncatable.
    3018             :      * This can be overridden by a per-server setting, which in turn can be
    3019             :      * overridden by a per-table setting.
    3020             :      */
    3021          58 :     foreach(lc, rels)
    3022             :     {
    3023          34 :         ForeignServer *server = NULL;
    3024          34 :         Relation    rel = lfirst(lc);
    3025          34 :         ForeignTable *table = GetForeignTable(RelationGetRelid(rel));
    3026             :         ListCell   *cell;
    3027             :         bool        truncatable;
    3028             : 
    3029             :         /*
    3030             :          * First time through, determine whether the foreign server allows
    3031             :          * truncates. Since all specified foreign tables are assumed to belong
    3032             :          * to the same foreign server, this result can be used for other
    3033             :          * foreign tables.
    3034             :          */
    3035          34 :         if (!OidIsValid(serverid))
    3036             :         {
    3037          30 :             serverid = table->serverid;
    3038          30 :             server = GetForeignServer(serverid);
    3039             : 
    3040         120 :             foreach(cell, server->options)
    3041             :             {
    3042          96 :                 DefElem    *defel = (DefElem *) lfirst(cell);
    3043             : 
    3044          96 :                 if (strcmp(defel->defname, "truncatable") == 0)
    3045             :                 {
    3046           6 :                     server_truncatable = defGetBoolean(defel);
    3047           6 :                     break;
    3048             :                 }
    3049             :             }
    3050             :         }
    3051             : 
    3052             :         /*
    3053             :          * Confirm that all specified foreign tables belong to the same
    3054             :          * foreign server.
    3055             :          */
    3056             :         Assert(table->serverid == serverid);
    3057             : 
    3058             :         /* Determine whether this foreign table allows truncations */
    3059          34 :         truncatable = server_truncatable;
    3060          68 :         foreach(cell, table->options)
    3061             :         {
    3062          48 :             DefElem    *defel = (DefElem *) lfirst(cell);
    3063             : 
    3064          48 :             if (strcmp(defel->defname, "truncatable") == 0)
    3065             :             {
    3066          14 :                 truncatable = defGetBoolean(defel);
    3067          14 :                 break;
    3068             :             }
    3069             :         }
    3070             : 
    3071          34 :         if (!truncatable)
    3072           6 :             ereport(ERROR,
    3073             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    3074             :                      errmsg("foreign table \"%s\" does not allow truncates",
    3075             :                             RelationGetRelationName(rel))));
    3076             :     }
    3077             :     Assert(OidIsValid(serverid));
    3078             : 
    3079             :     /*
    3080             :      * Get connection to the foreign server.  Connection manager will
    3081             :      * establish new connection if necessary.
    3082             :      */
    3083          24 :     user = GetUserMapping(GetUserId(), serverid);
    3084          24 :     conn = GetConnection(user, false, NULL);
    3085             : 
    3086             :     /* Construct the TRUNCATE command string */
    3087          24 :     initStringInfo(&sql);
    3088          24 :     deparseTruncateSql(&sql, rels, behavior, restart_seqs);
    3089             : 
    3090             :     /* Issue the TRUNCATE command to remote server */
    3091          24 :     do_sql_command(conn, sql.data);
    3092             : 
    3093          22 :     pfree(sql.data);
    3094          22 : }
    3095             : 
    3096             : /*
    3097             :  * estimate_path_cost_size
    3098             :  *      Get cost and size estimates for a foreign scan on given foreign relation
    3099             :  *      either a base relation or a join between foreign relations or an upper
    3100             :  *      relation containing foreign relations.
    3101             :  *
    3102             :  * param_join_conds are the parameterization clauses with outer relations.
    3103             :  * pathkeys specify the expected sort order if any for given path being costed.
    3104             :  * fpextra specifies additional post-scan/join-processing steps such as the
    3105             :  * final sort and the LIMIT restriction.
    3106             :  *
    3107             :  * The function returns the cost and size estimates in p_rows, p_width,
    3108             :  * p_disabled_nodes, p_startup_cost and p_total_cost variables.
    3109             :  */
    3110             : static void
    3111        5342 : estimate_path_cost_size(PlannerInfo *root,
    3112             :                         RelOptInfo *foreignrel,
    3113             :                         List *param_join_conds,
    3114             :                         List *pathkeys,
    3115             :                         PgFdwPathExtraData *fpextra,
    3116             :                         double *p_rows, int *p_width,
    3117             :                         int *p_disabled_nodes,
    3118             :                         Cost *p_startup_cost, Cost *p_total_cost)
    3119             : {
    3120        5342 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
    3121             :     double      rows;
    3122             :     double      retrieved_rows;
    3123             :     int         width;
    3124        5342 :     int         disabled_nodes = 0;
    3125             :     Cost        startup_cost;
    3126             :     Cost        total_cost;
    3127             : 
    3128             :     /* Make sure the core code has set up the relation's reltarget */
    3129             :     Assert(foreignrel->reltarget);
    3130             : 
    3131             :     /*
    3132             :      * If the table or the server is configured to use remote estimates,
    3133             :      * connect to the foreign server and execute EXPLAIN to estimate the
    3134             :      * number of rows selected by the restriction+join clauses.  Otherwise,
    3135             :      * estimate rows using whatever statistics we have locally, in a way
    3136             :      * similar to ordinary tables.
    3137             :      */
    3138        5342 :     if (fpinfo->use_remote_estimate)
    3139             :     {
    3140             :         List       *remote_param_join_conds;
    3141             :         List       *local_param_join_conds;
    3142             :         StringInfoData sql;
    3143             :         PGconn     *conn;
    3144             :         Selectivity local_sel;
    3145             :         QualCost    local_cost;
    3146        2566 :         List       *fdw_scan_tlist = NIL;
    3147             :         List       *remote_conds;
    3148             : 
    3149             :         /* Required only to be passed to deparseSelectStmtForRel */
    3150             :         List       *retrieved_attrs;
    3151             : 
    3152             :         /*
    3153             :          * param_join_conds might contain both clauses that are safe to send
    3154             :          * across, and clauses that aren't.
    3155             :          */
    3156        2566 :         classifyConditions(root, foreignrel, param_join_conds,
    3157             :                            &remote_param_join_conds, &local_param_join_conds);
    3158             : 
    3159             :         /* Build the list of columns to be fetched from the foreign server. */
    3160        2566 :         if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
    3161        1040 :             fdw_scan_tlist = build_tlist_to_deparse(foreignrel);
    3162             :         else
    3163        1526 :             fdw_scan_tlist = NIL;
    3164             : 
    3165             :         /*
    3166             :          * The complete list of remote conditions includes everything from
    3167             :          * baserestrictinfo plus any extra join_conds relevant to this
    3168             :          * particular path.
    3169             :          */
    3170        2566 :         remote_conds = list_concat(remote_param_join_conds,
    3171        2566 :                                    fpinfo->remote_conds);
    3172             : 
    3173             :         /*
    3174             :          * Construct EXPLAIN query including the desired SELECT, FROM, and
    3175             :          * WHERE clauses. Params and other-relation Vars are replaced by dummy
    3176             :          * values, so don't request params_list.
    3177             :          */
    3178        2566 :         initStringInfo(&sql);
    3179        2566 :         appendStringInfoString(&sql, "EXPLAIN ");
    3180        2566 :         deparseSelectStmtForRel(&sql, root, foreignrel, fdw_scan_tlist,
    3181             :                                 remote_conds, pathkeys,
    3182        2566 :                                 fpextra ? fpextra->has_final_sort : false,
    3183        2566 :                                 fpextra ? fpextra->has_limit : false,
    3184             :                                 false, &retrieved_attrs, NULL);
    3185             : 
    3186             :         /* Get the remote estimate */
    3187        2566 :         conn = GetConnection(fpinfo->user, false, NULL);
    3188        2566 :         get_remote_estimate(sql.data, conn, &rows, &width,
    3189             :                             &startup_cost, &total_cost);
    3190        2566 :         ReleaseConnection(conn);
    3191             : 
    3192        2566 :         retrieved_rows = rows;
    3193             : 
    3194             :         /* Factor in the selectivity of the locally-checked quals */
    3195        2566 :         local_sel = clauselist_selectivity(root,
    3196             :                                            local_param_join_conds,
    3197        2566 :                                            foreignrel->relid,
    3198             :                                            JOIN_INNER,
    3199             :                                            NULL);
    3200        2566 :         local_sel *= fpinfo->local_conds_sel;
    3201             : 
    3202        2566 :         rows = clamp_row_est(rows * local_sel);
    3203             : 
    3204             :         /* Add in the eval cost of the locally-checked quals */
    3205        2566 :         startup_cost += fpinfo->local_conds_cost.startup;
    3206        2566 :         total_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
    3207        2566 :         cost_qual_eval(&local_cost, local_param_join_conds, root);
    3208        2566 :         startup_cost += local_cost.startup;
    3209        2566 :         total_cost += local_cost.per_tuple * retrieved_rows;
    3210             : 
    3211             :         /*
    3212             :          * Add in tlist eval cost for each output row.  In case of an
    3213             :          * aggregate, some of the tlist expressions such as grouping
    3214             :          * expressions will be evaluated remotely, so adjust the costs.
    3215             :          */
    3216        2566 :         startup_cost += foreignrel->reltarget->cost.startup;
    3217        2566 :         total_cost += foreignrel->reltarget->cost.startup;
    3218        2566 :         total_cost += foreignrel->reltarget->cost.per_tuple * rows;
    3219        2566 :         if (IS_UPPER_REL(foreignrel))
    3220             :         {
    3221             :             QualCost    tlist_cost;
    3222             : 
    3223          78 :             cost_qual_eval(&tlist_cost, fdw_scan_tlist, root);
    3224          78 :             startup_cost -= tlist_cost.startup;
    3225          78 :             total_cost -= tlist_cost.startup;
    3226          78 :             total_cost -= tlist_cost.per_tuple * rows;
    3227             :         }
    3228             :     }
    3229             :     else
    3230             :     {
    3231        2776 :         Cost        run_cost = 0;
    3232             : 
    3233             :         /*
    3234             :          * We don't support join conditions in this mode (hence, no
    3235             :          * parameterized paths can be made).
    3236             :          */
    3237             :         Assert(param_join_conds == NIL);
    3238             : 
    3239             :         /*
    3240             :          * We will come here again and again with different set of pathkeys or
    3241             :          * additional post-scan/join-processing steps that caller wants to
    3242             :          * cost.  We don't need to calculate the cost/size estimates for the
    3243             :          * underlying scan, join, or grouping each time.  Instead, use those
    3244             :          * estimates if we have cached them already.
    3245             :          */
    3246        2776 :         if (fpinfo->rel_startup_cost >= 0 && fpinfo->rel_total_cost >= 0)
    3247             :         {
    3248             :             Assert(fpinfo->retrieved_rows >= 0);
    3249             : 
    3250         620 :             rows = fpinfo->rows;
    3251         620 :             retrieved_rows = fpinfo->retrieved_rows;
    3252         620 :             width = fpinfo->width;
    3253         620 :             startup_cost = fpinfo->rel_startup_cost;
    3254         620 :             run_cost = fpinfo->rel_total_cost - fpinfo->rel_startup_cost;
    3255             : 
    3256             :             /*
    3257             :              * If we estimate the costs of a foreign scan or a foreign join
    3258             :              * with additional post-scan/join-processing steps, the scan or
    3259             :              * join costs obtained from the cache wouldn't yet contain the
    3260             :              * eval costs for the final scan/join target, which would've been
    3261             :              * updated by apply_scanjoin_target_to_paths(); add the eval costs
    3262             :              * now.
    3263             :              */
    3264         620 :             if (fpextra && !IS_UPPER_REL(foreignrel))
    3265             :             {
    3266             :                 /* Shouldn't get here unless we have LIMIT */
    3267             :                 Assert(fpextra->has_limit);
    3268             :                 Assert(foreignrel->reloptkind == RELOPT_BASEREL ||
    3269             :                        foreignrel->reloptkind == RELOPT_JOINREL);
    3270         180 :                 startup_cost += foreignrel->reltarget->cost.startup;
    3271         180 :                 run_cost += foreignrel->reltarget->cost.per_tuple * rows;
    3272             :             }
    3273             :         }
    3274        2156 :         else if (IS_JOIN_REL(foreignrel))
    3275         224 :         {
    3276             :             PgFdwRelationInfo *fpinfo_i;
    3277             :             PgFdwRelationInfo *fpinfo_o;
    3278             :             QualCost    join_cost;
    3279             :             QualCost    remote_conds_cost;
    3280             :             double      nrows;
    3281             : 
    3282             :             /* Use rows/width estimates made by the core code. */
    3283         224 :             rows = foreignrel->rows;
    3284         224 :             width = foreignrel->reltarget->width;
    3285             : 
    3286             :             /* For join we expect inner and outer relations set */
    3287             :             Assert(fpinfo->innerrel && fpinfo->outerrel);
    3288             : 
    3289         224 :             fpinfo_i = (PgFdwRelationInfo *) fpinfo->innerrel->fdw_private;
    3290         224 :             fpinfo_o = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
    3291             : 
    3292             :             /* Estimate of number of rows in cross product */
    3293         224 :             nrows = fpinfo_i->rows * fpinfo_o->rows;
    3294             : 
    3295             :             /*
    3296             :              * Back into an estimate of the number of retrieved rows.  Just in
    3297             :              * case this is nuts, clamp to at most nrows.
    3298             :              */
    3299         224 :             retrieved_rows = clamp_row_est(rows / fpinfo->local_conds_sel);
    3300         224 :             retrieved_rows = Min(retrieved_rows, nrows);
    3301             : 
    3302             :             /*
    3303             :              * The cost of foreign join is estimated as cost of generating
    3304             :              * rows for the joining relations + cost for applying quals on the
    3305             :              * rows.
    3306             :              */
    3307             : 
    3308             :             /*
    3309             :              * Calculate the cost of clauses pushed down to the foreign server
    3310             :              */
    3311         224 :             cost_qual_eval(&remote_conds_cost, fpinfo->remote_conds, root);
    3312             :             /* Calculate the cost of applying join clauses */
    3313         224 :             cost_qual_eval(&join_cost, fpinfo->joinclauses, root);
    3314             : 
    3315             :             /*
    3316             :              * Startup cost includes startup cost of joining relations and the
    3317             :              * startup cost for join and other clauses. We do not include the
    3318             :              * startup cost specific to join strategy (e.g. setting up hash
    3319             :              * tables) since we do not know what strategy the foreign server
    3320             :              * is going to use.
    3321             :              */
    3322         224 :             startup_cost = fpinfo_i->rel_startup_cost + fpinfo_o->rel_startup_cost;
    3323         224 :             startup_cost += join_cost.startup;
    3324         224 :             startup_cost += remote_conds_cost.startup;
    3325         224 :             startup_cost += fpinfo->local_conds_cost.startup;
    3326             : 
    3327             :             /*
    3328             :              * Run time cost includes:
    3329             :              *
    3330             :              * 1. Run time cost (total_cost - startup_cost) of relations being
    3331             :              * joined
    3332             :              *
    3333             :              * 2. Run time cost of applying join clauses on the cross product
    3334             :              * of the joining relations.
    3335             :              *
    3336             :              * 3. Run time cost of applying pushed down other clauses on the
    3337             :              * result of join
    3338             :              *
    3339             :              * 4. Run time cost of applying nonpushable other clauses locally
    3340             :              * on the result fetched from the foreign server.
    3341             :              */
    3342         224 :             run_cost = fpinfo_i->rel_total_cost - fpinfo_i->rel_startup_cost;
    3343         224 :             run_cost += fpinfo_o->rel_total_cost - fpinfo_o->rel_startup_cost;
    3344         224 :             run_cost += nrows * join_cost.per_tuple;
    3345         224 :             nrows = clamp_row_est(nrows * fpinfo->joinclause_sel);
    3346         224 :             run_cost += nrows * remote_conds_cost.per_tuple;
    3347         224 :             run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
    3348             : 
    3349             :             /* Add in tlist eval cost for each output row */
    3350         224 :             startup_cost += foreignrel->reltarget->cost.startup;
    3351         224 :             run_cost += foreignrel->reltarget->cost.per_tuple * rows;
    3352             :         }
    3353        1932 :         else if (IS_UPPER_REL(foreignrel))
    3354         196 :         {
    3355         196 :             RelOptInfo *outerrel = fpinfo->outerrel;
    3356             :             PgFdwRelationInfo *ofpinfo;
    3357         196 :             AggClauseCosts aggcosts = {0};
    3358             :             double      input_rows;
    3359             :             int         numGroupCols;
    3360         196 :             double      numGroups = 1;
    3361             : 
    3362             :             /* The upper relation should have its outer relation set */
    3363             :             Assert(outerrel);
    3364             :             /* and that outer relation should have its reltarget set */
    3365             :             Assert(outerrel->reltarget);
    3366             : 
    3367             :             /*
    3368             :              * This cost model is mixture of costing done for sorted and
    3369             :              * hashed aggregates in cost_agg().  We are not sure which
    3370             :              * strategy will be considered at remote side, thus for
    3371             :              * simplicity, we put all startup related costs in startup_cost
    3372             :              * and all finalization and run cost are added in total_cost.
    3373             :              */
    3374             : 
    3375         196 :             ofpinfo = (PgFdwRelationInfo *) outerrel->fdw_private;
    3376             : 
    3377             :             /* Get rows from input rel */
    3378         196 :             input_rows = ofpinfo->rows;
    3379             : 
    3380             :             /* Collect statistics about aggregates for estimating costs. */
    3381         196 :             if (root->parse->hasAggs)
    3382             :             {
    3383         188 :                 get_agg_clause_costs(root, AGGSPLIT_SIMPLE, &aggcosts);
    3384             :             }
    3385             : 
    3386             :             /* Get number of grouping columns and possible number of groups */
    3387         196 :             numGroupCols = list_length(root->processed_groupClause);
    3388         196 :             numGroups = estimate_num_groups(root,
    3389             :                                             get_sortgrouplist_exprs(root->processed_groupClause,
    3390             :                                                                     fpinfo->grouped_tlist),
    3391             :                                             input_rows, NULL, NULL);
    3392             : 
    3393             :             /*
    3394             :              * Get the retrieved_rows and rows estimates.  If there are HAVING
    3395             :              * quals, account for their selectivity.
    3396             :              */
    3397         196 :             if (root->hasHavingQual)
    3398             :             {
    3399             :                 /* Factor in the selectivity of the remotely-checked quals */
    3400             :                 retrieved_rows =
    3401          28 :                     clamp_row_est(numGroups *
    3402          28 :                                   clauselist_selectivity(root,
    3403             :                                                          fpinfo->remote_conds,
    3404             :                                                          0,
    3405             :                                                          JOIN_INNER,
    3406             :                                                          NULL));
    3407             :                 /* Factor in the selectivity of the locally-checked quals */
    3408          28 :                 rows = clamp_row_est(retrieved_rows * fpinfo->local_conds_sel);
    3409             :             }
    3410             :             else
    3411             :             {
    3412         168 :                 rows = retrieved_rows = numGroups;
    3413             :             }
    3414             : 
    3415             :             /* Use width estimate made by the core code. */
    3416         196 :             width = foreignrel->reltarget->width;
    3417             : 
    3418             :             /*-----
    3419             :              * Startup cost includes:
    3420             :              *    1. Startup cost for underneath input relation, adjusted for
    3421             :              *       tlist replacement by apply_scanjoin_target_to_paths()
    3422             :              *    2. Cost of performing aggregation, per cost_agg()
    3423             :              *-----
    3424             :              */
    3425         196 :             startup_cost = ofpinfo->rel_startup_cost;
    3426         196 :             startup_cost += outerrel->reltarget->cost.startup;
    3427         196 :             startup_cost += aggcosts.transCost.startup;
    3428         196 :             startup_cost += aggcosts.transCost.per_tuple * input_rows;
    3429         196 :             startup_cost += aggcosts.finalCost.startup;
    3430         196 :             startup_cost += (cpu_operator_cost * numGroupCols) * input_rows;
    3431             : 
    3432             :             /*-----
    3433             :              * Run time cost includes:
    3434             :              *    1. Run time cost of underneath input relation, adjusted for
    3435             :              *       tlist replacement by apply_scanjoin_target_to_paths()
    3436             :              *    2. Run time cost of performing aggregation, per cost_agg()
    3437             :              *-----
    3438             :              */
    3439         196 :             run_cost = ofpinfo->rel_total_cost - ofpinfo->rel_startup_cost;
    3440         196 :             run_cost += outerrel->reltarget->cost.per_tuple * input_rows;
    3441         196 :             run_cost += aggcosts.finalCost.per_tuple * numGroups;
    3442         196 :             run_cost += cpu_tuple_cost * numGroups;
    3443             : 
    3444             :             /* Account for the eval cost of HAVING quals, if any */
    3445         196 :             if (root->hasHavingQual)
    3446             :             {
    3447             :                 QualCost    remote_cost;
    3448             : 
    3449             :                 /* Add in the eval cost of the remotely-checked quals */
    3450          28 :                 cost_qual_eval(&remote_cost, fpinfo->remote_conds, root);
    3451          28 :                 startup_cost += remote_cost.startup;
    3452          28 :                 run_cost += remote_cost.per_tuple * numGroups;
    3453             :                 /* Add in the eval cost of the locally-checked quals */
    3454          28 :                 startup_cost += fpinfo->local_conds_cost.startup;
    3455          28 :                 run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
    3456             :             }
    3457             : 
    3458             :             /* Add in tlist eval cost for each output row */
    3459         196 :             startup_cost += foreignrel->reltarget->cost.startup;
    3460         196 :             run_cost += foreignrel->reltarget->cost.per_tuple * rows;
    3461             :         }
    3462             :         else
    3463             :         {
    3464             :             Cost        cpu_per_tuple;
    3465             : 
    3466             :             /* Use rows/width estimates made by set_baserel_size_estimates. */
    3467        1736 :             rows = foreignrel->rows;
    3468        1736 :             width = foreignrel->reltarget->width;
    3469             : 
    3470             :             /*
    3471             :              * Back into an estimate of the number of retrieved rows.  Just in
    3472             :              * case this is nuts, clamp to at most foreignrel->tuples.
    3473             :              */
    3474        1736 :             retrieved_rows = clamp_row_est(rows / fpinfo->local_conds_sel);
    3475        1736 :             retrieved_rows = Min(retrieved_rows, foreignrel->tuples);
    3476             : 
    3477             :             /*
    3478             :              * Cost as though this were a seqscan, which is pessimistic.  We
    3479             :              * effectively imagine the local_conds are being evaluated
    3480             :              * remotely, too.
    3481             :              */
    3482        1736 :             startup_cost = 0;
    3483        1736 :             run_cost = 0;
    3484        1736 :             run_cost += seq_page_cost * foreignrel->pages;
    3485             : 
    3486        1736 :             startup_cost += foreignrel->baserestrictcost.startup;
    3487        1736 :             cpu_per_tuple = cpu_tuple_cost + foreignrel->baserestrictcost.per_tuple;
    3488        1736 :             run_cost += cpu_per_tuple * foreignrel->tuples;
    3489             : 
    3490             :             /* Add in tlist eval cost for each output row */
    3491        1736 :             startup_cost += foreignrel->reltarget->cost.startup;
    3492        1736 :             run_cost += foreignrel->reltarget->cost.per_tuple * rows;
    3493             :         }
    3494             : 
    3495             :         /*
    3496             :          * Without remote estimates, we have no real way to estimate the cost
    3497             :          * of generating sorted output.  It could be free if the query plan
    3498             :          * the remote side would have chosen generates properly-sorted output
    3499             :          * anyway, but in most cases it will cost something.  Estimate a value
    3500             :          * high enough that we won't pick the sorted path when the ordering
    3501             :          * isn't locally useful, but low enough that we'll err on the side of
    3502             :          * pushing down the ORDER BY clause when it's useful to do so.
    3503             :          */
    3504        2776 :         if (pathkeys != NIL)
    3505             :         {
    3506         508 :             if (IS_UPPER_REL(foreignrel))
    3507             :             {
    3508             :                 Assert(foreignrel->reloptkind == RELOPT_UPPER_REL &&
    3509             :                        fpinfo->stage == UPPERREL_GROUP_AGG);
    3510             : 
    3511             :                 /*
    3512             :                  * We can only get here when this function is called from
    3513             :                  * add_foreign_ordered_paths() or add_foreign_final_paths();
    3514             :                  * in which cases, the passed-in fpextra should not be NULL.
    3515             :                  */
    3516             :                 Assert(fpextra);
    3517          60 :                 adjust_foreign_grouping_path_cost(root, pathkeys,
    3518             :                                                   retrieved_rows, width,
    3519             :                                                   fpextra->limit_tuples,
    3520             :                                                   &disabled_nodes,
    3521             :                                                   &startup_cost, &run_cost);
    3522             :             }
    3523             :             else
    3524             :             {
    3525         448 :                 startup_cost *= DEFAULT_FDW_SORT_MULTIPLIER;
    3526         448 :                 run_cost *= DEFAULT_FDW_SORT_MULTIPLIER;
    3527             :             }
    3528             :         }
    3529             : 
    3530        2776 :         total_cost = startup_cost + run_cost;
    3531             : 
    3532             :         /* Adjust the cost estimates if we have LIMIT */
    3533        2776 :         if (fpextra && fpextra->has_limit)
    3534             :         {
    3535         184 :             adjust_limit_rows_costs(&rows, &startup_cost, &total_cost,
    3536             :                                     fpextra->offset_est, fpextra->count_est);
    3537         184 :             retrieved_rows = rows;
    3538             :         }
    3539             :     }
    3540             : 
    3541             :     /*
    3542             :      * If this includes the final sort step, the given target, which will be
    3543             :      * applied to the resulting path, might have different expressions from
    3544             :      * the foreignrel's reltarget (see make_sort_input_target()); adjust tlist
    3545             :      * eval costs.
    3546             :      */
    3547        5342 :     if (fpextra && fpextra->has_final_sort &&
    3548         218 :         fpextra->target != foreignrel->reltarget)
    3549             :     {
    3550          12 :         QualCost    oldcost = foreignrel->reltarget->cost;
    3551          12 :         QualCost    newcost = fpextra->target->cost;
    3552             : 
    3553          12 :         startup_cost += newcost.startup - oldcost.startup;
    3554          12 :         total_cost += newcost.startup - oldcost.startup;
    3555          12 :         total_cost += (newcost.per_tuple - oldcost.per_tuple) * rows;
    3556             :     }
    3557             : 
    3558             :     /*
    3559             :      * Cache the retrieved rows and cost estimates for scans, joins, or
    3560             :      * groupings without any parameterization, pathkeys, or additional
    3561             :      * post-scan/join-processing steps, before adding the costs for
    3562             :      * transferring data from the foreign server.  These estimates are useful
    3563             :      * for costing remote joins involving this relation or costing other
    3564             :      * remote operations on this relation such as remote sorts and remote
    3565             :      * LIMIT restrictions, when the costs can not be obtained from the foreign
    3566             :      * server.  This function will be called at least once for every foreign
    3567             :      * relation without any parameterization, pathkeys, or additional
    3568             :      * post-scan/join-processing steps.
    3569             :      */
    3570        5342 :     if (pathkeys == NIL && param_join_conds == NIL && fpextra == NULL)
    3571             :     {
    3572        3252 :         fpinfo->retrieved_rows = retrieved_rows;
    3573        3252 :         fpinfo->rel_startup_cost = startup_cost;
    3574        3252 :         fpinfo->rel_total_cost = total_cost;
    3575             :     }
    3576             : 
    3577             :     /*
    3578             :      * Add some additional cost factors to account for connection overhead
    3579             :      * (fdw_startup_cost), transferring data across the network
    3580             :      * (fdw_tuple_cost per retrieved row), and local manipulation of the data
    3581             :      * (cpu_tuple_cost per retrieved row).
    3582             :      */
    3583        5342 :     startup_cost += fpinfo->fdw_startup_cost;
    3584        5342 :     total_cost += fpinfo->fdw_startup_cost;
    3585        5342 :     total_cost += fpinfo->fdw_tuple_cost * retrieved_rows;
    3586        5342 :     total_cost += cpu_tuple_cost * retrieved_rows;
    3587             : 
    3588             :     /*
    3589             :      * If we have LIMIT, we should prefer performing the restriction remotely
    3590             :      * rather than locally, as the former avoids extra row fetches from the
    3591             :      * remote that the latter might cause.  But since the core code doesn't
    3592             :      * account for such fetches when estimating the costs of the local
    3593             :      * restriction (see create_limit_path()), there would be no difference
    3594             :      * between the costs of the local restriction and the costs of the remote
    3595             :      * restriction estimated above if we don't use remote estimates (except
    3596             :      * for the case where the foreignrel is a grouping relation, the given
    3597             :      * pathkeys is not NIL, and the effects of a bounded sort for that rel is
    3598             :      * accounted for in costing the remote restriction).  Tweak the costs of
    3599             :      * the remote restriction to ensure we'll prefer it if LIMIT is a useful
    3600             :      * one.
    3601             :      */
    3602        5342 :     if (!fpinfo->use_remote_estimate &&
    3603         244 :         fpextra && fpextra->has_limit &&
    3604         184 :         fpextra->limit_tuples > 0 &&
    3605         184 :         fpextra->limit_tuples < fpinfo->rows)
    3606             :     {
    3607             :         Assert(fpinfo->rows > 0);
    3608         172 :         total_cost -= (total_cost - startup_cost) * 0.05 *
    3609         172 :             (fpinfo->rows - fpextra->limit_tuples) / fpinfo->rows;
    3610             :     }
    3611             : 
    3612             :     /* Return results. */
    3613        5342 :     *p_rows = rows;
    3614        5342 :     *p_width = width;
    3615        5342 :     *p_disabled_nodes = disabled_nodes;
    3616        5342 :     *p_startup_cost = startup_cost;
    3617        5342 :     *p_total_cost = total_cost;
    3618        5342 : }
    3619             : 
    3620             : /*
    3621             :  * Estimate costs of executing a SQL statement remotely.
    3622             :  * The given "sql" must be an EXPLAIN command.
    3623             :  */
    3624             : static void
    3625        2566 : get_remote_estimate(const char *sql, PGconn *conn,
    3626             :                     double *rows, int *width,
    3627             :                     Cost *startup_cost, Cost *total_cost)
    3628             : {
    3629        2566 :     PGresult   *volatile res = NULL;
    3630             : 
    3631             :     /* PGresult must be released before leaving this function. */
    3632        2566 :     PG_TRY();
    3633             :     {
    3634             :         char       *line;
    3635             :         char       *p;
    3636             :         int         n;
    3637             : 
    3638             :         /*
    3639             :          * Execute EXPLAIN remotely.
    3640             :          */
    3641        2566 :         res = pgfdw_exec_query(conn, sql, NULL);
    3642        2566 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
    3643           0 :             pgfdw_report_error(ERROR, res, conn, false, sql);
    3644             : 
    3645             :         /*
    3646             :          * Extract cost numbers for topmost plan node.  Note we search for a
    3647             :          * left paren from the end of the line to avoid being confused by
    3648             :          * other uses of parentheses.
    3649             :          */
    3650        2566 :         line = PQgetvalue(res, 0, 0);
    3651        2566 :         p = strrchr(line, '(');
    3652        2566 :         if (p == NULL)
    3653           0 :             elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
    3654        2566 :         n = sscanf(p, "(cost=%lf..%lf rows=%lf width=%d)",
    3655             :                    startup_cost, total_cost, rows, width);
    3656        2566 :         if (n != 4)
    3657           0 :             elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
    3658             :     }
    3659           0 :     PG_FINALLY();
    3660             :     {
    3661        2566 :         PQclear(res);
    3662             :     }
    3663        2566 :     PG_END_TRY();
    3664        2566 : }
    3665             : 
    3666             : /*
    3667             :  * Adjust the cost estimates of a foreign grouping path to include the cost of
    3668             :  * generating properly-sorted output.
    3669             :  */
    3670             : static void
    3671          60 : adjust_foreign_grouping_path_cost(PlannerInfo *root,
    3672             :                                   List *pathkeys,
    3673             :                                   double retrieved_rows,
    3674             :                                   double width,
    3675             :                                   double limit_tuples,
    3676             :                                   int *p_disabled_nodes,
    3677             :                                   Cost *p_startup_cost,
    3678             :                                   Cost *p_run_cost)
    3679             : {
    3680             :     /*
    3681             :      * If the GROUP BY clause isn't sort-able, the plan chosen by the remote
    3682             :      * side is unlikely to generate properly-sorted output, so it would need
    3683             :      * an explicit sort; adjust the given costs with cost_sort().  Likewise,
    3684             :      * if the GROUP BY clause is sort-able but isn't a superset of the given
    3685             :      * pathkeys, adjust the costs with that function.  Otherwise, adjust the
    3686             :      * costs by applying the same heuristic as for the scan or join case.
    3687             :      */
    3688          60 :     if (!grouping_is_sortable(root->processed_groupClause) ||
    3689          60 :         !pathkeys_contained_in(pathkeys, root->group_pathkeys))
    3690          44 :     {
    3691             :         Path        sort_path;  /* dummy for result of cost_sort */
    3692             : 
    3693          44 :         cost_sort(&sort_path,
    3694             :                   root,
    3695             :                   pathkeys,
    3696             :                   0,
    3697          44 :                   *p_startup_cost + *p_run_cost,
    3698             :                   retrieved_rows,
    3699             :                   width,
    3700             :                   0.0,
    3701             :                   work_mem,
    3702             :                   limit_tuples);
    3703             : 
    3704          44 :         *p_startup_cost = sort_path.startup_cost;
    3705          44 :         *p_run_cost = sort_path.total_cost - sort_path.startup_cost;
    3706             :     }
    3707             :     else
    3708             :     {
    3709             :         /*
    3710             :          * The default extra cost seems too large for foreign-grouping cases;
    3711             :          * add 1/4th of that default.
    3712             :          */
    3713          16 :         double      sort_multiplier = 1.0 + (DEFAULT_FDW_SORT_MULTIPLIER
    3714             :                                              - 1.0) * 0.25;
    3715             : 
    3716          16 :         *p_startup_cost *= sort_multiplier;
    3717          16 :         *p_run_cost *= sort_multiplier;
    3718             :     }
    3719          60 : }
    3720             : 
    3721             : /*
    3722             :  * Detect whether we want to process an EquivalenceClass member.
    3723             :  *
    3724             :  * This is a callback for use by generate_implied_equalities_for_column.
    3725             :  */
    3726             : static bool
    3727         596 : ec_member_matches_foreign(PlannerInfo *root, RelOptInfo *rel,
    3728             :                           EquivalenceClass *ec, EquivalenceMember *em,
    3729             :                           void *arg)
    3730             : {
    3731         596 :     ec_member_foreign_arg *state = (ec_member_foreign_arg *) arg;
    3732         596 :     Expr       *expr = em->em_expr;
    3733             : 
    3734             :     /*
    3735             :      * If we've identified what we're processing in the current scan, we only
    3736             :      * want to match that expression.
    3737             :      */
    3738         596 :     if (state->current != NULL)
    3739           0 :         return equal(expr, state->current);
    3740             : 
    3741             :     /*
    3742             :      * Otherwise, ignore anything we've already processed.
    3743             :      */
    3744         596 :     if (list_member(state->already_used, expr))
    3745         314 :         return false;
    3746             : 
    3747             :     /* This is the new target to process. */
    3748         282 :     state->current = expr;
    3749         282 :     return true;
    3750             : }
    3751             : 
    3752             : /*
    3753             :  * Create cursor for node's query with current parameter values.
    3754             :  */
    3755             : static void
    3756        1644 : create_cursor(ForeignScanState *node)
    3757             : {
    3758        1644 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    3759        1644 :     ExprContext *econtext = node->ss.ps.ps_ExprContext;
    3760        1644 :     int         numParams = fsstate->numParams;
    3761        1644 :     const char **values = fsstate->param_values;
    3762        1644 :     PGconn     *conn = fsstate->conn;
    3763             :     StringInfoData buf;
    3764             :     PGresult   *res;
    3765             : 
    3766             :     /* First, process a pending asynchronous request, if any. */
    3767        1644 :     if (fsstate->conn_state->pendingAreq)
    3768           2 :         process_pending_request(fsstate->conn_state->pendingAreq);
    3769             : 
    3770             :     /*
    3771             :      * Construct array of query parameter values in text format.  We do the
    3772             :      * conversions in the short-lived per-tuple context, so as not to cause a
    3773             :      * memory leak over repeated scans.
    3774             :      */
    3775        1644 :     if (numParams > 0)
    3776             :     {
    3777             :         MemoryContext oldcontext;
    3778             : 
    3779         692 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
    3780             : 
    3781         692 :         process_query_params(econtext,
    3782             :                              fsstate->param_flinfo,
    3783             :                              fsstate->param_exprs,
    3784             :                              values);
    3785             : 
    3786         692 :         MemoryContextSwitchTo(oldcontext);
    3787             :     }
    3788             : 
    3789             :     /* Construct the DECLARE CURSOR command */
    3790        1644 :     initStringInfo(&buf);
    3791        1644 :     appendStringInfo(&buf, "DECLARE c%u CURSOR FOR\n%s",
    3792             :                      fsstate->cursor_number, fsstate->query);
    3793             : 
    3794             :     /*
    3795             :      * Notice that we pass NULL for paramTypes, thus forcing the remote server
    3796             :      * to infer types for all parameters.  Since we explicitly cast every
    3797             :      * parameter (see deparse.c), the "inference" is trivial and will produce
    3798             :      * the desired result.  This allows us to avoid assuming that the remote
    3799             :      * server has the same OIDs we do for the parameters' types.
    3800             :      */
    3801        1644 :     if (!PQsendQueryParams(conn, buf.data, numParams,
    3802             :                            NULL, values, NULL, NULL, 0))
    3803           0 :         pgfdw_report_error(ERROR, NULL, conn, false, buf.data);
    3804             : 
    3805             :     /*
    3806             :      * Get the result, and check for success.
    3807             :      *
    3808             :      * We don't use a PG_TRY block here, so be careful not to throw error
    3809             :      * without releasing the PGresult.
    3810             :      */
    3811        1644 :     res = pgfdw_get_result(conn);
    3812        1642 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    3813           6 :         pgfdw_report_error(ERROR, res, conn, true, fsstate->query);
    3814        1636 :     PQclear(res);
    3815             : 
    3816             :     /* Mark the cursor as created, and show no tuples have been retrieved */
    3817        1636 :     fsstate->cursor_exists = true;
    3818        1636 :     fsstate->tuples = NULL;
    3819        1636 :     fsstate->num_tuples = 0;
    3820        1636 :     fsstate->next_tuple = 0;
    3821        1636 :     fsstate->fetch_ct_2 = 0;
    3822        1636 :     fsstate->eof_reached = false;
    3823             : 
    3824             :     /* Clean up */
    3825        1636 :     pfree(buf.data);
    3826        1636 : }
    3827             : 
    3828             : /*
    3829             :  * Fetch some more rows from the node's cursor.
    3830             :  */
    3831             : static void
    3832        2978 : fetch_more_data(ForeignScanState *node)
    3833             : {
    3834        2978 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    3835        2978 :     PGresult   *volatile res = NULL;
    3836             :     MemoryContext oldcontext;
    3837             : 
    3838             :     /*
    3839             :      * We'll store the tuples in the batch_cxt.  First, flush the previous
    3840             :      * batch.
    3841             :      */
    3842        2978 :     fsstate->tuples = NULL;
    3843        2978 :     MemoryContextReset(fsstate->batch_cxt);
    3844        2978 :     oldcontext = MemoryContextSwitchTo(fsstate->batch_cxt);
    3845             : 
    3846             :     /* PGresult must be released before leaving this function. */
    3847        2978 :     PG_TRY();
    3848             :     {
    3849        2978 :         PGconn     *conn = fsstate->conn;
    3850             :         int         numrows;
    3851             :         int         i;
    3852             : 
    3853        2978 :         if (fsstate->async_capable)
    3854             :         {
    3855             :             Assert(fsstate->conn_state->pendingAreq);
    3856             : 
    3857             :             /*
    3858             :              * The query was already sent by an earlier call to
    3859             :              * fetch_more_data_begin.  So now we just fetch the result.
    3860             :              */
    3861         316 :             res = pgfdw_get_result(conn);
    3862             :             /* On error, report the original query, not the FETCH. */
    3863         316 :             if (PQresultStatus(res) != PGRES_TUPLES_OK)
    3864           0 :                 pgfdw_report_error(ERROR, res, conn, false, fsstate->query);
    3865             : 
    3866             :             /* Reset per-connection state */
    3867         316 :             fsstate->conn_state->pendingAreq = NULL;
    3868             :         }
    3869             :         else
    3870             :         {
    3871             :             char        sql[64];
    3872             : 
    3873             :             /* This is a regular synchronous fetch. */
    3874        2662 :             snprintf(sql, sizeof(sql), "FETCH %d FROM c%u",
    3875             :                      fsstate->fetch_size, fsstate->cursor_number);
    3876             : 
    3877        2662 :             res = pgfdw_exec_query(conn, sql, fsstate->conn_state);
    3878             :             /* On error, report the original query, not the FETCH. */
    3879        2662 :             if (PQresultStatus(res) != PGRES_TUPLES_OK)
    3880           2 :                 pgfdw_report_error(ERROR, res, conn, false, fsstate->query);
    3881             :         }
    3882             : 
    3883             :         /* Convert the data into HeapTuples */
    3884        2976 :         numrows = PQntuples(res);
    3885        2976 :         fsstate->tuples = (HeapTuple *) palloc0(numrows * sizeof(HeapTuple));
    3886        2976 :         fsstate->num_tuples = numrows;
    3887        2976 :         fsstate->next_tuple = 0;
    3888             : 
    3889      145414 :         for (i = 0; i < numrows; i++)
    3890             :         {
    3891             :             Assert(IsA(node->ss.ps.plan, ForeignScan));
    3892             : 
    3893      284884 :             fsstate->tuples[i] =
    3894      142446 :                 make_tuple_from_result_row(res, i,
    3895             :                                            fsstate->rel,
    3896             :                                            fsstate->attinmeta,
    3897             :                                            fsstate->retrieved_attrs,
    3898             :                                            node,
    3899             :                                            fsstate->temp_cxt);
    3900             :         }
    3901             : 
    3902             :         /* Update fetch_ct_2 */
    3903        2968 :         if (fsstate->fetch_ct_2 < 2)
    3904        1864 :             fsstate->fetch_ct_2++;
    3905             : 
    3906             :         /* Must be EOF if we didn't get as many tuples as we asked for. */
    3907        2968 :         fsstate->eof_reached = (numrows < fsstate->fetch_size);
    3908             :     }
    3909          10 :     PG_FINALLY();
    3910             :     {
    3911        2978 :         PQclear(res);
    3912             :     }
    3913        2978 :     PG_END_TRY();
    3914             : 
    3915        2968 :     MemoryContextSwitchTo(oldcontext);
    3916        2968 : }
    3917             : 
    3918             : /*
    3919             :  * Force assorted GUC parameters to settings that ensure that we'll output
    3920             :  * data values in a form that is unambiguous to the remote server.
    3921             :  *
    3922             :  * This is rather expensive and annoying to do once per row, but there's
    3923             :  * little choice if we want to be sure values are transmitted accurately;
    3924             :  * we can't leave the settings in place between rows for fear of affecting
    3925             :  * user-visible computations.
    3926             :  *
    3927             :  * We use the equivalent of a function SET option to allow the settings to
    3928             :  * persist only until the caller calls reset_transmission_modes().  If an
    3929             :  * error is thrown in between, guc.c will take care of undoing the settings.
    3930             :  *
    3931             :  * The return value is the nestlevel that must be passed to
    3932             :  * reset_transmission_modes() to undo things.
    3933             :  */
    3934             : int
    3935        8382 : set_transmission_modes(void)
    3936             : {
    3937        8382 :     int         nestlevel = NewGUCNestLevel();
    3938             : 
    3939             :     /*
    3940             :      * The values set here should match what pg_dump does.  See also
    3941             :      * configure_remote_session in connection.c.
    3942             :      */
    3943        8382 :     if (DateStyle != USE_ISO_DATES)
    3944        8378 :         (void) set_config_option("datestyle", "ISO",
    3945             :                                  PGC_USERSET, PGC_S_SESSION,
    3946             :                                  GUC_ACTION_SAVE, true, 0, false);
    3947        8382 :     if (IntervalStyle != INTSTYLE_POSTGRES)
    3948        8378 :         (void) set_config_option("intervalstyle", "postgres",
    3949             :                                  PGC_USERSET, PGC_S_SESSION,
    3950             :                                  GUC_ACTION_SAVE, true, 0, false);
    3951        8382 :     if (extra_float_digits < 3)
    3952        8378 :         (void) set_config_option("extra_float_digits", "3",
    3953             :                                  PGC_USERSET, PGC_S_SESSION,
    3954             :                                  GUC_ACTION_SAVE, true, 0, false);
    3955             : 
    3956             :     /*
    3957             :      * In addition force restrictive search_path, in case there are any
    3958             :      * regproc or similar constants to be printed.
    3959             :      */
    3960        8382 :     (void) set_config_option("search_path", "pg_catalog",
    3961             :                              PGC_USERSET, PGC_S_SESSION,
    3962             :                              GUC_ACTION_SAVE, true, 0, false);
    3963             : 
    3964        8382 :     return nestlevel;
    3965             : }
    3966             : 
    3967             : /*
    3968             :  * Undo the effects of set_transmission_modes().
    3969             :  */
    3970             : void
    3971        8382 : reset_transmission_modes(int nestlevel)
    3972             : {
    3973        8382 :     AtEOXact_GUC(true, nestlevel);
    3974        8382 : }
    3975             : 
    3976             : /*
    3977             :  * Utility routine to close a cursor.
    3978             :  */
    3979             : static void
    3980         980 : close_cursor(PGconn *conn, unsigned int cursor_number,
    3981             :              PgFdwConnState *conn_state)
    3982             : {
    3983             :     char        sql[64];
    3984             :     PGresult   *res;
    3985             : 
    3986         980 :     snprintf(sql, sizeof(sql), "CLOSE c%u", cursor_number);
    3987             : 
    3988             :     /*
    3989             :      * We don't use a PG_TRY block here, so be careful not to throw error
    3990             :      * without releasing the PGresult.
    3991             :      */
    3992         980 :     res = pgfdw_exec_query(conn, sql, conn_state);
    3993         980 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    3994           0 :         pgfdw_report_error(ERROR, res, conn, true, sql);
    3995         980 :     PQclear(res);
    3996         980 : }
    3997             : 
    3998             : /*
    3999             :  * create_foreign_modify
    4000             :  *      Construct an execution state of a foreign insert/update/delete
    4001             :  *      operation
    4002             :  */
    4003             : static PgFdwModifyState *
    4004         346 : create_foreign_modify(EState *estate,
    4005             :                       RangeTblEntry *rte,
    4006             :                       ResultRelInfo *resultRelInfo,
    4007             :                       CmdType operation,
    4008             :                       Plan *subplan,
    4009             :                       char *query,
    4010             :                       List *target_attrs,
    4011             :                       int values_end,
    4012             :                       bool has_returning,
    4013             :                       List *retrieved_attrs)
    4014             : {
    4015             :     PgFdwModifyState *fmstate;
    4016         346 :     Relation    rel = resultRelInfo->ri_RelationDesc;
    4017         346 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    4018             :     Oid         userid;
    4019             :     ForeignTable *table;
    4020             :     UserMapping *user;
    4021             :     AttrNumber  n_params;
    4022             :     Oid         typefnoid;
    4023             :     bool        isvarlena;
    4024             :     ListCell   *lc;
    4025             : 
    4026             :     /* Begin constructing PgFdwModifyState. */
    4027         346 :     fmstate = (PgFdwModifyState *) palloc0(sizeof(PgFdwModifyState));
    4028         346 :     fmstate->rel = rel;
    4029             : 
    4030             :     /* Identify which user to do the remote access as. */
    4031         346 :     userid = ExecGetResultRelCheckAsUser(resultRelInfo, estate);
    4032             : 
    4033             :     /* Get info about foreign table. */
    4034         346 :     table = GetForeignTable(RelationGetRelid(rel));
    4035         346 :     user = GetUserMapping(userid, table->serverid);
    4036             : 
    4037             :     /* Open connection; report that we'll create a prepared statement. */
    4038         346 :     fmstate->conn = GetConnection(user, true, &fmstate->conn_state);
    4039         346 :     fmstate->p_name = NULL;      /* prepared statement not made yet */
    4040             : 
    4041             :     /* Set up remote query information. */
    4042         346 :     fmstate->query = query;
    4043         346 :     if (operation == CMD_INSERT)
    4044             :     {
    4045         256 :         fmstate->query = pstrdup(fmstate->query);
    4046         256 :         fmstate->orig_query = pstrdup(fmstate->query);
    4047             :     }
    4048         346 :     fmstate->target_attrs = target_attrs;
    4049         346 :     fmstate->values_end = values_end;
    4050         346 :     fmstate->has_returning = has_returning;
    4051         346 :     fmstate->retrieved_attrs = retrieved_attrs;
    4052             : 
    4053             :     /* Create context for per-tuple temp workspace. */
    4054         346 :     fmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
    4055             :                                               "postgres_fdw temporary data",
    4056             :                                               ALLOCSET_SMALL_SIZES);
    4057             : 
    4058             :     /* Prepare for input conversion of RETURNING results. */
    4059         346 :     if (fmstate->has_returning)
    4060         124 :         fmstate->attinmeta = TupleDescGetAttInMetadata(tupdesc);
    4061             : 
    4062             :     /* Prepare for output conversion of parameters used in prepared stmt. */
    4063         346 :     n_params = list_length(fmstate->target_attrs) + 1;
    4064         346 :     fmstate->p_flinfo = (FmgrInfo *) palloc0(sizeof(FmgrInfo) * n_params);
    4065         346 :     fmstate->p_nums = 0;
    4066             : 
    4067         346 :     if (operation == CMD_UPDATE || operation == CMD_DELETE)
    4068             :     {
    4069             :         Assert(subplan != NULL);
    4070             : 
    4071             :         /* Find the ctid resjunk column in the subplan's result */
    4072          90 :         fmstate->ctidAttno = ExecFindJunkAttributeInTlist(subplan->targetlist,
    4073             :                                                           "ctid");
    4074          90 :         if (!AttributeNumberIsValid(fmstate->ctidAttno))
    4075           0 :             elog(ERROR, "could not find junk ctid column");
    4076             : 
    4077             :         /* First transmittable parameter will be ctid */
    4078          90 :         getTypeOutputInfo(TIDOID, &typefnoid, &isvarlena);
    4079          90 :         fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
    4080          90 :         fmstate->p_nums++;
    4081             :     }
    4082             : 
    4083         346 :     if (operation == CMD_INSERT || operation == CMD_UPDATE)
    4084             :     {
    4085             :         /* Set up for remaining transmittable parameters */
    4086        1098 :         foreach(lc, fmstate->target_attrs)
    4087             :         {
    4088         774 :             int         attnum = lfirst_int(lc);
    4089         774 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
    4090             : 
    4091             :             Assert(!attr->attisdropped);
    4092             : 
    4093             :             /* Ignore generated columns; they are set to DEFAULT */
    4094         774 :             if (attr->attgenerated)
    4095          16 :                 continue;
    4096         758 :             getTypeOutputInfo(attr->atttypid, &typefnoid, &isvarlena);
    4097         758 :             fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
    4098         758 :             fmstate->p_nums++;
    4099             :         }
    4100             :     }
    4101             : 
    4102             :     Assert(fmstate->p_nums <= n_params);
    4103             : 
    4104             :     /* Set batch_size from foreign server/table options. */
    4105         346 :     if (operation == CMD_INSERT)
    4106         256 :         fmstate->batch_size = get_batch_size_option(rel);
    4107             : 
    4108         346 :     fmstate->num_slots = 1;
    4109             : 
    4110             :     /* Initialize auxiliary state */
    4111         346 :     fmstate->aux_fmstate = NULL;
    4112             : 
    4113         346 :     return fmstate;
    4114             : }
    4115             : 
    4116             : /*
    4117             :  * execute_foreign_modify
    4118             :  *      Perform foreign-table modification as required, and fetch RETURNING
    4119             :  *      result if any.  (This is the shared guts of postgresExecForeignInsert,
    4120             :  *      postgresExecForeignBatchInsert, postgresExecForeignUpdate, and
    4121             :  *      postgresExecForeignDelete.)
    4122             :  */
    4123             : static TupleTableSlot **
    4124        2086 : execute_foreign_modify(EState *estate,
    4125             :                        ResultRelInfo *resultRelInfo,
    4126             :                        CmdType operation,
    4127             :                        TupleTableSlot **slots,
    4128             :                        TupleTableSlot **planSlots,
    4129             :                        int *numSlots)
    4130             : {
    4131        2086 :     PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
    4132        2086 :     ItemPointer ctid = NULL;
    4133             :     const char **p_values;
    4134             :     PGresult   *res;
    4135             :     int         n_rows;
    4136             :     StringInfoData sql;
    4137             : 
    4138             :     /* The operation should be INSERT, UPDATE, or DELETE */
    4139             :     Assert(operation == CMD_INSERT ||
    4140             :            operation == CMD_UPDATE ||
    4141             :            operation == CMD_DELETE);
    4142             : 
    4143             :     /* First, process a pending asynchronous request, if any. */
    4144        2086 :     if (fmstate->conn_state->pendingAreq)
    4145           2 :         process_pending_request(fmstate->conn_state->pendingAreq);
    4146             : 
    4147             :     /*
    4148             :      * If the existing query was deparsed and prepared for a different number
    4149             :      * of rows, rebuild it for the proper number.
    4150             :      */
    4151        2086 :     if (operation == CMD_INSERT && fmstate->num_slots != *numSlots)
    4152             :     {
    4153             :         /* Destroy the prepared statement created previously */
    4154          52 :         if (fmstate->p_name)
    4155          22 :             deallocate_query(fmstate);
    4156             : 
    4157             :         /* Build INSERT string with numSlots records in its VALUES clause. */
    4158          52 :         initStringInfo(&sql);
    4159          52 :         rebuildInsertSql(&sql, fmstate->rel,
    4160             :                          fmstate->orig_query, fmstate->target_attrs,
    4161             :                          fmstate->values_end, fmstate->p_nums,
    4162          52 :                          *numSlots - 1);
    4163          52 :         pfree(fmstate->query);
    4164          52 :         fmstate->query = sql.data;
    4165          52 :         fmstate->num_slots = *numSlots;
    4166             :     }
    4167             : 
    4168             :     /* Set up the prepared statement on the remote server, if we didn't yet */
    4169        2086 :     if (!fmstate->p_name)
    4170         356 :         prepare_foreign_modify(fmstate);
    4171             : 
    4172             :     /*
    4173             :      * For UPDATE/DELETE, get the ctid that was passed up as a resjunk column
    4174             :      */
    4175        2086 :     if (operation == CMD_UPDATE || operation == CMD_DELETE)
    4176             :     {
    4177             :         Datum       datum;
    4178             :         bool        isNull;
    4179             : 
    4180         228 :         datum = ExecGetJunkAttribute(planSlots[0],
    4181         228 :                                      fmstate->ctidAttno,
    4182             :                                      &isNull);
    4183             :         /* shouldn't ever get a null result... */
    4184         228 :         if (isNull)
    4185           0 :             elog(ERROR, "ctid is NULL");
    4186         228 :         ctid = (ItemPointer) DatumGetPointer(datum);
    4187             :     }
    4188             : 
    4189             :     /* Convert parameters needed by prepared statement to text form */
    4190        2086 :     p_values = convert_prep_stmt_params(fmstate, ctid, slots, *numSlots);
    4191             : 
    4192             :     /*
    4193             :      * Execute the prepared statement.
    4194             :      */
    4195        2086 :     if (!PQsendQueryPrepared(fmstate->conn,
    4196        2086 :                              fmstate->p_name,
    4197        2086 :                              fmstate->p_nums * (*numSlots),
    4198             :                              p_values,
    4199             :                              NULL,
    4200             :                              NULL,
    4201             :                              0))
    4202           0 :         pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
    4203             : 
    4204             :     /*
    4205             :      * Get the result, and check for success.
    4206             :      *
    4207             :      * We don't use a PG_TRY block here, so be careful not to throw error
    4208             :      * without releasing the PGresult.
    4209             :      */
    4210        2086 :     res = pgfdw_get_result(fmstate->conn);
    4211        4172 :     if (PQresultStatus(res) !=
    4212        2086 :         (fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
    4213          10 :         pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
    4214             : 
    4215             :     /* Check number of rows affected, and fetch RETURNING tuple if any */
    4216        2076 :     if (fmstate->has_returning)
    4217             :     {
    4218             :         Assert(*numSlots == 1);
    4219         216 :         n_rows = PQntuples(res);
    4220         216 :         if (n_rows > 0)
    4221         214 :             store_returning_result(fmstate, slots[0], res);
    4222             :     }
    4223             :     else
    4224        1860 :         n_rows = atoi(PQcmdTuples(res));
    4225             : 
    4226             :     /* And clean up */
    4227        2076 :     PQclear(res);
    4228             : 
    4229        2076 :     MemoryContextReset(fmstate->temp_cxt);
    4230             : 
    4231        2076 :     *numSlots = n_rows;
    4232             : 
    4233             :     /*
    4234             :      * Return NULL if nothing was inserted/updated/deleted on the remote end
    4235             :      */
    4236        2076 :     return (n_rows > 0) ? slots : NULL;
    4237             : }
    4238             : 
    4239             : /*
    4240             :  * prepare_foreign_modify
    4241             :  *      Establish a prepared statement for execution of INSERT/UPDATE/DELETE
    4242             :  */
    4243             : static void
    4244         356 : prepare_foreign_modify(PgFdwModifyState *fmstate)
    4245             : {
    4246             :     char        prep_name[NAMEDATALEN];
    4247             :     char       *p_name;
    4248             :     PGresult   *res;
    4249             : 
    4250             :     /*
    4251             :      * The caller would already have processed a pending asynchronous request
    4252             :      * if any, so no need to do it here.
    4253             :      */
    4254             : 
    4255             :     /* Construct name we'll use for the prepared statement. */
    4256         356 :     snprintf(prep_name, sizeof(prep_name), "pgsql_fdw_prep_%u",
    4257             :              GetPrepStmtNumber(fmstate->conn));
    4258         356 :     p_name = pstrdup(prep_name);
    4259             : 
    4260             :     /*
    4261             :      * We intentionally do not specify parameter types here, but leave the
    4262             :      * remote server to derive them by default.  This avoids possible problems
    4263             :      * with the remote server using different type OIDs than we do.  All of
    4264             :      * the prepared statements we use in this module are simple enough that
    4265             :      * the remote server will make the right choices.
    4266             :      */
    4267         356 :     if (!PQsendPrepare(fmstate->conn,
    4268             :                        p_name,
    4269         356 :                        fmstate->query,
    4270             :                        0,
    4271             :                        NULL))
    4272           0 :         pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
    4273             : 
    4274             :     /*
    4275             :      * Get the result, and check for success.
    4276             :      *
    4277             :      * We don't use a PG_TRY block here, so be careful not to throw error
    4278             :      * without releasing the PGresult.
    4279             :      */
    4280         356 :     res = pgfdw_get_result(fmstate->conn);
    4281         356 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    4282           0 :         pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
    4283         356 :     PQclear(res);
    4284             : 
    4285             :     /* This action shows that the prepare has been done. */
    4286         356 :     fmstate->p_name = p_name;
    4287         356 : }
    4288             : 
    4289             : /*
    4290             :  * convert_prep_stmt_params
    4291             :  *      Create array of text strings representing parameter values
    4292             :  *
    4293             :  * tupleid is ctid to send, or NULL if none
    4294             :  * slot is slot to get remaining parameters from, or NULL if none
    4295             :  *
    4296             :  * Data is constructed in temp_cxt; caller should reset that after use.
    4297             :  */
    4298             : static const char **
    4299        2086 : convert_prep_stmt_params(PgFdwModifyState *fmstate,
    4300             :                          ItemPointer tupleid,
    4301             :                          TupleTableSlot **slots,
    4302             :                          int numSlots)
    4303             : {
    4304             :     const char **p_values;
    4305             :     int         i;
    4306             :     int         j;
    4307        2086 :     int         pindex = 0;
    4308             :     MemoryContext oldcontext;
    4309             : 
    4310        2086 :     oldcontext = MemoryContextSwitchTo(fmstate->temp_cxt);
    4311             : 
    4312        2086 :     p_values = (const char **) palloc(sizeof(char *) * fmstate->p_nums * numSlots);
    4313             : 
    4314             :     /* ctid is provided only for UPDATE/DELETE, which don't allow batching */
    4315             :     Assert(!(tupleid != NULL && numSlots > 1));
    4316             : 
    4317             :     /* 1st parameter should be ctid, if it's in use */
    4318        2086 :     if (tupleid != NULL)
    4319             :     {
    4320             :         Assert(numSlots == 1);
    4321             :         /* don't need set_transmission_modes for TID output */
    4322         228 :         p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex],
    4323             :                                               PointerGetDatum(tupleid));
    4324         228 :         pindex++;
    4325             :     }
    4326             : 
    4327             :     /* get following parameters from slots */
    4328        2086 :     if (slots != NULL && fmstate->target_attrs != NIL)
    4329             :     {
    4330        2038 :         TupleDesc   tupdesc = RelationGetDescr(fmstate->rel);
    4331             :         int         nestlevel;
    4332             :         ListCell   *lc;
    4333             : 
    4334        2038 :         nestlevel = set_transmission_modes();
    4335             : 
    4336        4320 :         for (i = 0; i < numSlots; i++)
    4337             :         {
    4338        2282 :             j = (tupleid != NULL) ? 1 : 0;
    4339        9556 :             foreach(lc, fmstate->target_attrs)
    4340             :             {
    4341        7274 :                 int         attnum = lfirst_int(lc);
    4342        7274 :                 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
    4343             :                 Datum       value;
    4344             :                 bool        isnull;
    4345             : 
    4346             :                 /* Ignore generated columns; they are set to DEFAULT */
    4347        7274 :                 if (attr->attgenerated)
    4348          28 :                     continue;
    4349        7246 :                 value = slot_getattr(slots[i], attnum, &isnull);
    4350        7246 :                 if (isnull)
    4351        1166 :                     p_values[pindex] = NULL;
    4352             :                 else
    4353        6080 :                     p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[j],
    4354             :                                                           value);
    4355        7246 :                 pindex++;
    4356        7246 :                 j++;
    4357             :             }
    4358             :         }
    4359             : 
    4360        2038 :         reset_transmission_modes(nestlevel);
    4361             :     }
    4362             : 
    4363             :     Assert(pindex == fmstate->p_nums * numSlots);
    4364             : 
    4365        2086 :     MemoryContextSwitchTo(oldcontext);
    4366             : 
    4367        2086 :     return p_values;
    4368             : }
    4369             : 
    4370             : /*
    4371             :  * store_returning_result
    4372             :  *      Store the result of a RETURNING clause
    4373             :  *
    4374             :  * On error, be sure to release the PGresult on the way out.  Callers do not
    4375             :  * have PG_TRY blocks to ensure this happens.
    4376             :  */
    4377             : static void
    4378         214 : store_returning_result(PgFdwModifyState *fmstate,
    4379             :                        TupleTableSlot *slot, PGresult *res)
    4380             : {
    4381         214 :     PG_TRY();
    4382             :     {
    4383             :         HeapTuple   newtup;
    4384             : 
    4385         214 :         newtup = make_tuple_from_result_row(res, 0,
    4386             :                                             fmstate->rel,
    4387             :                                             fmstate->attinmeta,
    4388             :                                             fmstate->retrieved_attrs,
    4389             :                                             NULL,
    4390             :                                             fmstate->temp_cxt);
    4391             : 
    4392             :         /*
    4393             :          * The returning slot will not necessarily be suitable to store
    4394             :          * heaptuples directly, so allow for conversion.
    4395             :          */
    4396         214 :         ExecForceStoreHeapTuple(newtup, slot, true);
    4397             :     }
    4398           0 :     PG_CATCH();
    4399             :     {
    4400           0 :         PQclear(res);
    4401           0 :         PG_RE_THROW();
    4402             :     }
    4403         214 :     PG_END_TRY();
    4404         214 : }
    4405             : 
    4406             : /*
    4407             :  * finish_foreign_modify
    4408             :  *      Release resources for a foreign insert/update/delete operation
    4409             :  */
    4410             : static void
    4411         318 : finish_foreign_modify(PgFdwModifyState *fmstate)
    4412             : {
    4413             :     Assert(fmstate != NULL);
    4414             : 
    4415             :     /* If we created a prepared statement, destroy it */
    4416         318 :     deallocate_query(fmstate);
    4417             : 
    4418             :     /* Release remote connection */
    4419         318 :     ReleaseConnection(fmstate->conn);
    4420         318 :     fmstate->conn = NULL;
    4421         318 : }
    4422             : 
    4423             : /*
    4424             :  * deallocate_query
    4425             :  *      Deallocate a prepared statement for a foreign insert/update/delete
    4426             :  *      operation
    4427             :  */
    4428             : static void
    4429         340 : deallocate_query(PgFdwModifyState *fmstate)
    4430             : {
    4431             :     char        sql[64];
    4432             :     PGresult   *res;
    4433             : 
    4434             :     /* do nothing if the query is not allocated */
    4435         340 :     if (!fmstate->p_name)
    4436           8 :         return;
    4437             : 
    4438         332 :     snprintf(sql, sizeof(sql), "DEALLOCATE %s", fmstate->p_name);
    4439             : 
    4440             :     /*
    4441             :      * We don't use a PG_TRY block here, so be careful not to throw error
    4442             :      * without releasing the PGresult.
    4443             :      */
    4444         332 :     res = pgfdw_exec_query(fmstate->conn, sql, fmstate->conn_state);
    4445         332 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    4446           0 :         pgfdw_report_error(ERROR, res, fmstate->conn, true, sql);
    4447         332 :     PQclear(res);
    4448         332 :     pfree(fmstate->p_name);
    4449         332 :     fmstate->p_name = NULL;
    4450             : }
    4451             : 
    4452             : /*
    4453             :  * build_remote_returning
    4454             :  *      Build a RETURNING targetlist of a remote query for performing an
    4455             :  *      UPDATE/DELETE .. RETURNING on a join directly
    4456             :  */
    4457             : static List *
    4458           8 : build_remote_returning(Index rtindex, Relation rel, List *returningList)
    4459             : {
    4460           8 :     bool        have_wholerow = false;
    4461           8 :     List       *tlist = NIL;
    4462             :     List       *vars;
    4463             :     ListCell   *lc;
    4464             : 
    4465             :     Assert(returningList);
    4466             : 
    4467           8 :     vars = pull_var_clause((Node *) returningList, PVC_INCLUDE_PLACEHOLDERS);
    4468             : 
    4469             :     /*
    4470             :      * If there's a whole-row reference to the target relation, then we'll
    4471             :      * need all the columns of the relation.
    4472             :      */
    4473           8 :     foreach(lc, vars)
    4474             :     {
    4475           4 :         Var        *var = (Var *) lfirst(lc);
    4476             : 
    4477           4 :         if (IsA(var, Var) &&
    4478           4 :             var->varno == rtindex &&
    4479           4 :             var->varattno == InvalidAttrNumber)
    4480             :         {
    4481           4 :             have_wholerow = true;
    4482           4 :             break;
    4483             :         }
    4484             :     }
    4485             : 
    4486           8 :     if (have_wholerow)
    4487             :     {
    4488           4 :         TupleDesc   tupdesc = RelationGetDescr(rel);
    4489             :         int         i;
    4490             : 
    4491          40 :         for (i = 1; i <= tupdesc->natts; i++)
    4492             :         {
    4493          36 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
    4494             :             Var        *var;
    4495             : 
    4496             :             /* Ignore dropped attributes. */
    4497          36 :             if (attr->attisdropped)
    4498           4 :                 continue;
    4499             : 
    4500          32 :             var = makeVar(rtindex,
    4501             :                           i,
    4502             :                           attr->atttypid,
    4503             :                           attr->atttypmod,
    4504             :                           attr->attcollation,
    4505             :                           0);
    4506             : 
    4507          32 :             tlist = lappend(tlist,
    4508          32 :                             makeTargetEntry((Expr *) var,
    4509          32 :                                             list_length(tlist) + 1,
    4510             :                                             NULL,
    4511             :                                             false));
    4512             :         }
    4513             :     }
    4514             : 
    4515             :     /* Now add any remaining columns to tlist. */
    4516          60 :     foreach(lc, vars)
    4517             :     {
    4518          52 :         Var        *var = (Var *) lfirst(lc);
    4519             : 
    4520             :         /*
    4521             :          * No need for whole-row references to the target relation.  We don't
    4522             :          * need system columns other than ctid and oid either, since those are
    4523             :          * set locally.
    4524             :          */
    4525          52 :         if (IsA(var, Var) &&
    4526          52 :             var->varno == rtindex &&
    4527          36 :             var->varattno <= InvalidAttrNumber &&
    4528           4 :             var->varattno != SelfItemPointerAttributeNumber)
    4529           4 :             continue;           /* don't need it */
    4530             : 
    4531          48 :         if (tlist_member((Expr *) var, tlist))
    4532          32 :             continue;           /* already got it */
    4533             : 
    4534          16 :         tlist = lappend(tlist,
    4535          16 :                         makeTargetEntry((Expr *) var,
    4536          16 :                                         list_length(tlist) + 1,
    4537             :                                         NULL,
    4538             :                                         false));
    4539             :     }
    4540             : 
    4541           8 :     list_free(vars);
    4542             : 
    4543           8 :     return tlist;
    4544             : }
    4545             : 
    4546             : /*
    4547             :  * rebuild_fdw_scan_tlist
    4548             :  *      Build new fdw_scan_tlist of given foreign-scan plan node from given
    4549             :  *      tlist
    4550             :  *
    4551             :  * There might be columns that the fdw_scan_tlist of the given foreign-scan
    4552             :  * plan node contains that the given tlist doesn't.  The fdw_scan_tlist would
    4553             :  * have contained resjunk columns such as 'ctid' of the target relation and
    4554             :  * 'wholerow' of non-target relations, but the tlist might not contain them,
    4555             :  * for example.  So, adjust the tlist so it contains all the columns specified
    4556             :  * in the fdw_scan_tlist; else setrefs.c will get confused.
    4557             :  */
    4558             : static void
    4559           4 : rebuild_fdw_scan_tlist(ForeignScan *fscan, List *tlist)
    4560             : {
    4561           4 :     List       *new_tlist = tlist;
    4562           4 :     List       *old_tlist = fscan->fdw_scan_tlist;
    4563             :     ListCell   *lc;
    4564             : 
    4565          32 :     foreach(lc, old_tlist)
    4566             :     {
    4567          28 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
    4568             : 
    4569          28 :         if (tlist_member(tle->expr, new_tlist))
    4570          16 :             continue;           /* already got it */
    4571             : 
    4572          12 :         new_tlist = lappend(new_tlist,
    4573          12 :                             makeTargetEntry(tle->expr,
    4574          12 :                                             list_length(new_tlist) + 1,
    4575             :                                             NULL,
    4576             :                                             false));
    4577             :     }
    4578           4 :     fscan->fdw_scan_tlist = new_tlist;
    4579           4 : }
    4580             : 
    4581             : /*
    4582             :  * Execute a direct UPDATE/DELETE statement.
    4583             :  */
    4584             : static void
    4585         142 : execute_dml_stmt(ForeignScanState *node)
    4586             : {
    4587         142 :     PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
    4588         142 :     ExprContext *econtext = node->ss.ps.ps_ExprContext;
    4589         142 :     int         numParams = dmstate->numParams;
    4590         142 :     const char **values = dmstate->param_values;
    4591             : 
    4592             :     /* First, process a pending asynchronous request, if any. */
    4593         142 :     if (dmstate->conn_state->pendingAreq)
    4594           2 :         process_pending_request(dmstate->conn_state->pendingAreq);
    4595             : 
    4596             :     /*
    4597             :      * Construct array of query parameter values in text format.
    4598             :      */
    4599         142 :     if (numParams > 0)
    4600           0 :         process_query_params(econtext,
    4601             :                              dmstate->param_flinfo,
    4602             :                              dmstate->param_exprs,
    4603             :                              values);
    4604             : 
    4605             :     /*
    4606             :      * Notice that we pass NULL for paramTypes, thus forcing the remote server
    4607             :      * to infer types for all parameters.  Since we explicitly cast every
    4608             :      * parameter (see deparse.c), the "inference" is trivial and will produce
    4609             :      * the desired result.  This allows us to avoid assuming that the remote
    4610             :      * server has the same OIDs we do for the parameters' types.
    4611             :      */
    4612         142 :     if (!PQsendQueryParams(dmstate->conn, dmstate->query, numParams,
    4613             :                            NULL, values, NULL, NULL, 0))
    4614           0 :         pgfdw_report_error(ERROR, NULL, dmstate->conn, false, dmstate->query);
    4615             : 
    4616             :     /*
    4617             :      * Get the result, and check for success.
    4618             :      *
    4619             :      * We use a memory context callback to ensure that the PGresult will be
    4620             :      * released, even if the query fails somewhere that's outside our control.
    4621             :      * The callback is already registered, just need to fill in its arg.
    4622             :      */
    4623             :     Assert(dmstate->result == NULL);
    4624         142 :     dmstate->result = pgfdw_get_result(dmstate->conn);
    4625         142 :     dmstate->result_cb.arg = dmstate->result;
    4626             : 
    4627         284 :     if (PQresultStatus(dmstate->result) !=
    4628         142 :         (dmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
    4629           8 :         pgfdw_report_error(ERROR, dmstate->result, dmstate->conn, false,
    4630           8 :                            dmstate->query);
    4631             : 
    4632             :     /* Get the number of rows affected. */
    4633         134 :     if (dmstate->has_returning)
    4634          28 :         dmstate->num_tuples = PQntuples(dmstate->result);
    4635             :     else
    4636         106 :         dmstate->num_tuples = atoi(PQcmdTuples(dmstate->result));
    4637         134 : }
    4638             : 
    4639             : /*
    4640             :  * Get the result of a RETURNING clause.
    4641             :  */
    4642             : static TupleTableSlot *
    4643         728 : get_returning_data(ForeignScanState *node)
    4644             : {
    4645         728 :     PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
    4646         728 :     EState     *estate = node->ss.ps.state;
    4647         728 :     ResultRelInfo *resultRelInfo = node->resultRelInfo;
    4648         728 :     TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
    4649             :     TupleTableSlot *resultSlot;
    4650             : 
    4651             :     Assert(resultRelInfo->ri_projectReturning);
    4652             : 
    4653             :     /* If we didn't get any tuples, must be end of data. */
    4654         728 :     if (dmstate->next_tuple >= dmstate->num_tuples)
    4655          34 :         return ExecClearTuple(slot);
    4656             : 
    4657             :     /* Increment the command es_processed count if necessary. */
    4658         694 :     if (dmstate->set_processed)
    4659         692 :         estate->es_processed += 1;
    4660             : 
    4661             :     /*
    4662             :      * Store a RETURNING tuple.  If has_returning is false, just emit a dummy
    4663             :      * tuple.  (has_returning is false when the local query is of the form
    4664             :      * "UPDATE/DELETE .. RETURNING 1" for example.)
    4665             :      */
    4666         694 :     if (!dmstate->has_returning)
    4667             :     {
    4668          24 :         ExecStoreAllNullTuple(slot);
    4669          24 :         resultSlot = slot;
    4670             :     }
    4671             :     else
    4672             :     {
    4673             :         HeapTuple   newtup;
    4674             : 
    4675         670 :         newtup = make_tuple_from_result_row(dmstate->result,
    4676             :                                             dmstate->next_tuple,
    4677             :                                             dmstate->rel,
    4678             :                                             dmstate->attinmeta,
    4679             :                                             dmstate->retrieved_attrs,
    4680             :                                             node,
    4681             :                                             dmstate->temp_cxt);
    4682         670 :         ExecStoreHeapTuple(newtup, slot, false);
    4683             :         /* Get the updated/deleted tuple. */
    4684         670 :         if (dmstate->rel)
    4685         638 :             resultSlot = slot;
    4686             :         else
    4687          32 :             resultSlot = apply_returning_filter(dmstate, resultRelInfo, slot, estate);
    4688             :     }
    4689         694 :     dmstate->next_tuple++;
    4690             : 
    4691             :     /* Make slot available for evaluation of the local query RETURNING list. */
    4692         694 :     resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple =
    4693             :         resultSlot;
    4694             : 
    4695         694 :     return slot;
    4696             : }
    4697             : 
    4698             : /*
    4699             :  * Initialize a filter to extract an updated/deleted tuple from a scan tuple.
    4700             :  */
    4701             : static void
    4702           2 : init_returning_filter(PgFdwDirectModifyState *dmstate,
    4703             :                       List *fdw_scan_tlist,
    4704             :                       Index rtindex)
    4705             : {
    4706           2 :     TupleDesc   resultTupType = RelationGetDescr(dmstate->resultRel);
    4707             :     ListCell   *lc;
    4708             :     int         i;
    4709             : 
    4710             :     /*
    4711             :      * Calculate the mapping between the fdw_scan_tlist's entries and the
    4712             :      * result tuple's attributes.
    4713             :      *
    4714             :      * The "map" is an array of indexes of the result tuple's attributes in
    4715             :      * fdw_scan_tlist, i.e., one entry for every attribute of the result
    4716             :      * tuple.  We store zero for any attributes that don't have the
    4717             :      * corresponding entries in that list, marking that a NULL is needed in
    4718             :      * the result tuple.
    4719             :      *
    4720             :      * Also get the indexes of the entries for ctid and oid if any.
    4721             :      */
    4722           2 :     dmstate->attnoMap = (AttrNumber *)
    4723           2 :         palloc0(resultTupType->natts * sizeof(AttrNumber));
    4724             : 
    4725           2 :     dmstate->ctidAttno = dmstate->oidAttno = 0;
    4726             : 
    4727           2 :     i = 1;
    4728           2 :     dmstate->hasSystemCols = false;
    4729          32 :     foreach(lc, fdw_scan_tlist)
    4730             :     {
    4731          30 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
    4732          30 :         Var        *var = (Var *) tle->expr;
    4733             : 
    4734             :         Assert(IsA(var, Var));
    4735             : 
    4736             :         /*
    4737             :          * If the Var is a column of the target relation to be retrieved from
    4738             :          * the foreign server, get the index of the entry.
    4739             :          */
    4740          50 :         if (var->varno == rtindex &&
    4741          20 :             list_member_int(dmstate->retrieved_attrs, i))
    4742             :         {
    4743          16 :             int         attrno = var->varattno;
    4744             : 
    4745          16 :             if (attrno < 0)
    4746             :             {
    4747             :                 /*
    4748             :                  * We don't retrieve system columns other than ctid and oid.
    4749             :                  */
    4750           0 :                 if (attrno == SelfItemPointerAttributeNumber)
    4751           0 :                     dmstate->ctidAttno = i;
    4752             :                 else
    4753             :                     Assert(false);
    4754           0 :                 dmstate->hasSystemCols = true;
    4755             :             }
    4756             :             else
    4757             :             {
    4758             :                 /*
    4759             :                  * We don't retrieve whole-row references to the target
    4760             :                  * relation either.
    4761             :                  */
    4762             :                 Assert(attrno > 0);
    4763             : 
    4764          16 :                 dmstate->attnoMap[attrno - 1] = i;
    4765             :             }
    4766             :         }
    4767          30 :         i++;
    4768             :     }
    4769           2 : }
    4770             : 
    4771             : /*
    4772             :  * Extract and return an updated/deleted tuple from a scan tuple.
    4773             :  */
    4774             : static TupleTableSlot *
    4775          32 : apply_returning_filter(PgFdwDirectModifyState *dmstate,
    4776             :                        ResultRelInfo *resultRelInfo,
    4777             :                        TupleTableSlot *slot,
    4778             :                        EState *estate)
    4779             : {
    4780          32 :     TupleDesc   resultTupType = RelationGetDescr(dmstate->resultRel);
    4781             :     TupleTableSlot *resultSlot;
    4782             :     Datum      *values;
    4783             :     bool       *isnull;
    4784             :     Datum      *old_values;
    4785             :     bool       *old_isnull;
    4786             :     int         i;
    4787             : 
    4788             :     /*
    4789             :      * Use the return tuple slot as a place to store the result tuple.
    4790             :      */
    4791          32 :     resultSlot = ExecGetReturningSlot(estate, resultRelInfo);
    4792             : 
    4793             :     /*
    4794             :      * Extract all the values of the scan tuple.
    4795             :      */
    4796          32 :     slot_getallattrs(slot);
    4797          32 :     old_values = slot->tts_values;
    4798          32 :     old_isnull = slot->tts_isnull;
    4799             : 
    4800             :     /*
    4801             :      * Prepare to build the result tuple.
    4802             :      */
    4803          32 :     ExecClearTuple(resultSlot);
    4804          32 :     values = resultSlot->tts_values;
    4805          32 :     isnull = resultSlot->tts_isnull;
    4806             : 
    4807             :     /*
    4808             :      * Transpose data into proper fields of the result tuple.
    4809             :      */
    4810         320 :     for (i = 0; i < resultTupType->natts; i++)
    4811             :     {
    4812         288 :         int         j = dmstate->attnoMap[i];
    4813             : 
    4814         288 :         if (j == 0)
    4815             :         {
    4816          32 :             values[i] = (Datum) 0;
    4817          32 :             isnull[i] = true;
    4818             :         }
    4819             :         else
    4820             :         {
    4821         256 :             values[i] = old_values[j - 1];
    4822         256 :             isnull[i] = old_isnull[j - 1];
    4823             :         }
    4824             :     }
    4825             : 
    4826             :     /*
    4827             :      * Build the virtual tuple.
    4828             :      */
    4829          32 :     ExecStoreVirtualTuple(resultSlot);
    4830             : 
    4831             :     /*
    4832             :      * If we have any system columns to return, materialize a heap tuple in
    4833             :      * the slot from column values set above and install system columns in
    4834             :      * that tuple.
    4835             :      */
    4836          32 :     if (dmstate->hasSystemCols)
    4837             :     {
    4838           0 :         HeapTuple   resultTup = ExecFetchSlotHeapTuple(resultSlot, true, NULL);
    4839             : 
    4840             :         /* ctid */
    4841           0 :         if (dmstate->ctidAttno)
    4842             :         {
    4843           0 :             ItemPointer ctid = NULL;
    4844             : 
    4845           0 :             ctid = (ItemPointer) DatumGetPointer(old_values[dmstate->ctidAttno - 1]);
    4846           0 :             resultTup->t_self = *ctid;
    4847             :         }
    4848             : 
    4849             :         /*
    4850             :          * And remaining columns
    4851             :          *
    4852             :          * Note: since we currently don't allow the target relation to appear
    4853             :          * on the nullable side of an outer join, any system columns wouldn't
    4854             :          * go to NULL.
    4855             :          *
    4856             :          * Note: no need to care about tableoid here because it will be
    4857             :          * initialized in ExecProcessReturning().
    4858             :          */
    4859           0 :         HeapTupleHeaderSetXmin(resultTup->t_data, InvalidTransactionId);
    4860           0 :         HeapTupleHeaderSetXmax(resultTup->t_data, InvalidTransactionId);
    4861           0 :         HeapTupleHeaderSetCmin(resultTup->t_data, InvalidTransactionId);
    4862             :     }
    4863             : 
    4864             :     /*
    4865             :      * And return the result tuple.
    4866             :      */
    4867          32 :     return resultSlot;
    4868             : }
    4869             : 
    4870             : /*
    4871             :  * Prepare for processing of parameters used in remote query.
    4872             :  */
    4873             : static void
    4874          36 : prepare_query_params(PlanState *node,
    4875             :                      List *fdw_exprs,
    4876             :                      int numParams,
    4877             :                      FmgrInfo **param_flinfo,
    4878             :                      List **param_exprs,
    4879             :                      const char ***param_values)
    4880             : {
    4881             :     int         i;
    4882             :     ListCell   *lc;
    4883             : 
    4884             :     Assert(numParams > 0);
    4885             : 
    4886             :     /* Prepare for output conversion of parameters used in remote query. */
    4887          36 :     *param_flinfo = (FmgrInfo *) palloc0(sizeof(FmgrInfo) * numParams);
    4888             : 
    4889          36 :     i = 0;
    4890          74 :     foreach(lc, fdw_exprs)
    4891             :     {
    4892          38 :         Node       *param_expr = (Node *) lfirst(lc);
    4893             :         Oid         typefnoid;
    4894             :         bool        isvarlena;
    4895             : 
    4896          38 :         getTypeOutputInfo(exprType(param_expr), &typefnoid, &isvarlena);
    4897          38 :         fmgr_info(typefnoid, &(*param_flinfo)[i]);
    4898          38 :         i++;
    4899             :     }
    4900             : 
    4901             :     /*
    4902             :      * Prepare remote-parameter expressions for evaluation.  (Note: in
    4903             :      * practice, we expect that all these expressions will be just Params, so
    4904             :      * we could possibly do something more efficient than using the full
    4905             :      * expression-eval machinery for this.  But probably there would be little
    4906             :      * benefit, and it'd require postgres_fdw to know more than is desirable
    4907             :      * about Param evaluation.)
    4908             :      */
    4909          36 :     *param_exprs = ExecInitExprList(fdw_exprs, node);
    4910             : 
    4911             :     /* Allocate buffer for text form of query parameters. */
    4912          36 :     *param_values = (const char **) palloc0(numParams * sizeof(char *));
    4913          36 : }
    4914             : 
    4915             : /*
    4916             :  * Construct array of query parameter values in text format.
    4917             :  */
    4918             : static void
    4919         692 : process_query_params(ExprContext *econtext,
    4920             :                      FmgrInfo *param_flinfo,
    4921             :                      List *param_exprs,
    4922             :                      const char **param_values)
    4923             : {
    4924             :     int         nestlevel;
    4925             :     int         i;
    4926             :     ListCell   *lc;
    4927             : 
    4928         692 :     nestlevel = set_transmission_modes();
    4929             : 
    4930         692 :     i = 0;
    4931        1784 :     foreach(lc, param_exprs)
    4932             :     {
    4933        1092 :         ExprState  *expr_state = (ExprState *) lfirst(lc);
    4934             :         Datum       expr_value;
    4935             :         bool        isNull;
    4936             : 
    4937             :         /* Evaluate the parameter expression */
    4938        1092 :         expr_value = ExecEvalExpr(expr_state, econtext, &isNull);
    4939             : 
    4940             :         /*
    4941             :          * Get string representation of each parameter value by invoking
    4942             :          * type-specific output function, unless the value is null.
    4943             :          */
    4944        1092 :         if (isNull)
    4945           0 :             param_values[i] = NULL;
    4946             :         else
    4947        1092 :             param_values[i] = OutputFunctionCall(&param_flinfo[i], expr_value);
    4948             : 
    4949        1092 :         i++;
    4950             :     }
    4951             : 
    4952         692 :     reset_transmission_modes(nestlevel);
    4953         692 : }
    4954             : 
    4955             : /*
    4956             :  * postgresAnalyzeForeignTable
    4957             :  *      Test whether analyzing this foreign table is supported
    4958             :  */
    4959             : static bool
    4960          84 : postgresAnalyzeForeignTable(Relation relation,
    4961             :                             AcquireSampleRowsFunc *func,
    4962             :                             BlockNumber *totalpages)
    4963             : {
    4964             :     ForeignTable *table;
    4965             :     UserMapping *user;
    4966             :     PGconn     *conn;
    4967             :     StringInfoData sql;
    4968          84 :     PGresult   *volatile res = NULL;
    4969             : 
    4970             :     /* Return the row-analysis function pointer */
    4971          84 :     *func = postgresAcquireSampleRowsFunc;
    4972             : 
    4973             :     /*
    4974             :      * Now we have to get the number of pages.  It's annoying that the ANALYZE
    4975             :      * API requires us to return that now, because it forces some duplication
    4976             :      * of effort between this routine and postgresAcquireSampleRowsFunc.  But
    4977             :      * it's probably not worth redefining that API at this point.
    4978             :      */
    4979             : 
    4980             :     /*
    4981             :      * Get the connection to use.  We do the remote access as the table's
    4982             :      * owner, even if the ANALYZE was started by some other user.
    4983             :      */
    4984          84 :     table = GetForeignTable(RelationGetRelid(relation));
    4985          84 :     user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
    4986          84 :     conn = GetConnection(user, false, NULL);
    4987             : 
    4988             :     /*
    4989             :      * Construct command to get page count for relation.
    4990             :      */
    4991          84 :     initStringInfo(&sql);
    4992          84 :     deparseAnalyzeSizeSql(&sql, relation);
    4993             : 
    4994             :     /* In what follows, do not risk leaking any PGresults. */
    4995          84 :     PG_TRY();
    4996             :     {
    4997          84 :         res = pgfdw_exec_query(conn, sql.data, NULL);
    4998          84 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
    4999           0 :             pgfdw_report_error(ERROR, res, conn, false, sql.data);
    5000             : 
    5001          84 :         if (PQntuples(res) != 1 || PQnfields(res) != 1)
    5002           0 :             elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
    5003          84 :         *totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
    5004             :     }
    5005           0 :     PG_FINALLY();
    5006             :     {
    5007          84 :         PQclear(res);
    5008             :     }
    5009          84 :     PG_END_TRY();
    5010             : 
    5011          84 :     ReleaseConnection(conn);
    5012             : 
    5013          84 :     return true;
    5014             : }
    5015             : 
    5016             : /*
    5017             :  * postgresGetAnalyzeInfoForForeignTable
    5018             :  *      Count tuples in foreign table (just get pg_class.reltuples).
    5019             :  *
    5020             :  * can_tablesample determines if the remote relation supports acquiring the
    5021             :  * sample using TABLESAMPLE.
    5022             :  */
    5023             : static double
    5024          84 : postgresGetAnalyzeInfoForForeignTable(Relation relation, bool *can_tablesample)
    5025             : {
    5026             :     ForeignTable *table;
    5027             :     UserMapping *user;
    5028             :     PGconn     *conn;
    5029             :     StringInfoData sql;
    5030          84 :     PGresult   *volatile res = NULL;
    5031          84 :     volatile double reltuples = -1;
    5032          84 :     volatile char relkind = 0;
    5033             : 
    5034             :     /* assume the remote relation does not support TABLESAMPLE */
    5035          84 :     *can_tablesample = false;
    5036             : 
    5037             :     /*
    5038             :      * Get the connection to use.  We do the remote access as the table's
    5039             :      * owner, even if the ANALYZE was started by some other user.
    5040             :      */
    5041          84 :     table = GetForeignTable(RelationGetRelid(relation));
    5042          84 :     user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
    5043          84 :     conn = GetConnection(user, false, NULL);
    5044             : 
    5045             :     /*
    5046             :      * Construct command to get page count for relation.
    5047             :      */
    5048          84 :     initStringInfo(&sql);
    5049          84 :     deparseAnalyzeInfoSql(&sql, relation);
    5050             : 
    5051             :     /* In what follows, do not risk leaking any PGresults. */
    5052          84 :     PG_TRY();
    5053             :     {
    5054          84 :         res = pgfdw_exec_query(conn, sql.data, NULL);
    5055          84 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
    5056           0 :             pgfdw_report_error(ERROR, res, conn, false, sql.data);
    5057             : 
    5058          84 :         if (PQntuples(res) != 1 || PQnfields(res) != 2)
    5059           0 :             elog(ERROR, "unexpected result from deparseAnalyzeInfoSql query");
    5060          84 :         reltuples = strtod(PQgetvalue(res, 0, 0), NULL);
    5061          84 :         relkind = *(PQgetvalue(res, 0, 1));
    5062             :     }
    5063           0 :     PG_FINALLY();
    5064             :     {
    5065          84 :         if (res)
    5066          84 :             PQclear(res);
    5067             :     }
    5068          84 :     PG_END_TRY();
    5069             : 
    5070          84 :     ReleaseConnection(conn);
    5071             : 
    5072             :     /* TABLESAMPLE is supported only for regular tables and matviews */
    5073         168 :     *can_tablesample = (relkind == RELKIND_RELATION ||
    5074          84 :                         relkind == RELKIND_MATVIEW ||
    5075           0 :                         relkind == RELKIND_PARTITIONED_TABLE);
    5076             : 
    5077          84 :     return reltuples;
    5078             : }
    5079             : 
    5080             : /*
    5081             :  * Acquire a random sample of rows from foreign table managed by postgres_fdw.
    5082             :  *
    5083             :  * Selected rows are returned in the caller-allocated array rows[],
    5084             :  * which must have at least targrows entries.
    5085             :  * The actual number of rows selected is returned as the function result.
    5086             :  * We also count the total number of rows in the table and return it into
    5087             :  * *totalrows.  Note that *totaldeadrows is always set to 0.
    5088             :  *
    5089             :  * Note that the returned list of rows is not always in order by physical
    5090             :  * position in the table.  Therefore, correlation estimates derived later
    5091             :  * may be meaningless, but it's OK because we don't use the estimates
    5092             :  * currently (the planner only pays attention to correlation for indexscans).
    5093             :  */
    5094             : static int
    5095          84 : postgresAcquireSampleRowsFunc(Relation relation, int elevel,
    5096             :                               HeapTuple *rows, int targrows,
    5097             :                               double *totalrows,
    5098             :                               double *totaldeadrows)
    5099             : {
    5100             :     PgFdwAnalyzeState astate;
    5101             :     ForeignTable *table;
    5102             :     ForeignServer *server;
    5103             :     UserMapping *user;
    5104             :     PGconn     *conn;
    5105             :     int         server_version_num;
    5106          84 :     PgFdwSamplingMethod method = ANALYZE_SAMPLE_AUTO;   /* auto is default */
    5107          84 :     double      sample_frac = -1.0;
    5108             :     double      reltuples;
    5109             :     unsigned int cursor_number;
    5110             :     StringInfoData sql;
    5111          84 :     PGresult   *volatile res = NULL;
    5112             :     ListCell   *lc;
    5113             : 
    5114             :     /* Initialize workspace state */
    5115          84 :     astate.rel = relation;
    5116          84 :     astate.attinmeta = TupleDescGetAttInMetadata(RelationGetDescr(relation));
    5117             : 
    5118          84 :     astate.rows = rows;
    5119          84 :     astate.targrows = targrows;
    5120          84 :     astate.numrows = 0;
    5121          84 :     astate.samplerows = 0;
    5122          84 :     astate.rowstoskip = -1;     /* -1 means not set yet */
    5123          84 :     reservoir_init_selection_state(&astate.rstate, targrows);
    5124             : 
    5125             :     /* Remember ANALYZE context, and create a per-tuple temp context */
    5126          84 :     astate.anl_cxt = CurrentMemoryContext;
    5127          84 :     astate.temp_cxt = AllocSetContextCreate(CurrentMemoryContext,
    5128             :                                             "postgres_fdw temporary data",
    5129             :                                             ALLOCSET_SMALL_SIZES);
    5130             : 
    5131             :     /*
    5132             :      * Get the connection to use.  We do the remote access as the table's
    5133             :      * owner, even if the ANALYZE was started by some other user.
    5134             :      */
    5135          84 :     table = GetForeignTable(RelationGetRelid(relation));
    5136          84 :     server = GetForeignServer(table->serverid);
    5137          84 :     user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
    5138          84 :     conn = GetConnection(user, false, NULL);
    5139             : 
    5140             :     /* We'll need server version, so fetch it now. */
    5141          84 :     server_version_num = PQserverVersion(conn);
    5142             : 
    5143             :     /*
    5144             :      * What sampling method should we use?
    5145             :      */
    5146         368 :     foreach(lc, server->options)
    5147             :     {
    5148         284 :         DefElem    *def = (DefElem *) lfirst(lc);
    5149             : 
    5150         284 :         if (strcmp(def->defname, "analyze_sampling") == 0)
    5151             :         {
    5152           0 :             char       *value = defGetString(def);
    5153             : 
    5154           0 :             if (strcmp(value, "off") == 0)
    5155           0 :                 method = ANALYZE_SAMPLE_OFF;
    5156           0 :             else if (strcmp(value, "auto") == 0)
    5157           0 :                 method = ANALYZE_SAMPLE_AUTO;
    5158           0 :             else if (strcmp(value, "random") == 0)
    5159           0 :                 method = ANALYZE_SAMPLE_RANDOM;
    5160           0 :             else if (strcmp(value, "system") == 0)
    5161           0 :                 method = ANALYZE_SAMPLE_SYSTEM;
    5162           0 :             else if (strcmp(value, "bernoulli") == 0)
    5163           0 :                 method = ANALYZE_SAMPLE_BERNOULLI;
    5164             : 
    5165           0 :             break;
    5166             :         }
    5167             :     }
    5168             : 
    5169         196 :     foreach(lc, table->options)
    5170             :     {
    5171         112 :         DefElem    *def = (DefElem *) lfirst(lc);
    5172             : 
    5173         112 :         if (strcmp(def->defname, "analyze_sampling") == 0)
    5174             :         {
    5175           0 :             char       *value = defGetString(def);
    5176             : 
    5177           0 :             if (strcmp(value, "off") == 0)
    5178           0 :                 method = ANALYZE_SAMPLE_OFF;
    5179           0 :             else if (strcmp(value, "auto") == 0)
    5180           0 :                 method = ANALYZE_SAMPLE_AUTO;
    5181           0 :             else if (strcmp(value, "random") == 0)
    5182           0 :                 method = ANALYZE_SAMPLE_RANDOM;
    5183           0 :             else if (strcmp(value, "system") == 0)
    5184           0 :                 method = ANALYZE_SAMPLE_SYSTEM;
    5185           0 :             else if (strcmp(value, "bernoulli") == 0)
    5186           0 :                 method = ANALYZE_SAMPLE_BERNOULLI;
    5187             : 
    5188           0 :             break;
    5189             :         }
    5190             :     }
    5191             : 
    5192             :     /*
    5193             :      * Error-out if explicitly required one of the TABLESAMPLE methods, but
    5194             :      * the server does not support it.
    5195             :      */
    5196          84 :     if ((server_version_num < 95000) &&
    5197           0 :         (method == ANALYZE_SAMPLE_SYSTEM ||
    5198             :          method == ANALYZE_SAMPLE_BERNOULLI))
    5199           0 :         ereport(ERROR,
    5200             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5201             :                  errmsg("remote server does not support TABLESAMPLE feature")));
    5202             : 
    5203             :     /*
    5204             :      * If we've decided to do remote sampling, calculate the sampling rate. We
    5205             :      * need to get the number of tuples from the remote server, but skip that
    5206             :      * network round-trip if not needed.
    5207             :      */
    5208          84 :     if (method != ANALYZE_SAMPLE_OFF)
    5209             :     {
    5210             :         bool        can_tablesample;
    5211             : 
    5212          84 :         reltuples = postgresGetAnalyzeInfoForForeignTable(relation,
    5213             :                                                           &can_tablesample);
    5214             : 
    5215             :         /*
    5216             :          * Make sure we're not choosing TABLESAMPLE when the remote relation
    5217             :          * does not support that. But only do this for "auto" - if the user
    5218             :          * explicitly requested BERNOULLI/SYSTEM, it's better to fail.
    5219             :          */
    5220          84 :         if (!can_tablesample && (method == ANALYZE_SAMPLE_AUTO))
    5221           0 :             method = ANALYZE_SAMPLE_RANDOM;
    5222             : 
    5223             :         /*
    5224             :          * Remote's reltuples could be 0 or -1 if the table has never been
    5225             :          * vacuumed/analyzed.  In that case, disable sampling after all.
    5226             :          */
    5227          84 :         if ((reltuples <= 0) || (targrows >= reltuples))
    5228          84 :             method = ANALYZE_SAMPLE_OFF;
    5229             :         else
    5230             :         {
    5231             :             /*
    5232             :              * All supported sampling methods require sampling rate, not
    5233             :              * target rows directly, so we calculate that using the remote
    5234             :              * reltuples value. That's imperfect, because it might be off a
    5235             :              * good deal, but that's not something we can (or should) address
    5236             :              * here.
    5237             :              *
    5238             :              * If reltuples is too low (i.e. when table grew), we'll end up
    5239             :              * sampling more rows - but then we'll apply the local sampling,
    5240             :              * so we get the expected sample size. This is the same outcome as
    5241             :              * without remote sampling.
    5242             :              *
    5243             :              * If reltuples is too high (e.g. after bulk DELETE), we will end
    5244             :              * up sampling too few rows.
    5245             :              *
    5246             :              * We can't really do much better here - we could try sampling a
    5247             :              * bit more rows, but we don't know how off the reltuples value is
    5248             :              * so how much is "a bit more"?
    5249             :              *
    5250             :              * Furthermore, the targrows value for partitions is determined
    5251             :              * based on table size (relpages), which can be off in different
    5252             :              * ways too. Adjusting the sampling rate here might make the issue
    5253             :              * worse.
    5254             :              */
    5255           0 :             sample_frac = targrows / reltuples;
    5256             : 
    5257             :             /*
    5258             :              * We should never get sampling rate outside the valid range
    5259             :              * (between 0.0 and 1.0), because those cases should be covered by
    5260             :              * the previous branch that sets ANALYZE_SAMPLE_OFF.
    5261             :              */
    5262             :             Assert(sample_frac >= 0.0 && sample_frac <= 1.0);
    5263             :         }
    5264             :     }
    5265             : 
    5266             :     /*
    5267             :      * For "auto" method, pick the one we believe is best. For servers with
    5268             :      * TABLESAMPLE support we pick BERNOULLI, for old servers we fall-back to
    5269             :      * random() to at least reduce network transfer.
    5270             :      */
    5271          84 :     if (method == ANALYZE_SAMPLE_AUTO)
    5272             :     {
    5273           0 :         if (server_version_num < 95000)
    5274           0 :             method = ANALYZE_SAMPLE_RANDOM;
    5275             :         else
    5276           0 :             method = ANALYZE_SAMPLE_BERNOULLI;
    5277             :     }
    5278             : 
    5279             :     /*
    5280             :      * Construct cursor that retrieves whole rows from remote.
    5281             :      */
    5282          84 :     cursor_number = GetCursorNumber(conn);
    5283          84 :     initStringInfo(&sql);
    5284          84 :     appendStringInfo(&sql, "DECLARE c%u CURSOR FOR ", cursor_number);
    5285             : 
    5286          84 :     deparseAnalyzeSql(&sql, relation, method, sample_frac, &astate.retrieved_attrs);
    5287             : 
    5288             :     /* In what follows, do not risk leaking any PGresults. */
    5289          84 :     PG_TRY();
    5290             :     {
    5291             :         char        fetch_sql[64];
    5292             :         int         fetch_size;
    5293             : 
    5294          84 :         res = pgfdw_exec_query(conn, sql.data, NULL);
    5295          84 :         if (PQresultStatus(res) != PGRES_COMMAND_OK)
    5296           0 :             pgfdw_report_error(ERROR, res, conn, false, sql.data);
    5297          84 :         PQclear(res);
    5298          84 :         res = NULL;
    5299             : 
    5300             :         /*
    5301             :          * Determine the fetch size.  The default is arbitrary, but shouldn't
    5302             :          * be enormous.
    5303             :          */
    5304          84 :         fetch_size = 100;
    5305         368 :         foreach(lc, server->options)
    5306             :         {
    5307         284 :             DefElem    *def = (DefElem *) lfirst(lc);
    5308             : 
    5309         284 :             if (strcmp(def->defname, "fetch_size") == 0)
    5310             :             {
    5311           0 :                 (void) parse_int(defGetString(def), &fetch_size, 0, NULL);
    5312           0 :                 break;
    5313             :             }
    5314             :         }
    5315         196 :         foreach(lc, table->options)
    5316             :         {
    5317         112 :             DefElem    *def = (DefElem *) lfirst(lc);
    5318             : 
    5319         112 :             if (strcmp(def->defname, "fetch_size") == 0)
    5320             :             {
    5321           0 :                 (void) parse_int(defGetString(def), &fetch_size, 0, NULL);
    5322           0 :                 break;
    5323             :             }
    5324             :         }
    5325             : 
    5326             :         /* Construct command to fetch rows from remote. */
    5327          84 :         snprintf(fetch_sql, sizeof(fetch_sql), "FETCH %d FROM c%u",
    5328             :                  fetch_size, cursor_number);
    5329             : 
    5330             :         /* Retrieve and process rows a batch at a time. */
    5331             :         for (;;)
    5332         344 :         {
    5333             :             int         numrows;
    5334             :             int         i;
    5335             : 
    5336             :             /* Allow users to cancel long query */
    5337         428 :             CHECK_FOR_INTERRUPTS();
    5338             : 
    5339             :             /*
    5340             :              * XXX possible future improvement: if rowstoskip is large, we
    5341             :              * could issue a MOVE rather than physically fetching the rows,
    5342             :              * then just adjust rowstoskip and samplerows appropriately.
    5343             :              */
    5344             : 
    5345             :             /* Fetch some rows */
    5346         428 :             res = pgfdw_exec_query(conn, fetch_sql, NULL);
    5347             :             /* On error, report the original query, not the FETCH. */
    5348         428 :             if (PQresultStatus(res) != PGRES_TUPLES_OK)
    5349           0 :                 pgfdw_report_error(ERROR, res, conn, false, sql.data);
    5350             : 
    5351             :             /* Process whatever we got. */
    5352         428 :             numrows = PQntuples(res);
    5353       35882 :             for (i = 0; i < numrows; i++)
    5354       35456 :                 analyze_row_processor(res, i, &astate);
    5355             : 
    5356         426 :             PQclear(res);
    5357         426 :             res = NULL;
    5358             : 
    5359             :             /* Must be EOF if we didn't get all the rows requested. */
    5360         426 :             if (numrows < fetch_size)
    5361          82 :                 break;
    5362             :         }
    5363             : 
    5364             :         /* Close the cursor, just to be tidy. */
    5365          82 :         close_cursor(conn, cursor_number, NULL);
    5366             :     }
    5367           2 :     PG_CATCH();
    5368             :     {
    5369           2 :         PQclear(res);
    5370           2 :         PG_RE_THROW();
    5371             :     }
    5372          82 :     PG_END_TRY();
    5373             : 
    5374          82 :     ReleaseConnection(conn);
    5375             : 
    5376             :     /* We assume that we have no dead tuple. */
    5377          82 :     *totaldeadrows = 0.0;
    5378             : 
    5379             :     /*
    5380             :      * Without sampling, we've retrieved all living tuples from foreign
    5381             :      * server, so report that as totalrows.  Otherwise use the reltuples
    5382             :      * estimate we got from the remote side.
    5383             :      */
    5384          82 :     if (method == ANALYZE_SAMPLE_OFF)
    5385          82 :         *totalrows = astate.samplerows;
    5386             :     else
    5387           0 :         *totalrows = reltuples;
    5388             : 
    5389             :     /*
    5390             :      * Emit some interesting relation info
    5391             :      */
    5392          82 :     ereport(elevel,
    5393             :             (errmsg("\"%s\": table contains %.0f rows, %d rows in sample",
    5394             :                     RelationGetRelationName(relation),
    5395             :                     *totalrows, astate.numrows)));
    5396             : 
    5397          82 :     return astate.numrows;
    5398             : }
    5399             : 
    5400             : /*
    5401             :  * Collect sample rows from the result of query.
    5402             :  *   - Use all tuples in sample until target # of samples are collected.
    5403             :  *   - Subsequently, replace already-sampled tuples randomly.
    5404             :  */
    5405             : static void
    5406       35456 : analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
    5407             : {
    5408       35456 :     int         targrows = astate->targrows;
    5409             :     int         pos;            /* array index to store tuple in */
    5410             :     MemoryContext oldcontext;
    5411             : 
    5412             :     /* Always increment sample row counter. */
    5413       35456 :     astate->samplerows += 1;
    5414             : 
    5415             :     /*
    5416             :      * Determine the slot where this sample row should be stored.  Set pos to
    5417             :      * negative value to indicate the row should be skipped.
    5418             :      */
    5419       35456 :     if (astate->numrows < targrows)
    5420             :     {
    5421             :         /* First targrows rows are always included into the sample */
    5422       35456 :         pos = astate->numrows++;
    5423             :     }
    5424             :     else
    5425             :     {
    5426             :         /*
    5427             :          * Now we start replacing tuples in the sample until we reach the end
    5428             :          * of the relation.  Same algorithm as in acquire_sample_rows in
    5429             :          * analyze.c; see Jeff Vitter's paper.
    5430             :          */
    5431           0 :         if (astate->rowstoskip < 0)
    5432           0 :             astate->rowstoskip = reservoir_get_next_S(&astate->rstate, astate->samplerows, targrows);
    5433             : 
    5434           0 :         if (astate->rowstoskip <= 0)
    5435             :         {
    5436             :             /* Choose a random reservoir element to replace. */
    5437           0 :             pos = (int) (targrows * sampler_random_fract(&astate->rstate.randstate));
    5438             :             Assert(pos >= 0 && pos < targrows);
    5439           0 :             heap_freetuple(astate->rows[pos]);
    5440             :         }
    5441             :         else
    5442             :         {
    5443             :             /* Skip this tuple. */
    5444           0 :             pos = -1;
    5445             :         }
    5446             : 
    5447           0 :         astate->rowstoskip -= 1;
    5448             :     }
    5449             : 
    5450       35456 :     if (pos >= 0)
    5451             :     {
    5452             :         /*
    5453             :          * Create sample tuple from current result row, and store it in the
    5454             :          * position determined above.  The tuple has to be created in anl_cxt.
    5455             :          */
    5456       35456 :         oldcontext = MemoryContextSwitchTo(astate->anl_cxt);
    5457             : 
    5458       35456 :         astate->rows[pos] = make_tuple_from_result_row(res, row,
    5459             :                                                        astate->rel,
    5460             :                                                        astate->attinmeta,
    5461             :                                                        astate->retrieved_attrs,
    5462             :                                                        NULL,
    5463             :                                                        astate->temp_cxt);
    5464             : 
    5465       35454 :         MemoryContextSwitchTo(oldcontext);
    5466             :     }
    5467       35454 : }
    5468             : 
    5469             : /*
    5470             :  * Import a foreign schema
    5471             :  */
    5472             : static List *
    5473          20 : postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
    5474             : {
    5475          20 :     List       *commands = NIL;
    5476          20 :     bool        import_collate = true;
    5477          20 :     bool        import_default = false;
    5478          20 :     bool        import_generated = true;
    5479          20 :     bool        import_not_null = true;
    5480             :     ForeignServer *server;
    5481             :     UserMapping *mapping;
    5482             :     PGconn     *conn;
    5483             :     StringInfoData buf;
    5484          20 :     PGresult   *volatile res = NULL;
    5485             :     int         numrows,
    5486             :                 i;
    5487             :     ListCell   *lc;
    5488             : 
    5489             :     /* Parse statement options */
    5490          28 :     foreach(lc, stmt->options)
    5491             :     {
    5492           8 :         DefElem    *def = (DefElem *) lfirst(lc);
    5493             : 
    5494           8 :         if (strcmp(def->defname, "import_collate") == 0)
    5495           2 :             import_collate = defGetBoolean(def);
    5496           6 :         else if (strcmp(def->defname, "import_default") == 0)
    5497           2 :             import_default = defGetBoolean(def);
    5498           4 :         else if (strcmp(def->defname, "import_generated") == 0)
    5499           2 :             import_generated = defGetBoolean(def);
    5500           2 :         else if (strcmp(def->defname, "import_not_null") == 0)
    5501           2 :             import_not_null = defGetBoolean(def);
    5502             :         else
    5503           0 :             ereport(ERROR,
    5504             :                     (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
    5505             :                      errmsg("invalid option \"%s\"", def->defname)));
    5506             :     }
    5507             : 
    5508             :     /*
    5509             :      * Get connection to the foreign server.  Connection manager will
    5510             :      * establish new connection if necessary.
    5511             :      */
    5512          20 :     server = GetForeignServer(serverOid);
    5513          20 :     mapping = GetUserMapping(GetUserId(), server->serverid);
    5514          20 :     conn = GetConnection(mapping, false, NULL);
    5515             : 
    5516             :     /* Don't attempt to import collation if remote server hasn't got it */
    5517          20 :     if (PQserverVersion(conn) < 90100)
    5518           0 :         import_collate = false;
    5519             : 
    5520             :     /* Create workspace for strings */
    5521          20 :     initStringInfo(&buf);
    5522             : 
    5523             :     /* In what follows, do not risk leaking any PGresults. */
    5524          20 :     PG_TRY();
    5525             :     {
    5526             :         /* Check that the schema really exists */
    5527          20 :         appendStringInfoString(&buf, "SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = ");
    5528          20 :         deparseStringLiteral(&buf, stmt->remote_schema);
    5529             : 
    5530          20 :         res = pgfdw_exec_query(conn, buf.data, NULL);
    5531          20 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
    5532           0 :             pgfdw_report_error(ERROR, res, conn, false, buf.data);
    5533             : 
    5534          20 :         if (PQntuples(res) != 1)
    5535           2 :             ereport(ERROR,
    5536             :                     (errcode(ERRCODE_FDW_SCHEMA_NOT_FOUND),
    5537             :                      errmsg("schema \"%s\" is not present on foreign server \"%s\"",
    5538             :                             stmt->remote_schema, server->servername)));
    5539             : 
    5540          18 :         PQclear(res);
    5541          18 :         res = NULL;
    5542          18 :         resetStringInfo(&buf);
    5543             : 
    5544             :         /*
    5545             :          * Fetch all table data from this schema, possibly restricted by
    5546             :          * EXCEPT or LIMIT TO.  (We don't actually need to pay any attention
    5547             :          * to EXCEPT/LIMIT TO here, because the core code will filter the
    5548             :          * statements we return according to those lists anyway.  But it
    5549             :          * should save a few cycles to not process excluded tables in the
    5550             :          * first place.)
    5551             :          *
    5552             :          * Import table data for partitions only when they are explicitly
    5553             :          * specified in LIMIT TO clause. Otherwise ignore them and only
    5554             :          * include the definitions of the root partitioned tables to allow
    5555             :          * access to the complete remote data set locally in the schema
    5556             :          * imported.
    5557             :          *
    5558             :          * Note: because we run the connection with search_path restricted to
    5559             :          * pg_catalog, the format_type() and pg_get_expr() outputs will always
    5560             :          * include a schema name for types/functions in other schemas, which
    5561             :          * is what we want.
    5562             :          */
    5563          18 :         appendStringInfoString(&buf,
    5564             :                                "SELECT relname, "
    5565             :                                "  attname, "
    5566             :                                "  format_type(atttypid, atttypmod), "
    5567             :                                "  attnotnull, "
    5568             :                                "  pg_get_expr(adbin, adrelid), ");
    5569             : 
    5570             :         /* Generated columns are supported since Postgres 12 */
    5571          18 :         if (PQserverVersion(conn) >= 120000)
    5572          18 :             appendStringInfoString(&buf,
    5573             :                                    "  attgenerated, ");
    5574             :         else
    5575           0 :             appendStringInfoString(&buf,
    5576             :                                    "  NULL, ");
    5577             : 
    5578          18 :         if (import_collate)
    5579          16 :             appendStringInfoString(&buf,
    5580             :                                    "  collname, "
    5581             :                                    "  collnsp.nspname ");
    5582             :         else
    5583           2 :             appendStringInfoString(&buf,
    5584             :                                    "  NULL, NULL ");
    5585             : 
    5586          18 :         appendStringInfoString(&buf,
    5587             :                                "FROM pg_class c "
    5588             :                                "  JOIN pg_namespace n ON "
    5589             :                                "    relnamespace = n.oid "
    5590             :                                "  LEFT JOIN pg_attribute a ON "
    5591             :                                "    attrelid = c.oid AND attnum > 0 "
    5592             :                                "      AND NOT attisdropped "
    5593             :                                "  LEFT JOIN pg_attrdef ad ON "
    5594             :                                "    adrelid = c.oid AND adnum = attnum ");
    5595             : 
    5596          18 :         if (import_collate)
    5597          16 :             appendStringInfoString(&buf,
    5598             :                                    "  LEFT JOIN pg_collation coll ON "
    5599             :                                    "    coll.oid = attcollation "
    5600             :                                    "  LEFT JOIN pg_namespace collnsp ON "
    5601             :                                    "    collnsp.oid = collnamespace ");
    5602             : 
    5603          18 :         appendStringInfoString(&buf,
    5604             :                                "WHERE c.relkind IN ("
    5605             :                                CppAsString2(RELKIND_RELATION) ","
    5606             :                                CppAsString2(RELKIND_VIEW) ","
    5607             :                                CppAsString2(RELKIND_FOREIGN_TABLE) ","
    5608             :                                CppAsString2(RELKIND_MATVIEW) ","
    5609             :                                CppAsString2(RELKIND_PARTITIONED_TABLE) ") "
    5610             :                                "  AND n.nspname = ");
    5611          18 :         deparseStringLiteral(&buf, stmt->remote_schema);
    5612             : 
    5613             :         /* Partitions are supported since Postgres 10 */
    5614          18 :         if (PQserverVersion(conn) >= 100000 &&
    5615          18 :             stmt->list_type != FDW_IMPORT_SCHEMA_LIMIT_TO)
    5616          10 :             appendStringInfoString(&buf, " AND NOT c.relispartition ");
    5617             : 
    5618             :         /* Apply restrictions for LIMIT TO and EXCEPT */
    5619          18 :         if (stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO ||
    5620          10 :             stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT)
    5621             :         {
    5622          10 :             bool        first_item = true;
    5623             : 
    5624          10 :             appendStringInfoString(&buf, " AND c.relname ");
    5625          10 :             if (stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT)
    5626           2 :                 appendStringInfoString(&buf, "NOT ");
    5627          10 :             appendStringInfoString(&buf, "IN (");
    5628             : 
    5629             :             /* Append list of table names within IN clause */
    5630          30 :             foreach(lc, stmt->table_list)
    5631             :             {
    5632          20 :                 RangeVar   *rv = (RangeVar *) lfirst(lc);
    5633             : 
    5634          20 :                 if (first_item)
    5635          10 :                     first_item = false;
    5636             :                 else
    5637          10 :                     appendStringInfoString(&buf, ", ");
    5638          20 :                 deparseStringLiteral(&buf, rv->relname);
    5639             :             }
    5640          10 :             appendStringInfoChar(&buf, ')');
    5641             :         }
    5642             : 
    5643             :         /* Append ORDER BY at the end of query to ensure output ordering */
    5644          18 :         appendStringInfoString(&buf, " ORDER BY c.relname, a.attnum");
    5645             : 
    5646             :         /* Fetch the data */
    5647          18 :         res = pgfdw_exec_query(conn, buf.data, NULL);
    5648          18 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
    5649           0 :             pgfdw_report_error(ERROR, res, conn, false, buf.data);
    5650             : 
    5651             :         /* Process results */
    5652          18 :         numrows = PQntuples(res);
    5653             :         /* note: incrementation of i happens in inner loop's while() test */
    5654          94 :         for (i = 0; i < numrows;)
    5655             :         {
    5656          76 :             char       *tablename = PQgetvalue(res, i, 0);
    5657          76 :             bool        first_item = true;
    5658             : 
    5659          76 :             resetStringInfo(&buf);
    5660          76 :             appendStringInfo(&buf, "CREATE FOREIGN TABLE %s (\n",
    5661             :                              quote_identifier(tablename));
    5662             : 
    5663             :             /* Scan all rows for this table */
    5664             :             do
    5665             :             {
    5666             :                 char       *attname;
    5667             :                 char       *typename;
    5668             :                 char       *attnotnull;
    5669             :                 char       *attgenerated;
    5670             :                 char       *attdefault;
    5671             :                 char       *collname;
    5672             :                 char       *collnamespace;
    5673             : 
    5674             :                 /* If table has no columns, we'll see nulls here */
    5675         150 :                 if (PQgetisnull(res, i, 1))
    5676          10 :                     continue;
    5677             : 
    5678         140 :                 attname = PQgetvalue(res, i, 1);
    5679         140 :                 typename = PQgetvalue(res, i, 2);
    5680         140 :                 attnotnull = PQgetvalue(res, i, 3);
    5681         140 :                 attdefault = PQgetisnull(res, i, 4) ? NULL :
    5682          30 :                     PQgetvalue(res, i, 4);
    5683         140 :                 attgenerated = PQgetisnull(res, i, 5) ? NULL :
    5684         140 :                     PQgetvalue(res, i, 5);
    5685         140 :                 collname = PQgetisnull(res, i, 6) ? NULL :
    5686          38 :                     PQgetvalue(res, i, 6);
    5687         140 :                 collnamespace = PQgetisnull(res, i, 7) ? NULL :
    5688          38 :                     PQgetvalue(res, i, 7);
    5689             : 
    5690         140 :                 if (first_item)
    5691          66 :                     first_item = false;
    5692             :                 else
    5693          74 :                     appendStringInfoString(&buf, ",\n");
    5694             : 
    5695             :                 /* Print column name and type */
    5696         140 :                 appendStringInfo(&buf, "  %s %s",
    5697             :                                  quote_identifier(attname),
    5698             :                                  typename);
    5699             : 
    5700             :                 /*
    5701             :                  * Add column_name option so that renaming the foreign table's
    5702             :                  * column doesn't break the association to the underlying
    5703             :                  * column.
    5704             :                  */
    5705         140 :                 appendStringInfoString(&buf, " OPTIONS (column_name ");
    5706         140 :                 deparseStringLiteral(&buf, attname);
    5707         140 :                 appendStringInfoChar(&buf, ')');
    5708             : 
    5709             :                 /* Add COLLATE if needed */
    5710         140 :                 if (import_collate && collname != NULL && collnamespace != NULL)
    5711          38 :                     appendStringInfo(&buf, " COLLATE %s.%s",
    5712             :                                      quote_identifier(collnamespace),
    5713             :                                      quote_identifier(collname));
    5714             : 
    5715             :                 /* Add DEFAULT if needed */
    5716         140 :                 if (import_default && attdefault != NULL &&
    5717           6 :                     (!attgenerated || !attgenerated[0]))
    5718           4 :                     appendStringInfo(&buf, " DEFAULT %s", attdefault);
    5719             : 
    5720             :                 /* Add GENERATED if needed */
    5721         140 :                 if (import_generated && attgenerated != NULL &&
    5722         114 :                     attgenerated[0] == ATTRIBUTE_GENERATED_STORED)
    5723             :                 {
    5724             :                     Assert(attdefault != NULL);
    5725           8 :                     appendStringInfo(&buf,
    5726             :                                      " GENERATED ALWAYS AS (%s) STORED",
    5727             :                                      attdefault);
    5728             :                 }
    5729             : 
    5730             :                 /* Add NOT NULL if needed */
    5731         140 :                 if (import_not_null && attnotnull[0] == 't')
    5732           8 :                     appendStringInfoString(&buf, " NOT NULL");
    5733             :             }
    5734         150 :             while (++i < numrows &&
    5735         132 :                    strcmp(PQgetvalue(res, i, 0), tablename) == 0);
    5736             : 
    5737             :             /*
    5738             :              * Add server name and table-level options.  We specify remote
    5739             :              * schema and table name as options (the latter to ensure that
    5740             :              * renaming the foreign table doesn't break the association).
    5741             :              */
    5742          76 :             appendStringInfo(&buf, "\n) SERVER %s\nOPTIONS (",
    5743          76 :                              quote_identifier(server->servername));
    5744             : 
    5745          76 :             appendStringInfoString(&buf, "schema_name ");
    5746          76 :             deparseStringLiteral(&buf, stmt->remote_schema);
    5747          76 :             appendStringInfoString(&buf, ", table_name ");
    5748          76 :             deparseStringLiteral(&buf, tablename);
    5749             : 
    5750          76 :             appendStringInfoString(&buf, ");");
    5751             : 
    5752          76 :             commands = lappend(commands, pstrdup(buf.data));
    5753             :         }
    5754             :     }
    5755           2 :     PG_FINALLY();
    5756             :     {
    5757          20 :         PQclear(res);
    5758             :     }
    5759          20 :     PG_END_TRY();
    5760             : 
    5761          18 :     ReleaseConnection(conn);
    5762             : 
    5763          18 :     return commands;
    5764             : }
    5765             : 
    5766             : /*
    5767             :  * Check if reltarget is safe enough to push down semi-join.  Reltarget is not
    5768             :  * safe, if it contains references to inner rel relids, which do not belong to
    5769             :  * outer rel.
    5770             :  */
    5771             : static bool
    5772         128 : semijoin_target_ok(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel)
    5773             : {
    5774             :     List       *vars;
    5775             :     ListCell   *lc;
    5776         128 :     bool        ok = true;
    5777             : 
    5778             :     Assert(joinrel->reltarget);
    5779             : 
    5780         128 :     vars = pull_var_clause((Node *) joinrel->reltarget->exprs, PVC_INCLUDE_PLACEHOLDERS);
    5781             : 
    5782         886 :     foreach(lc, vars)
    5783             :     {
    5784         788 :         Var        *var = (Var *) lfirst(lc);
    5785             : 
    5786         788 :         if (!IsA(var, Var))
    5787           0 :             continue;
    5788             : 
    5789         788 :         if (bms_is_member(var->varno, innerrel->relids))
    5790             :         {
    5791             :             /*
    5792             :              * The planner can create semi-join, which refers to inner rel
    5793             :              * vars in its target list. However, we deparse semi-join as an
    5794             :              * exists() subquery, so can't handle references to inner rel in
    5795             :              * the target list.
    5796             :              */
    5797             :             Assert(!bms_is_member(var->varno, outerrel->relids));
    5798          30 :             ok = false;
    5799          30 :             break;
    5800             :         }
    5801             :     }
    5802         128 :     return ok;
    5803             : }
    5804             : 
    5805             : /*
    5806             :  * Assess whether the join between inner and outer relations can be pushed down
    5807             :  * to the foreign server. As a side effect, save information we obtain in this
    5808             :  * function to PgFdwRelationInfo passed in.
    5809             :  */
    5810             : static bool
    5811         784 : foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
    5812             :                 RelOptInfo *outerrel, RelOptInfo *innerrel,
    5813             :                 JoinPathExtraData *extra)
    5814             : {
    5815             :     PgFdwRelationInfo *fpinfo;
    5816             :     PgFdwRelationInfo *fpinfo_o;
    5817             :     PgFdwRelationInfo *fpinfo_i;
    5818             :     ListCell   *lc;
    5819             :     List       *joinclauses;
    5820             : 
    5821             :     /*
    5822             :      * We support pushing down INNER, LEFT, RIGHT, FULL OUTER and SEMI joins.
    5823             :      * Constructing queries representing ANTI joins is hard, hence not
    5824             :      * considered right now.
    5825             :      */
    5826         784 :     if (jointype != JOIN_INNER && jointype != JOIN_LEFT &&
    5827         258 :         jointype != JOIN_RIGHT && jointype != JOIN_FULL &&
    5828             :         jointype != JOIN_SEMI)
    5829          38 :         return false;
    5830             : 
    5831             :     /*
    5832             :      * We can't push down semi-join if its reltarget is not safe
    5833             :      */
    5834         746 :     if ((jointype == JOIN_SEMI) && !semijoin_target_ok(root, joinrel, outerrel, innerrel))
    5835          30 :         return false;
    5836             : 
    5837             :     /*
    5838             :      * If either of the joining relations is marked as unsafe to pushdown, the
    5839             :      * join can not be pushed down.
    5840             :      */
    5841         716 :     fpinfo = (PgFdwRelationInfo *) joinrel->fdw_private;
    5842         716 :     fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private;
    5843         716 :     fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private;
    5844         716 :     if (!fpinfo_o || !fpinfo_o->pushdown_safe ||
    5845         706 :         !fpinfo_i || !fpinfo_i->pushdown_safe)
    5846          10 :         return false;
    5847             : 
    5848             :     /*
    5849             :      * If joining relations have local conditions, those conditions are
    5850             :      * required to be applied before joining the relations. Hence the join can
    5851             :      * not be pushed down.
    5852             :      */
    5853         706 :     if (fpinfo_o->local_conds || fpinfo_i->local_conds)
    5854          18 :         return false;
    5855             : 
    5856             :     /*
    5857             :      * Merge FDW options.  We might be tempted to do this after we have deemed
    5858             :      * the foreign join to be OK.  But we must do this beforehand so that we
    5859             :      * know which quals can be evaluated on the foreign server, which might
    5860             :      * depend on shippable_extensions.
    5861             :      */
    5862         688 :     fpinfo->server = fpinfo_o->server;
    5863         688 :     merge_fdw_options(fpinfo, fpinfo_o, fpinfo_i);
    5864             : 
    5865             :     /*
    5866             :      * Separate restrict list into join quals and pushed-down (other) quals.
    5867             :      *
    5868             :      * Join quals belonging to an outer join must all be shippable, else we
    5869             :      * cannot execute the join remotely.  Add such quals to 'joinclauses'.
    5870             :      *
    5871             :      * Add other quals to fpinfo->remote_conds if they are shippable, else to
    5872             :      * fpinfo->local_conds.  In an inner join it's okay to execute conditions
    5873             :      * either locally or remotely; the same is true for pushed-down conditions
    5874             :      * at an outer join.
    5875             :      *
    5876             :      * Note we might return failure after having already scribbled on
    5877             :      * fpinfo->remote_conds and fpinfo->local_conds.  That's okay because we
    5878             :      * won't consult those lists again if we deem the join unshippable.
    5879             :      */
    5880         688 :     joinclauses = NIL;
    5881        1370 :     foreach(lc, extra->restrictlist)
    5882             :     {
    5883         688 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    5884         688 :         bool        is_remote_clause = is_foreign_expr(root, joinrel,
    5885             :                                                        rinfo->clause);
    5886             : 
    5887         688 :         if (IS_OUTER_JOIN(jointype) &&
    5888         258 :             !RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids))
    5889             :         {
    5890         226 :             if (!is_remote_clause)
    5891           6 :                 return false;
    5892         220 :             joinclauses = lappend(joinclauses, rinfo);
    5893             :         }
    5894             :         else
    5895             :         {
    5896         462 :             if (is_remote_clause)
    5897         438 :                 fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
    5898             :             else
    5899          24 :                 fpinfo->local_conds = lappend(fpinfo->local_conds, rinfo);
    5900             :         }
    5901             :     }
    5902             : 
    5903             :     /*
    5904             :      * deparseExplicitTargetList() isn't smart enough to handle anything other
    5905             :      * than a Var.  In particular, if there's some PlaceHolderVar that would
    5906             :      * need to be evaluated within this join tree (because there's an upper
    5907             :      * reference to a quantity that may go to NULL as a result of an outer
    5908             :      * join), then we can't try to push the join down because we'll fail when
    5909             :      * we get to deparseExplicitTargetList().  However, a PlaceHolderVar that
    5910             :      * needs to be evaluated *at the top* of this join tree is OK, because we
    5911             :      * can do that locally after fetching the results from the remote side.
    5912             :      */
    5913         688 :     foreach(lc, root->placeholder_list)
    5914             :     {
    5915          22 :         PlaceHolderInfo *phinfo = lfirst(lc);
    5916             :         Relids      relids;
    5917             : 
    5918             :         /* PlaceHolderInfo refers to parent relids, not child relids. */
    5919          22 :         relids = IS_OTHER_REL(joinrel) ?
    5920          44 :             joinrel->top_parent_relids : joinrel->relids;
    5921             : 
    5922          44 :         if (bms_is_subset(phinfo->ph_eval_at, relids) &&
    5923          22 :             bms_nonempty_difference(relids, phinfo->ph_eval_at))
    5924          16 :             return false;
    5925             :     }
    5926             : 
    5927             :     /* Save the join clauses, for later use. */
    5928         666 :     fpinfo->joinclauses = joinclauses;
    5929             : 
    5930         666 :     fpinfo->outerrel = outerrel;
    5931         666 :     fpinfo->innerrel = innerrel;
    5932         666 :     fpinfo->jointype = jointype;
    5933             : 
    5934             :     /*
    5935             :      * By default, both the input relations are not required to be deparsed as
    5936             :      * subqueries, but there might be some relations covered by the input
    5937             :      * relations that are required to be deparsed as subqueries, so save the
    5938             :      * relids of those relations for later use by the deparser.
    5939             :      */
    5940         666 :     fpinfo->make_outerrel_subquery = false;
    5941         666 :     fpinfo->make_innerrel_subquery = false;
    5942             :     Assert(bms_is_subset(fpinfo_o->lower_subquery_rels, outerrel->relids));
    5943             :     Assert(bms_is_subset(fpinfo_i->lower_subquery_rels, innerrel->relids));
    5944        1332 :     fpinfo->lower_subquery_rels = bms_union(fpinfo_o->lower_subquery_rels,
    5945         666 :                                             fpinfo_i->lower_subquery_rels);
    5946        1332 :     fpinfo->hidden_subquery_rels = bms_union(fpinfo_o->hidden_subquery_rels,
    5947         666 :                                              fpinfo_i->hidden_subquery_rels);
    5948             : 
    5949             :     /*
    5950             :      * Pull the other remote conditions from the joining relations into join
    5951             :      * clauses or other remote clauses (remote_conds) of this relation
    5952             :      * wherever possible. This avoids building subqueries at every join step.
    5953             :      *
    5954             :      * For an inner join, clauses from both the relations are added to the
    5955             :      * other remote clauses. For LEFT and RIGHT OUTER join, the clauses from
    5956             :      * the outer side are added to remote_conds since those can be evaluated
    5957             :      * after the join is evaluated. The clauses from inner side are added to
    5958             :      * the joinclauses, since they need to be evaluated while constructing the
    5959             :      * join.
    5960             :      *
    5961             :      * For SEMI-JOIN clauses from inner relation can not be added to
    5962             :      * remote_conds, but should be treated as join clauses (as they are
    5963             :      * deparsed to EXISTS subquery, where inner relation can be referred). A
    5964             :      * list of relation ids, which can't be referred to from higher levels, is
    5965             :      * preserved as a hidden_subquery_rels list.
    5966             :      *
    5967             :      * For a FULL OUTER JOIN, the other clauses from either relation can not
    5968             :      * be added to the joinclauses or remote_conds, since each relation acts
    5969             :      * as an outer relation for the other.
    5970             :      *
    5971             :      * The joining sides can not have local conditions, thus no need to test
    5972             :      * shippability of the clauses being pulled up.
    5973             :      */
    5974         666 :     switch (jointype)
    5975             :     {
    5976         374 :         case JOIN_INNER:
    5977         748 :             fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
    5978         374 :                                                fpinfo_i->remote_conds);
    5979         748 :             fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
    5980         374 :                                                fpinfo_o->remote_conds);
    5981         374 :             break;
    5982             : 
    5983         120 :         case JOIN_LEFT:
    5984             : 
    5985             :             /*
    5986             :              * When semi-join is involved in the inner or outer part of the
    5987             :              * left join, it's deparsed as a subquery, and we can't refer to
    5988             :              * its vars on the upper level.
    5989             :              */
    5990         120 :             if (bms_is_empty(fpinfo_i->hidden_subquery_rels))
    5991         112 :                 fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
    5992         112 :                                                   fpinfo_i->remote_conds);
    5993         120 :             if (bms_is_empty(fpinfo_o->hidden_subquery_rels))
    5994         120 :                 fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
    5995         120 :                                                    fpinfo_o->remote_conds);
    5996         120 :             break;
    5997             : 
    5998           0 :         case JOIN_RIGHT:
    5999             : 
    6000             :             /*
    6001             :              * When semi-join is involved in the inner or outer part of the
    6002             :              * right join, it's deparsed as a subquery, and we can't refer to
    6003             :              * its vars on the upper level.
    6004             :              */
    6005           0 :             if (bms_is_empty(fpinfo_o->hidden_subquery_rels))
    6006           0 :                 fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
    6007           0 :                                                   fpinfo_o->remote_conds);
    6008           0 :             if (bms_is_empty(fpinfo_i->hidden_subquery_rels))
    6009           0 :                 fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
    6010           0 :                                                    fpinfo_i->remote_conds);
    6011           0 :             break;
    6012             : 
    6013          88 :         case JOIN_SEMI:
    6014         176 :             fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
    6015          88 :                                               fpinfo_i->remote_conds);
    6016         176 :             fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
    6017          88 :                                               fpinfo->remote_conds);
    6018          88 :             fpinfo->remote_conds = list_copy(fpinfo_o->remote_conds);
    6019         176 :             fpinfo->hidden_subquery_rels = bms_union(fpinfo->hidden_subquery_rels,
    6020          88 :                                                      innerrel->relids);
    6021          88 :             break;
    6022             : 
    6023          84 :         case JOIN_FULL:
    6024             : 
    6025             :             /*
    6026             :              * In this case, if any of the input relations has conditions, we
    6027             :              * need to deparse that relation as a subquery so that the
    6028             :              * conditions can be evaluated before the join.  Remember it in
    6029             :              * the fpinfo of this relation so that the deparser can take
    6030             :              * appropriate action.  Also, save the relids of base relations
    6031             :              * covered by that relation for later use by the deparser.
    6032             :              */
    6033          84 :             if (fpinfo_o->remote_conds)
    6034             :             {
    6035          28 :                 fpinfo->make_outerrel_subquery = true;
    6036          28 :                 fpinfo->lower_subquery_rels =
    6037          28 :                     bms_add_members(fpinfo->lower_subquery_rels,
    6038          28 :                                     outerrel->relids);
    6039             :             }
    6040          84 :             if (fpinfo_i->remote_conds)
    6041             :             {
    6042          28 :                 fpinfo->make_innerrel_subquery = true;
    6043          28 :                 fpinfo->lower_subquery_rels =
    6044          28 :                     bms_add_members(fpinfo->lower_subquery_rels,
    6045          28 :                                     innerrel->relids);
    6046             :             }
    6047          84 :             break;
    6048             : 
    6049           0 :         default:
    6050             :             /* Should not happen, we have just checked this above */
    6051           0 :             elog(ERROR, "unsupported join type %d", jointype);
    6052             :     }
    6053             : 
    6054             :     /*
    6055             :      * For an inner join, all restrictions can be treated alike. Treating the
    6056             :      * pushed down conditions as join conditions allows a top level full outer
    6057             :      * join to be deparsed without requiring subqueries.
    6058             :      */
    6059         666 :     if (jointype == JOIN_INNER)
    6060             :     {
    6061             :         Assert(!fpinfo->joinclauses);
    6062         374 :         fpinfo->joinclauses = fpinfo->remote_conds;
    6063         374 :         fpinfo->remote_conds = NIL;
    6064             :     }
    6065         292 :     else if (jointype == JOIN_LEFT || jointype == JOIN_RIGHT || jointype == JOIN_FULL)
    6066             :     {
    6067             :         /*
    6068             :          * Conditions, generated from semi-joins, should be evaluated before
    6069             :          * LEFT/RIGHT/FULL join.
    6070             :          */
    6071         204 :         if (!bms_is_empty(fpinfo_o->hidden_subquery_rels))
    6072             :         {
    6073           0 :             fpinfo->make_outerrel_subquery = true;
    6074           0 :             fpinfo->lower_subquery_rels = bms_add_members(fpinfo->lower_subquery_rels, outerrel->relids);
    6075             :         }
    6076             : 
    6077         204 :         if (!bms_is_empty(fpinfo_i->hidden_subquery_rels))
    6078             :         {
    6079           8 :             fpinfo->make_innerrel_subquery = true;
    6080           8 :             fpinfo->lower_subquery_rels = bms_add_members(fpinfo->lower_subquery_rels, innerrel->relids);
    6081             :         }
    6082             :     }
    6083             : 
    6084             :     /* Mark that this join can be pushed down safely */
    6085         666 :     fpinfo->pushdown_safe = true;
    6086             : 
    6087             :     /* Get user mapping */
    6088         666 :     if (fpinfo->use_remote_estimate)
    6089             :     {
    6090         442 :         if (fpinfo_o->use_remote_estimate)
    6091         310 :             fpinfo->user = fpinfo_o->user;
    6092             :         else
    6093         132 :             fpinfo->user = fpinfo_i->user;
    6094             :     }
    6095             :     else
    6096         224 :         fpinfo->user = NULL;
    6097             : 
    6098             :     /*
    6099             :      * Set # of retrieved rows and cached relation costs to some negative
    6100             :      * value, so that we can detect when they are set to some sensible values,
    6101             :      * during one (usually the first) of the calls to estimate_path_cost_size.
    6102             :      */
    6103         666 :     fpinfo->retrieved_rows = -1;
    6104         666 :     fpinfo->rel_startup_cost = -1;
    6105         666 :     fpinfo->rel_total_cost = -1;
    6106             : 
    6107             :     /*
    6108             :      * Set the string describing this join relation to be used in EXPLAIN
    6109             :      * output of corresponding ForeignScan.  Note that the decoration we add
    6110             :      * to the base relation names mustn't include any digits, or it'll confuse
    6111             :      * postgresExplainForeignScan.
    6112             :      */
    6113         666 :     fpinfo->relation_name = psprintf("(%s) %s JOIN (%s)",
    6114             :                                      fpinfo_o->relation_name,
    6115             :                                      get_jointype_name(fpinfo->jointype),
    6116             :                                      fpinfo_i->relation_name);
    6117             : 
    6118             :     /*
    6119             :      * Set the relation index.  This is defined as the position of this
    6120             :      * joinrel in the join_rel_list list plus the length of the rtable list.
    6121             :      * Note that since this joinrel is at the end of the join_rel_list list
    6122             :      * when we are called, we can get the position by list_length.
    6123             :      */
    6124             :     Assert(fpinfo->relation_index == 0); /* shouldn't be set yet */
    6125         666 :     fpinfo->relation_index =
    6126         666 :         list_length(root->parse->rtable) + list_length(root->join_rel_list);
    6127             : 
    6128         666 :     return true;
    6129             : }
    6130             : 
    6131             : static void
    6132        3002 : add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
    6133             :                                 Path *epq_path, List *restrictlist)
    6134             : {
    6135        3002 :     List       *useful_pathkeys_list = NIL; /* List of all pathkeys */
    6136             :     ListCell   *lc;
    6137             : 
    6138        3002 :     useful_pathkeys_list = get_useful_pathkeys_for_relation(root, rel);
    6139             : 
    6140             :     /*
    6141             :      * Before creating sorted paths, arrange for the passed-in EPQ path, if
    6142             :      * any, to return columns needed by the parent ForeignScan node so that
    6143             :      * they will propagate up through Sort nodes injected below, if necessary.
    6144             :      */
    6145        3002 :     if (epq_path != NULL && useful_pathkeys_list != NIL)
    6146             :     {
    6147          64 :         PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
    6148          64 :         PathTarget *target = copy_pathtarget(epq_path->pathtarget);
    6149             : 
    6150             :         /* Include columns required for evaluating PHVs in the tlist. */
    6151          64 :         add_new_columns_to_pathtarget(target,
    6152          64 :                                       pull_var_clause((Node *) target->exprs,
    6153             :                                                       PVC_RECURSE_PLACEHOLDERS));
    6154             : 
    6155             :         /* Include columns required for evaluating the local conditions. */
    6156          70 :         foreach(lc, fpinfo->local_conds)
    6157             :         {
    6158           6 :             RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    6159             : 
    6160           6 :             add_new_columns_to_pathtarget(target,
    6161           6 :                                           pull_var_clause((Node *) rinfo->clause,
    6162             :                                                           PVC_RECURSE_PLACEHOLDERS));
    6163             :         }
    6164             : 
    6165             :         /*
    6166             :          * If we have added any new columns, adjust the tlist of the EPQ path.
    6167             :          *
    6168             :          * Note: the plan created using this path will only be used to execute
    6169             :          * EPQ checks, where accuracy of the plan cost and width estimates
    6170             :          * would not be important, so we do not do set_pathtarget_cost_width()
    6171             :          * for the new pathtarget here.  See also postgresGetForeignPlan().
    6172             :          */
    6173          64 :         if (list_length(target->exprs) > list_length(epq_path->pathtarget->exprs))
    6174             :         {
    6175             :             /* The EPQ path is a join path, so it is projection-capable. */
    6176             :             Assert(is_projection_capable_path(epq_path));
    6177             : 
    6178             :             /*
    6179             :              * Use create_projection_path() here, so as to avoid modifying it
    6180             :              * in place.
    6181             :              */
    6182           8 :             epq_path = (Path *) create_projection_path(root,
    6183             :                                                        rel,
    6184             :                                                        epq_path,
    6185             :                                                        target);
    6186             :         }
    6187             :     }
    6188             : 
    6189             :     /* Create one path for each set of pathkeys we found above. */
    6190        4378 :     foreach(lc, useful_pathkeys_list)
    6191             :     {
    6192             :         double      rows;
    6193             :         int         width;
    6194             :         int         disabled_nodes;
    6195             :         Cost        startup_cost;
    6196             :         Cost        total_cost;
    6197        1376 :         List       *useful_pathkeys = lfirst(lc);
    6198             :         Path       *sorted_epq_path;
    6199             : 
    6200        1376 :         estimate_path_cost_size(root, rel, NIL, useful_pathkeys, NULL,
    6201             :                                 &rows, &width, &disabled_nodes,
    6202             :                                 &startup_cost, &total_cost);
    6203             : 
    6204             :         /*
    6205             :          * The EPQ path must be at least as well sorted as the path itself, in
    6206             :          * case it gets used as input to a mergejoin.
    6207             :          */
    6208        1376 :         sorted_epq_path = epq_path;
    6209        1376 :         if (sorted_epq_path != NULL &&
    6210          64 :             !pathkeys_contained_in(useful_pathkeys,
    6211             :                                    sorted_epq_path->pathkeys))
    6212             :             sorted_epq_path = (Path *)
    6213          52 :                 create_sort_path(root,
    6214             :                                  rel,
    6215             :                                  sorted_epq_path,
    6216             :                                  useful_pathkeys,
    6217             :                                  -1.0);
    6218             : 
    6219        1376 :         if (IS_SIMPLE_REL(rel))
    6220         842 :             add_path(rel, (Path *)
    6221         842 :                      create_foreignscan_path(root, rel,
    6222             :                                              NULL,
    6223             :                                              rows,
    6224             :                                              disabled_nodes,
    6225             :                                              startup_cost,
    6226             :                                              total_cost,
    6227             :                                              useful_pathkeys,
    6228             :                                              rel->lateral_relids,
    6229             :                                              sorted_epq_path,
    6230             :                                              NIL,   /* no fdw_restrictinfo
    6231             :                                                      * list */
    6232             :                                              NIL));
    6233             :         else
    6234         534 :             add_path(rel, (Path *)
    6235         534 :                      create_foreign_join_path(root, rel,
    6236             :                                               NULL,
    6237             :                                               rows,
    6238             :                                               disabled_nodes,
    6239             :                                               startup_cost,
    6240             :                                               total_cost,
    6241             :                                               useful_pathkeys,
    6242             :                                               rel->lateral_relids,
    6243             :                                               sorted_epq_path,
    6244             :                                               restrictlist,
    6245             :                                               NIL));
    6246             :     }
    6247        3002 : }
    6248             : 
    6249             : /*
    6250             :  * Parse options from foreign server and apply them to fpinfo.
    6251             :  *
    6252             :  * New options might also require tweaking merge_fdw_options().
    6253             :  */
    6254             : static void
    6255        2340 : apply_server_options(PgFdwRelationInfo *fpinfo)
    6256             : {
    6257             :     ListCell   *lc;
    6258             : 
    6259        9876 :     foreach(lc, fpinfo->server->options)
    6260             :     {
    6261        7536 :         DefElem    *def = (DefElem *) lfirst(lc);
    6262             : 
    6263        7536 :         if (strcmp(def->defname, "use_remote_estimate") == 0)
    6264         208 :             fpinfo->use_remote_estimate = defGetBoolean(def);
    6265        7328 :         else if (strcmp(def->defname, "fdw_startup_cost") == 0)
    6266          12 :             (void) parse_real(defGetString(def), &fpinfo->fdw_startup_cost, 0,
    6267             :                               NULL);
    6268        7316 :         else if (strcmp(def->defname, "fdw_tuple_cost") == 0)
    6269           4 :             (void) parse_real(defGetString(def), &fpinfo->fdw_tuple_cost, 0,
    6270             :                               NULL);
    6271        7312 :         else if (strcmp(def->defname, "extensions") == 0)
    6272        1838 :             fpinfo->shippable_extensions =
    6273        1838 :                 ExtractExtensionList(defGetString(def), false);
    6274        5474 :         else if (strcmp(def->defname, "fetch_size") == 0)
    6275           0 :             (void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL);
    6276        5474 :         else if (strcmp(def->defname, "async_capable") == 0)
    6277         242 :             fpinfo->async_capable = defGetBoolean(def);
    6278             :     }
    6279        2340 : }
    6280             : 
    6281             : /*
    6282             :  * Parse options from foreign table and apply them to fpinfo.
    6283             :  *
    6284             :  * New options might also require tweaking merge_fdw_options().
    6285             :  */
    6286             : static void
    6287        2340 : apply_table_options(PgFdwRelationInfo *fpinfo)
    6288             : {
    6289             :     ListCell   *lc;
    6290             : 
    6291        6844 :     foreach(lc, fpinfo->table->options)
    6292             :     {
    6293        4504 :         DefElem    *def = (DefElem *) lfirst(lc);
    6294             : 
    6295        4504 :         if (strcmp(def->defname, "use_remote_estimate") == 0)
    6296         694 :             fpinfo->use_remote_estimate = defGetBoolean(def);
    6297        3810 :         else if (strcmp(def->defname, "fetch_size") == 0)
    6298           0 :             (void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL);
    6299        3810 :         else if (strcmp(def->defname, "async_capable") == 0)
    6300           0 :             fpinfo->async_capable = defGetBoolean(def);
    6301             :     }
    6302        2340 : }
    6303             : 
    6304             : /*
    6305             :  * Merge FDW options from input relations into a new set of options for a join
    6306             :  * or an upper rel.
    6307             :  *
    6308             :  * For a join relation, FDW-specific information about the inner and outer
    6309             :  * relations is provided using fpinfo_i and fpinfo_o.  For an upper relation,
    6310             :  * fpinfo_o provides the information for the input relation; fpinfo_i is
    6311             :  * expected to NULL.
    6312             :  */
    6313             : static void
    6314        1576 : merge_fdw_options(PgFdwRelationInfo *fpinfo,
    6315             :                   const PgFdwRelationInfo *fpinfo_o,
    6316             :                   const PgFdwRelationInfo *fpinfo_i)
    6317             : {
    6318             :     /* We must always have fpinfo_o. */
    6319             :     Assert(fpinfo_o);
    6320             : 
    6321             :     /* fpinfo_i may be NULL, but if present the servers must both match. */
    6322             :     Assert(!fpinfo_i ||
    6323             :            fpinfo_i->server->serverid == fpinfo_o->server->serverid);
    6324             : 
    6325             :     /*
    6326             :      * Copy the server specific FDW options.  (For a join, both relations come
    6327             :      * from the same server, so the server options should have the same value
    6328             :      * for both relations.)
    6329             :      */
    6330        1576 :     fpinfo->fdw_startup_cost = fpinfo_o->fdw_startup_cost;
    6331        1576 :     fpinfo->fdw_tuple_cost = fpinfo_o->fdw_tuple_cost;
    6332        1576 :     fpinfo->shippable_extensions = fpinfo_o->shippable_extensions;
    6333        1576 :     fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate;
    6334        1576 :     fpinfo->fetch_size = fpinfo_o->fetch_size;
    6335        1576 :     fpinfo->async_capable = fpinfo_o->async_capable;
    6336             : 
    6337             :     /* Merge the table level options from either side of the join. */
    6338        1576 :     if (fpinfo_i)
    6339             :     {
    6340             :         /*
    6341             :          * We'll prefer to use remote estimates for this join if any table
    6342             :          * from either side of the join is using remote estimates.  This is
    6343             :          * most likely going to be preferred since they're already willing to
    6344             :          * pay the price of a round trip to get the remote EXPLAIN.  In any
    6345             :          * case it's not entirely clear how we might otherwise handle this
    6346             :          * best.
    6347             :          */
    6348        1056 :         fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate ||
    6349         368 :             fpinfo_i->use_remote_estimate;
    6350             : 
    6351             :         /*
    6352             :          * Set fetch size to maximum of the joining sides, since we are
    6353             :          * expecting the rows returned by the join to be proportional to the
    6354             :          * relation sizes.
    6355             :          */
    6356         688 :         fpinfo->fetch_size = Max(fpinfo_o->fetch_size, fpinfo_i->fetch_size);
    6357             : 
    6358             :         /*
    6359             :          * We'll prefer to consider this join async-capable if any table from
    6360             :          * either side of the join is considered async-capable.  This would be
    6361             :          * reasonable because in that case the foreign server would have its
    6362             :          * own resources to scan that table asynchronously, and the join could
    6363             :          * also be computed asynchronously using the resources.
    6364             :          */
    6365        1360 :         fpinfo->async_capable = fpinfo_o->async_capable ||
    6366         672 :             fpinfo_i->async_capable;
    6367             :     }
    6368        1576 : }
    6369             : 
    6370             : /*
    6371             :  * postgresGetForeignJoinPaths
    6372             :  *      Add possible ForeignPath to joinrel, if join is safe to push down.
    6373             :  */
    6374             : static void
    6375        2704 : postgresGetForeignJoinPaths(PlannerInfo *root,
    6376             :                             RelOptInfo *joinrel,
    6377             :                             RelOptInfo *outerrel,
    6378             :                             RelOptInfo *innerrel,
    6379             :                             JoinType jointype,
    6380             :                             JoinPathExtraData *extra)
    6381             : {
    6382             :     PgFdwRelationInfo *fpinfo;
    6383             :     ForeignPath *joinpath;
    6384             :     double      rows;
    6385             :     int         width;
    6386             :     int         disabled_nodes;
    6387             :     Cost        startup_cost;
    6388             :     Cost        total_cost;
    6389             :     Path       *epq_path;       /* Path to create plan to be executed when
    6390             :                                  * EvalPlanQual gets triggered. */
    6391             : 
    6392             :     /*
    6393             :      * Skip if this join combination has been considered already.
    6394             :      */
    6395        2704 :     if (joinrel->fdw_private)
    6396        2038 :         return;
    6397             : 
    6398             :     /*
    6399             :      * This code does not work for joins with lateral references, since those
    6400             :      * must have parameterized paths, which we don't generate yet.
    6401             :      */
    6402         792 :     if (!bms_is_empty(joinrel->lateral_relids))
    6403           8 :         return;
    6404             : 
    6405             :     /*
    6406             :      * Create unfinished PgFdwRelationInfo entry which is used to indicate
    6407             :      * that the join relation is already considered, so that we won't waste
    6408             :      * time in judging safety of join pushdown and adding the same paths again
    6409             :      * if found safe. Once we know that this join can be pushed down, we fill
    6410             :      * the entry.
    6411             :      */
    6412         784 :     fpinfo = (PgFdwRelationInfo *) palloc0(sizeof(PgFdwRelationInfo));
    6413         784 :     fpinfo->pushdown_safe = false;
    6414         784 :     joinrel->fdw_private = fpinfo;
    6415             :     /* attrs_used is only for base relations. */
    6416         784 :     fpinfo->attrs_used = NULL;
    6417             : 
    6418             :     /*
    6419             :      * If there is a possibility that EvalPlanQual will be executed, we need
    6420             :      * to be able to reconstruct the row using scans of the base relations.
    6421             :      * GetExistingLocalJoinPath will find a suitable path for this purpose in
    6422             :      * the path list of the joinrel, if one exists.  We must be careful to
    6423             :      * call it before adding any ForeignPath, since the ForeignPath might
    6424             :      * dominate the only suitable local path available.  We also do it before
    6425             :      * calling foreign_join_ok(), since that function updates fpinfo and marks
    6426             :      * it as pushable if the join is found to be pushable.
    6427             :      */
    6428         784 :     if (root->parse->commandType == CMD_DELETE ||
    6429         756 :         root->parse->commandType == CMD_UPDATE ||
    6430         704 :         root->rowMarks)
    6431             :     {
    6432         152 :         epq_path = GetExistingLocalJoinPath(joinrel);
    6433         152 :         if (!epq_path)
    6434             :         {
    6435           0 :             elog(DEBUG3, "could not push down foreign join because a local path suitable for EPQ checks was not found");
    6436           0 :             return;
    6437             :         }
    6438             :     }
    6439             :     else
    6440         632 :         epq_path = NULL;
    6441             : 
    6442         784 :     if (!foreign_join_ok(root, joinrel, jointype, outerrel, innerrel, extra))
    6443             :     {
    6444             :         /* Free path required for EPQ if we copied one; we don't need it now */
    6445         118 :         if (epq_path)
    6446           4 :             pfree(epq_path);
    6447         118 :         return;
    6448             :     }
    6449             : 
    6450             :     /*
    6451             :      * Compute the selectivity and cost of the local_conds, so we don't have
    6452             :      * to do it over again for each path. The best we can do for these
    6453             :      * conditions is to estimate selectivity on the basis of local statistics.
    6454             :      * The local conditions are applied after the join has been computed on
    6455             :      * the remote side like quals in WHERE clause, so pass jointype as
    6456             :      * JOIN_INNER.
    6457             :      */
    6458         666 :     fpinfo->local_conds_sel = clauselist_selectivity(root,
    6459             :                                                      fpinfo->local_conds,
    6460             :                                                      0,
    6461             :                                                      JOIN_INNER,
    6462             :                                                      NULL);
    6463         666 :     cost_qual_eval(&fpinfo->local_conds_cost, fpinfo->local_conds, root);
    6464             : 
    6465             :     /*
    6466             :      * If we are going to estimate costs locally, estimate the join clause
    6467             :      * selectivity here while we have special join info.
    6468             :      */
    6469         666 :     if (!fpinfo->use_remote_estimate)
    6470         224 :         fpinfo->joinclause_sel = clauselist_selectivity(root, fpinfo->joinclauses,
    6471             :                                                         0, fpinfo->jointype,
    6472             :                                                         extra->sjinfo);
    6473             : 
    6474             :     /* Estimate costs for bare join relation */
    6475         666 :     estimate_path_cost_size(root, joinrel, NIL, NIL, NULL,
    6476             :                             &rows, &width, &disabled_nodes,
    6477             :                             &startup_cost, &total_cost);
    6478             :     /* Now update this information in the joinrel */
    6479         666 :     joinrel->rows = rows;
    6480         666 :     joinrel->reltarget->width = width;
    6481         666 :     fpinfo->rows = rows;
    6482         666 :     fpinfo->width = width;
    6483         666 :     fpinfo->disabled_nodes = disabled_nodes;
    6484         666 :     fpinfo->startup_cost = startup_cost;
    6485         666 :     fpinfo->total_cost = total_cost;
    6486             : 
    6487             :     /*
    6488             :      * Create a new join path and add it to the joinrel which represents a
    6489             :      * join between foreign tables.
    6490             :      */
    6491         666 :     joinpath = create_foreign_join_path(root,
    6492             :                                         joinrel,
    6493             :                                         NULL,   /* default pathtarget */
    6494             :                                         rows,
    6495             :                                         disabled_nodes,
    6496             :                                         startup_cost,
    6497             :                                         total_cost,
    6498             :                                         NIL,    /* no pathkeys */
    6499             :                                         joinrel->lateral_relids,
    6500             :                                         epq_path,
    6501             :                                         extra->restrictlist,
    6502             :                                         NIL);   /* no fdw_private */
    6503             : 
    6504             :     /* Add generated path into joinrel by add_path(). */
    6505         666 :     add_path(joinrel, (Path *) joinpath);
    6506             : 
    6507             :     /* Consider pathkeys for the join relation */
    6508         666 :     add_paths_with_pathkeys_for_rel(root, joinrel, epq_path,
    6509             :                                     extra->restrictlist);
    6510             : 
    6511             :     /* XXX Consider parameterized paths for the join relation */
    6512             : }
    6513             : 
    6514             : /*
    6515             :  * Assess whether the aggregation, grouping and having operations can be pushed
    6516             :  * down to the foreign server.  As a side effect, save information we obtain in
    6517             :  * this function to PgFdwRelationInfo of the input relation.
    6518             :  */
    6519             : static bool
    6520         318 : foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
    6521             :                     Node *havingQual)
    6522             : {
    6523         318 :     Query      *query = root->parse;
    6524         318 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
    6525         318 :     PathTarget *grouping_target = grouped_rel->reltarget;
    6526             :     PgFdwRelationInfo *ofpinfo;
    6527             :     ListCell   *lc;
    6528             :     int         i;
    6529         318 :     List       *tlist = NIL;
    6530             : 
    6531             :     /* We currently don't support pushing Grouping Sets. */
    6532         318 :     if (query->groupingSets)
    6533          12 :         return false;
    6534             : 
    6535             :     /* Get the fpinfo of the underlying scan relation. */
    6536         306 :     ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
    6537             : 
    6538             :     /*
    6539             :      * If underlying scan relation has any local conditions, those conditions
    6540             :      * are required to be applied before performing aggregation.  Hence the
    6541             :      * aggregate cannot be pushed down.
    6542             :      */
    6543         306 :     if (ofpinfo->local_conds)
    6544          18 :         return false;
    6545             : 
    6546             :     /*
    6547             :      * Examine grouping expressions, as well as other expressions we'd need to
    6548             :      * compute, and check whether they are safe to push down to the foreign
    6549             :      * server.  All GROUP BY expressions will be part of the grouping target
    6550             :      * and thus there is no need to search for them separately.  Add grouping
    6551             :      * expressions into target list which will be passed to foreign server.
    6552             :      *
    6553             :      * A tricky fine point is that we must not put any expression into the
    6554             :      * target list that is just a foreign param (that is, something that
    6555             :      * deparse.c would conclude has to be sent to the foreign server).  If we
    6556             :      * do, the expression will also appear in the fdw_exprs list of the plan
    6557             :      * node, and setrefs.c will get confused and decide that the fdw_exprs
    6558             :      * entry is actually a reference to the fdw_scan_tlist entry, resulting in
    6559             :      * a broken plan.  Somewhat oddly, it's OK if the expression contains such
    6560             :      * a node, as long as it's not at top level; then no match is possible.
    6561             :      */
    6562         288 :     i = 0;
    6563         846 :     foreach(lc, grouping_target->exprs)
    6564             :     {
    6565         594 :         Expr       *expr = (Expr *) lfirst(lc);
    6566         594 :         Index       sgref = get_pathtarget_sortgroupref(grouping_target, i);
    6567             :         ListCell   *l;
    6568             : 
    6569             :         /*
    6570             :          * Check whether this expression is part of GROUP BY clause.  Note we
    6571             :          * check the whole GROUP BY clause not just processed_groupClause,
    6572             :          * because we will ship all of it, cf. appendGroupByClause.
    6573             :          */
    6574         594 :         if (sgref && get_sortgroupref_clause_noerr(sgref, query->groupClause))
    6575         184 :         {
    6576             :             TargetEntry *tle;
    6577             : 
    6578             :             /*
    6579             :              * If any GROUP BY expression is not shippable, then we cannot
    6580             :              * push down aggregation to the foreign server.
    6581             :              */
    6582         190 :             if (!is_foreign_expr(root, grouped_rel, expr))
    6583          36 :                 return false;
    6584             : 
    6585             :             /*
    6586             :              * If it would be a foreign param, we can't put it into the tlist,
    6587             :              * so we have to fail.
    6588             :              */
    6589         188 :             if (is_foreign_param(root, grouped_rel, expr))
    6590           4 :                 return false;
    6591             : 
    6592             :             /*
    6593             :              * Pushable, so add to tlist.  We need to create a TLE for this
    6594             :              * expression and apply the sortgroupref to it.  We cannot use
    6595             :              * add_to_flat_tlist() here because that avoids making duplicate
    6596             :              * entries in the tlist.  If there are duplicate entries with
    6597             :              * distinct sortgrouprefs, we have to duplicate that situation in
    6598             :              * the output tlist.
    6599             :              */
    6600         184 :             tle = makeTargetEntry(expr, list_length(tlist) + 1, NULL, false);
    6601         184 :             tle->ressortgroupref = sgref;
    6602         184 :             tlist = lappend(tlist, tle);
    6603             :         }
    6604             :         else
    6605             :         {
    6606             :             /*
    6607             :              * Non-grouping expression we need to compute.  Can we ship it
    6608             :              * as-is to the foreign server?
    6609             :              */
    6610         404 :             if (is_foreign_expr(root, grouped_rel, expr) &&
    6611         362 :                 !is_foreign_param(root, grouped_rel, expr))
    6612         358 :             {
    6613             :                 /* Yes, so add to tlist as-is; OK to suppress duplicates */
    6614         358 :                 tlist = add_to_flat_tlist(tlist, list_make1(expr));
    6615             :             }
    6616             :             else
    6617             :             {
    6618             :                 /* Not pushable as a whole; extract its Vars and aggregates */
    6619             :                 List       *aggvars;
    6620             : 
    6621          46 :                 aggvars = pull_var_clause((Node *) expr,
    6622             :                                           PVC_INCLUDE_AGGREGATES);
    6623             : 
    6624             :                 /*
    6625             :                  * If any aggregate expression is not shippable, then we
    6626             :                  * cannot push down aggregation to the foreign server.  (We
    6627             :                  * don't have to check is_foreign_param, since that certainly
    6628             :                  * won't return true for any such expression.)
    6629             :                  */
    6630          46 :                 if (!is_foreign_expr(root, grouped_rel, (Expr *) aggvars))
    6631          30 :                     return false;
    6632             : 
    6633             :                 /*
    6634             :                  * Add aggregates, if any, into the targetlist.  Plain Vars
    6635             :                  * outside an aggregate can be ignored, because they should be
    6636             :                  * either same as some GROUP BY column or part of some GROUP
    6637             :                  * BY expression.  In either case, they are already part of
    6638             :                  * the targetlist and thus no need to add them again.  In fact
    6639             :                  * including plain Vars in the tlist when they do not match a
    6640             :                  * GROUP BY column would cause the foreign server to complain
    6641             :                  * that the shipped query is invalid.
    6642             :                  */
    6643          28 :                 foreach(l, aggvars)
    6644             :                 {
    6645          12 :                     Expr       *aggref = (Expr *) lfirst(l);
    6646             : 
    6647          12 :                     if (IsA(aggref, Aggref))
    6648           8 :                         tlist = add_to_flat_tlist(tlist, list_make1(aggref));
    6649             :                 }
    6650             :             }
    6651             :         }
    6652             : 
    6653         558 :         i++;
    6654             :     }
    6655             : 
    6656             :     /*
    6657             :      * Classify the pushable and non-pushable HAVING clauses and save them in
    6658             :      * remote_conds and local_conds of the grouped rel's fpinfo.
    6659             :      */
    6660         252 :     if (havingQual)
    6661             :     {
    6662          68 :         foreach(lc, (List *) havingQual)
    6663             :         {
    6664          38 :             Expr       *expr = (Expr *) lfirst(lc);
    6665             :             RestrictInfo *rinfo;
    6666             : 
    6667             :             /*
    6668             :              * Currently, the core code doesn't wrap havingQuals in
    6669             :              * RestrictInfos, so we must make our own.
    6670             :              */
    6671             :             Assert(!IsA(expr, RestrictInfo));
    6672          38 :             rinfo = make_restrictinfo(root,
    6673             :                                       expr,
    6674             :                                       true,
    6675             :                                       false,
    6676             :                                       false,
    6677             :                                       false,
    6678             :                                       root->qual_security_level,
    6679             :                                       grouped_rel->relids,
    6680             :                                       NULL,
    6681             :                                       NULL);
    6682          38 :             if (is_foreign_expr(root, grouped_rel, expr))
    6683          32 :                 fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
    6684             :             else
    6685           6 :                 fpinfo->local_conds = lappend(fpinfo->local_conds, rinfo);
    6686             :         }
    6687             :     }
    6688             : 
    6689             :     /*
    6690             :      * If there are any local conditions, pull Vars and aggregates from it and
    6691             :      * check whether they are safe to pushdown or not.
    6692             :      */
    6693         252 :     if (fpinfo->local_conds)
    6694             :     {
    6695           6 :         List       *aggvars = NIL;
    6696             : 
    6697          12 :         foreach(lc, fpinfo->local_conds)
    6698             :         {
    6699           6 :             RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    6700             : 
    6701           6 :             aggvars = list_concat(aggvars,
    6702           6 :                                   pull_var_clause((Node *) rinfo->clause,
    6703             :                                                   PVC_INCLUDE_AGGREGATES));
    6704             :         }
    6705             : 
    6706          14 :         foreach(lc, aggvars)
    6707             :         {
    6708          10 :             Expr       *expr = (Expr *) lfirst(lc);
    6709             : 
    6710             :             /*
    6711             :              * If aggregates within local conditions are not safe to push
    6712             :              * down, then we cannot push down the query.  Vars are already
    6713             :              * part of GROUP BY clause which are checked above, so no need to
    6714             :              * access them again here.  Again, we need not check
    6715             :              * is_foreign_param for a foreign aggregate.
    6716             :              */
    6717          10 :             if (IsA(expr, Aggref))
    6718             :             {
    6719          10 :                 if (!is_foreign_expr(root, grouped_rel, expr))
    6720           2 :                     return false;
    6721             : 
    6722           8 :                 tlist = add_to_flat_tlist(tlist, list_make1(expr));
    6723             :             }
    6724             :         }
    6725             :     }
    6726             : 
    6727             :     /* Store generated targetlist */
    6728         250 :     fpinfo->grouped_tlist = tlist;
    6729             : 
    6730             :     /* Safe to pushdown */
    6731         250 :     fpinfo->pushdown_safe = true;
    6732             : 
    6733             :     /*
    6734             :      * Set # of retrieved rows and cached relation costs to some negative
    6735             :      * value, so that we can detect when they are set to some sensible values,
    6736             :      * during one (usually the first) of the calls to estimate_path_cost_size.
    6737             :      */
    6738         250 :     fpinfo->retrieved_rows = -1;
    6739         250 :     fpinfo->rel_startup_cost = -1;
    6740         250 :     fpinfo->rel_total_cost = -1;
    6741             : 
    6742             :     /*
    6743             :      * Set the string describing this grouped relation to be used in EXPLAIN
    6744             :      * output of corresponding ForeignScan.  Note that the decoration we add
    6745             :      * to the base relation name mustn't include any digits, or it'll confuse
    6746             :      * postgresExplainForeignScan.
    6747             :      */
    6748         250 :     fpinfo->relation_name = psprintf("Aggregate on (%s)",
    6749             :                                      ofpinfo->relation_name);
    6750             : 
    6751         250 :     return true;
    6752             : }
    6753             : 
    6754             : /*
    6755             :  * postgresGetForeignUpperPaths
    6756             :  *      Add paths for post-join operations like aggregation, grouping etc. if
    6757             :  *      corresponding operations are safe to push down.
    6758             :  */
    6759             : static void
    6760        1920 : postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
    6761             :                              RelOptInfo *input_rel, RelOptInfo *output_rel,
    6762             :                              void *extra)
    6763             : {
    6764             :     PgFdwRelationInfo *fpinfo;
    6765             : 
    6766             :     /*
    6767             :      * If input rel is not safe to pushdown, then simply return as we cannot
    6768             :      * perform any post-join operations on the foreign server.
    6769             :      */
    6770        1920 :     if (!input_rel->fdw_private ||
    6771        1788 :         !((PgFdwRelationInfo *) input_rel->fdw_private)->pushdown_safe)
    6772         244 :         return;
    6773             : 
    6774             :     /* Ignore stages we don't support; and skip any duplicate calls. */
    6775        1676 :     if ((stage != UPPERREL_GROUP_AGG &&
    6776        1058 :          stage != UPPERREL_ORDERED &&
    6777        1642 :          stage != UPPERREL_FINAL) ||
    6778        1642 :         output_rel->fdw_private)
    6779          34 :         return;
    6780             : 
    6781        1642 :     fpinfo = (PgFdwRelationInfo *) palloc0(sizeof(PgFdwRelationInfo));
    6782        1642 :     fpinfo->pushdown_safe = false;
    6783        1642 :     fpinfo->stage = stage;
    6784        1642 :     output_rel->fdw_private = fpinfo;
    6785             : 
    6786        1642 :     switch (stage)
    6787             :     {
    6788         318 :         case UPPERREL_GROUP_AGG:
    6789         318 :             add_foreign_grouping_paths(root, input_rel, output_rel,
    6790             :                                        (GroupPathExtraData *) extra);
    6791         318 :             break;
    6792         300 :         case UPPERREL_ORDERED:
    6793         300 :             add_foreign_ordered_paths(root, input_rel, output_rel);
    6794         300 :             break;
    6795        1024 :         case UPPERREL_FINAL:
    6796        1024 :             add_foreign_final_paths(root, input_rel, output_rel,
    6797             :                                     (FinalPathExtraData *) extra);
    6798        1024 :             break;
    6799           0 :         default:
    6800           0 :             elog(ERROR, "unexpected upper relation: %d", (int) stage);
    6801             :             break;
    6802             :     }
    6803             : }
    6804             : 
    6805             : /*
    6806             :  * add_foreign_grouping_paths
    6807             :  *      Add foreign path for grouping and/or aggregation.
    6808             :  *
    6809             :  * Given input_rel represents the underlying scan.  The paths are added to the
    6810             :  * given grouped_rel.
    6811             :  */
    6812             : static void
    6813         318 : add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
    6814             :                            RelOptInfo *grouped_rel,
    6815             :                            GroupPathExtraData *extra)
    6816             : {
    6817         318 :     Query      *parse = root->parse;
    6818         318 :     PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
    6819         318 :     PgFdwRelationInfo *fpinfo = grouped_rel->fdw_private;
    6820             :     ForeignPath *grouppath;
    6821             :     double      rows;
    6822             :     int         width;
    6823             :     int         disabled_nodes;
    6824             :     Cost        startup_cost;
    6825             :     Cost        total_cost;
    6826             : 
    6827             :     /* Nothing to be done, if there is no grouping or aggregation required. */
    6828         318 :     if (!parse->groupClause && !parse->groupingSets && !parse->hasAggs &&
    6829           0 :         !root->hasHavingQual)
    6830          68 :         return;
    6831             : 
    6832             :     Assert(extra->patype == PARTITIONWISE_AGGREGATE_NONE ||
    6833             :            extra->patype == PARTITIONWISE_AGGREGATE_FULL);
    6834             : 
    6835             :     /* save the input_rel as outerrel in fpinfo */
    6836         318 :     fpinfo->outerrel = input_rel;
    6837             : 
    6838             :     /*
    6839             :      * Copy foreign table, foreign server, user mapping, FDW options etc.
    6840             :      * details from the input relation's fpinfo.
    6841             :      */
    6842         318 :     fpinfo->table = ifpinfo->table;
    6843         318 :     fpinfo->server = ifpinfo->server;
    6844         318 :     fpinfo->user = ifpinfo->user;
    6845         318 :     merge_fdw_options(fpinfo, ifpinfo, NULL);
    6846             : 
    6847             :     /*
    6848             :      * Assess if it is safe to push down aggregation and grouping.
    6849             :      *
    6850             :      * Use HAVING qual from extra. In case of child partition, it will have
    6851             :      * translated Vars.
    6852             :      */
    6853         318 :     if (!foreign_grouping_ok(root, grouped_rel, extra->havingQual))
    6854          68 :         return;
    6855             : 
    6856             :     /*
    6857             :      * Compute the selectivity and cost of the local_conds, so we don't have
    6858             :      * to do it over again for each path.  (Currently we create just a single
    6859             :      * path here, but in future it would be possible that we build more paths
    6860             :      * such as pre-sorted paths as in postgresGetForeignPaths and
    6861             :      * postgresGetForeignJoinPaths.)  The best we can do for these conditions
    6862             :      * is to estimate selectivity on the basis of local statistics.
    6863             :      */
    6864         250 :     fpinfo->local_conds_sel = clauselist_selectivity(root,
    6865             :                                                      fpinfo->local_conds,
    6866             :                                                      0,
    6867             :                                                      JOIN_INNER,
    6868             :                                                      NULL);
    6869             : 
    6870         250 :     cost_qual_eval(&fpinfo->local_conds_cost, fpinfo->local_conds, root);
    6871             : 
    6872             :     /* Estimate the cost of push down */
    6873         250 :     estimate_path_cost_size(root, grouped_rel, NIL, NIL, NULL,
    6874             :                             &rows, &width, &disabled_nodes,
    6875             :                             &startup_cost, &total_cost);
    6876             : 
    6877             :     /* Now update this information in the fpinfo */
    6878         250 :     fpinfo->rows = rows;
    6879         250 :     fpinfo->width = width;
    6880         250 :     fpinfo->disabled_nodes = disabled_nodes;
    6881         250 :     fpinfo->startup_cost = startup_cost;
    6882         250 :     fpinfo->total_cost = total_cost;
    6883             : 
    6884             :     /* Create and add foreign path to the grouping relation. */
    6885         250 :     grouppath = create_foreign_upper_path(root,
    6886             :                                           grouped_rel,
    6887         250 :                                           grouped_rel->reltarget,
    6888             :                                           rows,
    6889             :                                           disabled_nodes,
    6890             :                                           startup_cost,
    6891             :                                           total_cost,
    6892             :                                           NIL,  /* no pathkeys */
    6893             :                                           NULL,
    6894             :                                           NIL,  /* no fdw_restrictinfo list */
    6895             :                                           NIL); /* no fdw_private */
    6896             : 
    6897             :     /* Add generated path into grouped_rel by add_path(). */
    6898         250 :     add_path(grouped_rel, (Path *) grouppath);
    6899             : }
    6900             : 
    6901             : /*
    6902             :  * add_foreign_ordered_paths
    6903             :  *      Add foreign paths for performing the final sort remotely.
    6904             :  *
    6905             :  * Given input_rel contains the source-data Paths.  The paths are added to the
    6906             :  * given ordered_rel.
    6907             :  */
    6908             : static void
    6909         300 : add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
    6910             :                           RelOptInfo *ordered_rel)
    6911             : {
    6912         300 :     Query      *parse = root->parse;
    6913         300 :     PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
    6914         300 :     PgFdwRelationInfo *fpinfo = ordered_rel->fdw_private;
    6915             :     PgFdwPathExtraData *fpextra;
    6916             :     double      rows;
    6917             :     int         width;
    6918             :     int         disabled_nodes;
    6919             :     Cost        startup_cost;
    6920             :     Cost        total_cost;
    6921             :     List       *fdw_private;
    6922             :     ForeignPath *ordered_path;
    6923             :     ListCell   *lc;
    6924             : 
    6925             :     /* Shouldn't get here unless the query has ORDER BY */
    6926             :     Assert(parse->sortClause);
    6927             : 
    6928             :     /* We don't support cases where there are any SRFs in the targetlist */
    6929         300 :     if (parse->hasTargetSRFs)
    6930         216 :         return;
    6931             : 
    6932             :     /* Save the input_rel as outerrel in fpinfo */
    6933         300 :     fpinfo->outerrel = input_rel;
    6934             : 
    6935             :     /*
    6936             :      * Copy foreign table, foreign server, user mapping, FDW options etc.
    6937             :      * details from the input relation's fpinfo.
    6938             :      */
    6939         300 :     fpinfo->table = ifpinfo->table;
    6940         300 :     fpinfo->server = ifpinfo->server;
    6941         300 :     fpinfo->user = ifpinfo->user;
    6942         300 :     merge_fdw_options(fpinfo, ifpinfo, NULL);
    6943             : 
    6944             :     /*
    6945             :      * If the input_rel is a base or join relation, we would already have
    6946             :      * considered pushing down the final sort to the remote server when
    6947             :      * creating pre-sorted foreign paths for that relation, because the
    6948             :      * query_pathkeys is set to the root->sort_pathkeys in that case (see
    6949             :      * standard_qp_callback()).
    6950             :      */
    6951         300 :     if (input_rel->reloptkind == RELOPT_BASEREL ||
    6952         218 :         input_rel->reloptkind == RELOPT_JOINREL)
    6953             :     {
    6954             :         Assert(root->query_pathkeys == root->sort_pathkeys);
    6955             : 
    6956             :         /* Safe to push down if the query_pathkeys is safe to push down */
    6957         208 :         fpinfo->pushdown_safe = ifpinfo->qp_is_pushdown_safe;
    6958             : 
    6959         208 :         return;
    6960             :     }
    6961             : 
    6962             :     /* The input_rel should be a grouping relation */
    6963             :     Assert(input_rel->reloptkind == RELOPT_UPPER_REL &&
    6964             :            ifpinfo->stage == UPPERREL_GROUP_AGG);
    6965             : 
    6966             :     /*
    6967             :      * We try to create a path below by extending a simple foreign path for
    6968             :      * the underlying grouping relation to perform the final sort remotely,
    6969             :      * which is stored into the fdw_private list of the resulting path.
    6970             :      */
    6971             : 
    6972             :     /* Assess if it is safe to push down the final sort */
    6973         188 :     foreach(lc, root->sort_pathkeys)
    6974             :     {
    6975         104 :         PathKey    *pathkey = (PathKey *) lfirst(lc);
    6976         104 :         EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
    6977             : 
    6978             :         /*
    6979             :          * is_foreign_expr would detect volatile expressions as well, but
    6980             :          * checking ec_has_volatile here saves some cycles.
    6981             :          */
    6982         104 :         if (pathkey_ec->ec_has_volatile)
    6983           8 :             return;
    6984             : 
    6985             :         /*
    6986             :          * Can't push down the sort if pathkey's opfamily is not shippable.
    6987             :          */
    6988          96 :         if (!is_shippable(pathkey->pk_opfamily, OperatorFamilyRelationId,
    6989             :                           fpinfo))
    6990           0 :             return;
    6991             : 
    6992             :         /*
    6993             :          * The EC must contain a shippable EM that is computed in input_rel's
    6994             :          * reltarget, else we can't push down the sort.
    6995             :          */
    6996          96 :         if (find_em_for_rel_target(root,
    6997             :                                    pathkey_ec,
    6998             :                                    input_rel) == NULL)
    6999           0 :             return;
    7000             :     }
    7001             : 
    7002             :     /* Safe to push down */
    7003          84 :     fpinfo->pushdown_safe = true;
    7004             : 
    7005             :     /* Construct PgFdwPathExtraData */
    7006          84 :     fpextra = (PgFdwPathExtraData *) palloc0(sizeof(PgFdwPathExtraData));
    7007          84 :     fpextra->target = root->upper_targets[UPPERREL_ORDERED];
    7008          84 :     fpextra->has_final_sort = true;
    7009             : 
    7010             :     /* Estimate the costs of performing the final sort remotely */
    7011          84 :     estimate_path_cost_size(root, input_rel, NIL, root->sort_pathkeys, fpextra,
    7012             :                             &rows, &width, &disabled_nodes,
    7013             :                             &startup_cost, &total_cost);
    7014             : 
    7015             :     /*
    7016             :      * Build the fdw_private list that will be used by postgresGetForeignPlan.
    7017             :      * Items in the list must match order in enum FdwPathPrivateIndex.
    7018             :      */
    7019          84 :     fdw_private = list_make2(makeBoolean(true), makeBoolean(false));
    7020             : 
    7021             :     /* Create foreign ordering path */
    7022          84 :     ordered_path = create_foreign_upper_path(root,
    7023             :                                              input_rel,
    7024          84 :                                              root->upper_targets[UPPERREL_ORDERED],
    7025             :                                              rows,
    7026             :                                              disabled_nodes,
    7027             :                                              startup_cost,
    7028             :                                              total_cost,
    7029             :                                              root->sort_pathkeys,
    7030             :                                              NULL,  /* no extra plan */
    7031             :                                              NIL,   /* no fdw_restrictinfo
    7032             :                                                      * list */
    7033             :                                              fdw_private);
    7034             : 
    7035             :     /* and add it to the ordered_rel */
    7036          84 :     add_path(ordered_rel, (Path *) ordered_path);
    7037             : }
    7038             : 
    7039             : /*
    7040             :  * add_foreign_final_paths
    7041             :  *      Add foreign paths for performing the final processing remotely.
    7042             :  *
    7043             :  * Given input_rel contains the source-data Paths.  The paths are added to the
    7044             :  * given final_rel.
    7045             :  */
    7046             : static void
    7047        1024 : add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
    7048             :                         RelOptInfo *final_rel,
    7049             :                         FinalPathExtraData *extra)
    7050             : {
    7051        1024 :     Query      *parse = root->parse;
    7052        1024 :     PgFdwRelationInfo *ifpinfo = (PgFdwRelationInfo *) input_rel->fdw_private;
    7053        1024 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) final_rel->fdw_private;
    7054        1024 :     bool        has_final_sort = false;
    7055        1024 :     List       *pathkeys = NIL;
    7056             :     PgFdwPathExtraData *fpextra;
    7057        1024 :     bool        save_use_remote_estimate = false;
    7058             :     double      rows;
    7059             :     int         width;
    7060             :     int         disabled_nodes;
    7061             :     Cost        startup_cost;
    7062             :     Cost        total_cost;
    7063             :     List       *fdw_private;
    7064             :     ForeignPath *final_path;
    7065             : 
    7066             :     /*
    7067             :      * Currently, we only support this for SELECT commands
    7068             :      */
    7069        1024 :     if (parse->commandType != CMD_SELECT)
    7070         782 :         return;
    7071             : 
    7072             :     /*
    7073             :      * No work if there is no FOR UPDATE/SHARE clause and if there is no need
    7074             :      * to add a LIMIT node
    7075             :      */
    7076         798 :     if (!parse->rowMarks && !extra->limit_needed)
    7077         528 :         return;
    7078             : 
    7079             :     /* We don't support cases where there are any SRFs in the targetlist */
    7080         270 :     if (parse->hasTargetSRFs)
    7081           0 :         return;
    7082             : 
    7083             :     /* Save the input_rel as outerrel in fpinfo */
    7084         270 :     fpinfo->outerrel = input_rel;
    7085             : 
    7086             :     /*
    7087             :      * Copy foreign table, foreign server, user mapping, FDW options etc.
    7088             :      * details from the input relation's fpinfo.
    7089             :      */
    7090         270 :     fpinfo->table = ifpinfo->table;
    7091         270 :     fpinfo->server = ifpinfo->server;
    7092         270 :     fpinfo->user = ifpinfo->user;
    7093         270 :     merge_fdw_options(fpinfo, ifpinfo, NULL);
    7094             : 
    7095             :     /*
    7096             :      * If there is no need to add a LIMIT node, there might be a ForeignPath
    7097             :      * in the input_rel's pathlist that implements all behavior of the query.
    7098             :      * Note: we would already have accounted for the query's FOR UPDATE/SHARE
    7099             :      * (if any) before we get here.
    7100             :      */
    7101         270 :     if (!extra->limit_needed)
    7102             :     {
    7103             :         ListCell   *lc;
    7104             : 
    7105             :         Assert(parse->rowMarks);
    7106             : 
    7107             :         /*
    7108             :          * Grouping and aggregation are not supported with FOR UPDATE/SHARE,
    7109             :          * so the input_rel should be a base, join, or ordered relation; and
    7110             :          * if it's an ordered relation, its input relation should be a base or
    7111             :          * join relation.
    7112             :          */
    7113             :         Assert(input_rel->reloptkind == RELOPT_BASEREL ||
    7114             :                input_rel->reloptkind == RELOPT_JOINREL ||
    7115             :                (input_rel->reloptkind == RELOPT_UPPER_REL &&
    7116             :                 ifpinfo->stage == UPPERREL_ORDERED &&
    7117             :                 (ifpinfo->outerrel->reloptkind == RELOPT_BASEREL ||
    7118             :                  ifpinfo->outerrel->reloptkind == RELOPT_JOINREL)));
    7119             : 
    7120           8 :         foreach(lc, input_rel->pathlist)
    7121             :         {
    7122           8 :             Path       *path = (Path *) lfirst(lc);
    7123             : 
    7124             :             /*
    7125             :              * apply_scanjoin_target_to_paths() uses create_projection_path()
    7126             :              * to adjust each of its input paths if needed, whereas
    7127             :              * create_ordered_paths() uses apply_projection_to_path() to do
    7128             :              * that.  So the former might have put a ProjectionPath on top of
    7129             :              * the ForeignPath; look through ProjectionPath and see if the
    7130             :              * path underneath it is ForeignPath.
    7131             :              */
    7132           8 :             if (IsA(path, ForeignPath) ||
    7133           0 :                 (IsA(path, ProjectionPath) &&
    7134           0 :                  IsA(((ProjectionPath *) path)->subpath, ForeignPath)))
    7135             :             {
    7136             :                 /*
    7137             :                  * Create foreign final path; this gets rid of a
    7138             :                  * no-longer-needed outer plan (if any), which makes the
    7139             :                  * EXPLAIN output look cleaner
    7140             :                  */
    7141           8 :                 final_path = create_foreign_upper_path(root,
    7142             :                                                        path->parent,
    7143             :                                                        path->pathtarget,
    7144             :                                                        path->rows,
    7145             :                                                        path->disabled_nodes,
    7146             :                                                        path->startup_cost,
    7147             :                                                        path->total_cost,
    7148             :                                                        path->pathkeys,
    7149             :                                                        NULL,    /* no extra plan */
    7150             :                                                        NIL, /* no fdw_restrictinfo
    7151             :                                                              * list */
    7152             :                                                        NIL);    /* no fdw_private */
    7153             : 
    7154             :                 /* and add it to the final_rel */
    7155           8 :                 add_path(final_rel, (Path *) final_path);
    7156             : 
    7157             :                 /* Safe to push down */
    7158           8 :                 fpinfo->pushdown_safe = true;
    7159             : 
    7160           8 :                 return;
    7161             :             }
    7162             :         }
    7163             : 
    7164             :         /*
    7165             :          * If we get here it means no ForeignPaths; since we would already
    7166             :          * have considered pushing down all operations for the query to the
    7167             :          * remote server, give up on it.
    7168             :          */
    7169           0 :         return;
    7170             :     }
    7171             : 
    7172             :     Assert(extra->limit_needed);
    7173             : 
    7174             :     /*
    7175             :      * If the input_rel is an ordered relation, replace the input_rel with its
    7176             :      * input relation
    7177             :      */
    7178         262 :     if (input_rel->reloptkind == RELOPT_UPPER_REL &&
    7179         148 :         ifpinfo->stage == UPPERREL_ORDERED)
    7180             :     {
    7181         148 :         input_rel = ifpinfo->outerrel;
    7182         148 :         ifpinfo = (PgFdwRelationInfo *) input_rel->fdw_private;
    7183         148 :         has_final_sort = true;
    7184         148 :         pathkeys = root->sort_pathkeys;
    7185             :     }
    7186             : 
    7187             :     /* The input_rel should be a base, join, or grouping relation */
    7188             :     Assert(input_rel->reloptkind == RELOPT_BASEREL ||
    7189             :            input_rel->reloptkind == RELOPT_JOINREL ||
    7190             :            (input_rel->reloptkind == RELOPT_UPPER_REL &&
    7191             :             ifpinfo->stage == UPPERREL_GROUP_AGG));
    7192             : 
    7193             :     /*
    7194             :      * We try to create a path below by extending a simple foreign path for
    7195             :      * the underlying base, join, or grouping relation to perform the final
    7196             :      * sort (if has_final_sort) and the LIMIT restriction remotely, which is
    7197             :      * stored into the fdw_private list of the resulting path.  (We
    7198             :      * re-estimate the costs of sorting the underlying relation, if
    7199             :      * has_final_sort.)
    7200             :      */
    7201             : 
    7202             :     /*
    7203             :      * Assess if it is safe to push down the LIMIT and OFFSET to the remote
    7204             :      * server
    7205             :      */
    7206             : 
    7207             :     /*
    7208             :      * If the underlying relation has any local conditions, the LIMIT/OFFSET
    7209             :      * cannot be pushed down.
    7210             :      */
    7211         262 :     if (ifpinfo->local_conds)
    7212          16 :         return;
    7213             : 
    7214             :     /*
    7215             :      * If the query has FETCH FIRST .. WITH TIES, 1) it must have ORDER BY as
    7216             :      * well, which is used to determine which additional rows tie for the last
    7217             :      * place in the result set, and 2) ORDER BY must already have been
    7218             :      * determined to be safe to push down before we get here.  So in that case
    7219             :      * the FETCH clause is safe to push down with ORDER BY if the remote
    7220             :      * server is v13 or later, but if not, the remote query will fail entirely
    7221             :      * for lack of support for it.  Since we do not currently have a way to do
    7222             :      * a remote-version check (without accessing the remote server), disable
    7223             :      * pushing the FETCH clause for now.
    7224             :      */
    7225         246 :     if (parse->limitOption == LIMIT_OPTION_WITH_TIES)
    7226           4 :         return;
    7227             : 
    7228             :     /*
    7229             :      * Also, the LIMIT/OFFSET cannot be pushed down, if their expressions are
    7230             :      * not safe to remote.
    7231             :      */
    7232         242 :     if (!is_foreign_expr(root, input_rel, (Expr *) parse->limitOffset) ||
    7233         242 :         !is_foreign_expr(root, input_rel, (Expr *) parse->limitCount))
    7234           0 :         return;
    7235             : 
    7236             :     /* Safe to push down */
    7237         242 :     fpinfo->pushdown_safe = true;
    7238             : 
    7239             :     /* Construct PgFdwPathExtraData */
    7240         242 :     fpextra = (PgFdwPathExtraData *) palloc0(sizeof(PgFdwPathExtraData));
    7241         242 :     fpextra->target = root->upper_targets[UPPERREL_FINAL];
    7242         242 :     fpextra->has_final_sort = has_final_sort;
    7243         242 :     fpextra->has_limit = extra->limit_needed;
    7244         242 :     fpextra->limit_tuples = extra->limit_tuples;
    7245         242 :     fpextra->count_est = extra->count_est;
    7246         242 :     fpextra->offset_est = extra->offset_est;
    7247             : 
    7248             :     /*
    7249             :      * Estimate the costs of performing the final sort and the LIMIT
    7250             :      * restriction remotely.  If has_final_sort is false, we wouldn't need to
    7251             :      * execute EXPLAIN anymore if use_remote_estimate, since the costs can be
    7252             :      * roughly estimated using the costs we already have for the underlying
    7253             :      * relation, in the same way as when use_remote_estimate is false.  Since
    7254             :      * it's pretty expensive to execute EXPLAIN, force use_remote_estimate to
    7255             :      * false in that case.
    7256             :      */
    7257         242 :     if (!fpextra->has_final_sort)
    7258             :     {
    7259         108 :         save_use_remote_estimate = ifpinfo->use_remote_estimate;
    7260         108 :         ifpinfo->use_remote_estimate = false;
    7261             :     }
    7262         242 :     estimate_path_cost_size(root, input_rel, NIL, pathkeys, fpextra,
    7263             :                             &rows, &width, &disabled_nodes,
    7264             :                             &startup_cost, &total_cost);
    7265         242 :     if (!fpextra->has_final_sort)
    7266         108 :         ifpinfo->use_remote_estimate = save_use_remote_estimate;
    7267             : 
    7268             :     /*
    7269             :      * Build the fdw_private list that will be used by postgresGetForeignPlan.
    7270             :      * Items in the list must match order in enum FdwPathPrivateIndex.
    7271             :      */
    7272         242 :     fdw_private = list_make2(makeBoolean(has_final_sort),
    7273             :                              makeBoolean(extra->limit_needed));
    7274             : 
    7275             :     /*
    7276             :      * Create foreign final path; this gets rid of a no-longer-needed outer
    7277             :      * plan (if any), which makes the EXPLAIN output look cleaner
    7278             :      */
    7279         242 :     final_path = create_foreign_upper_path(root,
    7280             :                                            input_rel,
    7281         242 :                                            root->upper_targets[UPPERREL_FINAL],
    7282             :                                            rows,
    7283             :                                            disabled_nodes,
    7284             :                                            startup_cost,
    7285             :                                            total_cost,
    7286             :                                            pathkeys,
    7287             :                                            NULL,    /* no extra plan */
    7288             :                                            NIL, /* no fdw_restrictinfo list */
    7289             :                                            fdw_private);
    7290             : 
    7291             :     /* and add it to the final_rel */
    7292         242 :     add_path(final_rel, (Path *) final_path);
    7293             : }
    7294             : 
    7295             : /*
    7296             :  * postgresIsForeignPathAsyncCapable
    7297             :  *      Check whether a given ForeignPath node is async-capable.
    7298             :  */
    7299             : static bool
    7300         466 : postgresIsForeignPathAsyncCapable(ForeignPath *path)
    7301             : {
    7302         466 :     RelOptInfo *rel = ((Path *) path)->parent;
    7303         466 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
    7304             : 
    7305         466 :     return fpinfo->async_capable;
    7306             : }
    7307             : 
    7308             : /*
    7309             :  * postgresForeignAsyncRequest
    7310             :  *      Asynchronously request next tuple from a foreign PostgreSQL table.
    7311             :  */
    7312             : static void
    7313       12350 : postgresForeignAsyncRequest(AsyncRequest *areq)
    7314             : {
    7315       12350 :     produce_tuple_asynchronously(areq, true);
    7316       12350 : }
    7317             : 
    7318             : /*
    7319             :  * postgresForeignAsyncConfigureWait
    7320             :  *      Configure a file descriptor event for which we wish to wait.
    7321             :  */
    7322             : static void
    7323         370 : postgresForeignAsyncConfigureWait(AsyncRequest *areq)
    7324             : {
    7325         370 :     ForeignScanState *node = (ForeignScanState *) areq->requestee;
    7326         370 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    7327         370 :     AsyncRequest *pendingAreq = fsstate->conn_state->pendingAreq;
    7328         370 :     AppendState *requestor = (AppendState *) areq->requestor;
    7329         370 :     WaitEventSet *set = requestor->as_eventset;
    7330             : 
    7331             :     /* This should not be called unless callback_pending */
    7332             :     Assert(areq->callback_pending);
    7333             : 
    7334             :     /*
    7335             :      * If process_pending_request() has been invoked on the given request
    7336             :      * before we get here, we might have some tuples already; in which case
    7337             :      * complete the request
    7338             :      */
    7339         370 :     if (fsstate->next_tuple < fsstate->num_tuples)
    7340             :     {
    7341          10 :         complete_pending_request(areq);
    7342          10 :         if (areq->request_complete)
    7343           6 :             return;
    7344             :         Assert(areq->callback_pending);
    7345             :     }
    7346             : 
    7347             :     /* We must have run out of tuples */
    7348             :     Assert(fsstate->next_tuple >= fsstate->num_tuples);
    7349             : 
    7350             :     /* The core code would have registered postmaster death event */
    7351             :     Assert(GetNumRegisteredWaitEvents(set) >= 1);
    7352             : 
    7353             :     /* Begin an asynchronous data fetch if not already done */
    7354         364 :     if (!pendingAreq)
    7355           8 :         fetch_more_data_begin(areq);
    7356         356 :     else if (pendingAreq->requestor != areq->requestor)
    7357             :     {
    7358             :         /*
    7359             :          * This is the case when the in-process request was made by another
    7360             :          * Append.  Note that it might be useless to process the request made
    7361             :          * by that Append, because the query might not need tuples from that
    7362             :          * Append anymore; so we avoid processing it to begin a fetch for the
    7363             :          * given request if possible.  If there are any child subplans of the
    7364             :          * same parent that are ready for new requests, skip the given
    7365             :          * request.  Likewise, if there are any configured events other than
    7366             :          * the postmaster death event, skip it.  Otherwise, process the
    7367             :          * in-process request, then begin a fetch to configure the event
    7368             :          * below, because we might otherwise end up with no configured events
    7369             :          * other than the postmaster death event.
    7370             :          */
    7371          16 :         if (!bms_is_empty(requestor->as_needrequest))
    7372           0 :             return;
    7373          16 :         if (GetNumRegisteredWaitEvents(set) > 1)
    7374          12 :             return;
    7375           4 :         process_pending_request(pendingAreq);
    7376           4 :         fetch_more_data_begin(areq);
    7377             :     }
    7378         340 :     else if (pendingAreq->requestee != areq->requestee)
    7379             :     {
    7380             :         /*
    7381             :          * This is the case when the in-process request was made by the same
    7382             :          * parent but for a different child.  Since we configure only the
    7383             :          * event for the request made for that child, skip the given request.
    7384             :          */
    7385          16 :         return;
    7386             :     }
    7387             :     else
    7388             :         Assert(pendingAreq == areq);
    7389             : 
    7390         334 :     AddWaitEventToSet(set, WL_SOCKET_READABLE, PQsocket(fsstate->conn),
    7391             :                       NULL, areq);
    7392             : }
    7393             : 
    7394             : /*
    7395             :  * postgresForeignAsyncNotify
    7396             :  *      Fetch some more tuples from a file descriptor that becomes ready,
    7397             :  *      requesting next tuple.
    7398             :  */
    7399             : static void
    7400         296 : postgresForeignAsyncNotify(AsyncRequest *areq)
    7401             : {
    7402         296 :     ForeignScanState *node = (ForeignScanState *) areq->requestee;
    7403         296 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    7404             : 
    7405             :     /* The core code would have initialized the callback_pending flag */
    7406             :     Assert(!areq->callback_pending);
    7407             : 
    7408             :     /*
    7409             :      * If process_pending_request() has been invoked on the given request
    7410             :      * before we get here, we might have some tuples already; in which case
    7411             :      * produce the next tuple
    7412             :      */
    7413         296 :     if (fsstate->next_tuple < fsstate->num_tuples)
    7414             :     {
    7415           0 :         produce_tuple_asynchronously(areq, true);
    7416           0 :         return;
    7417             :     }
    7418             : 
    7419             :     /* We must have run out of tuples */
    7420             :     Assert(fsstate->next_tuple >= fsstate->num_tuples);
    7421             : 
    7422             :     /* The request should be currently in-process */
    7423             :     Assert(fsstate->conn_state->pendingAreq == areq);
    7424             : 
    7425             :     /* On error, report the original query, not the FETCH. */
    7426         296 :     if (!PQconsumeInput(fsstate->conn))
    7427           0 :         pgfdw_report_error(ERROR, NULL, fsstate->conn, false, fsstate->query);
    7428             : 
    7429         296 :     fetch_more_data(node);
    7430             : 
    7431         296 :     produce_tuple_asynchronously(areq, true);
    7432             : }
    7433             : 
    7434             : /*
    7435             :  * Asynchronously produce next tuple from a foreign PostgreSQL table.
    7436             :  */
    7437             : static void
    7438       12656 : produce_tuple_asynchronously(AsyncRequest *areq, bool fetch)
    7439             : {
    7440       12656 :     ForeignScanState *node = (ForeignScanState *) areq->requestee;
    7441       12656 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    7442       12656 :     AsyncRequest *pendingAreq = fsstate->conn_state->pendingAreq;
    7443             :     TupleTableSlot *result;
    7444             : 
    7445             :     /* This should not be called if the request is currently in-process */
    7446             :     Assert(areq != pendingAreq);
    7447             : 
    7448             :     /* Fetch some more tuples, if we've run out */
    7449       12656 :     if (fsstate->next_tuple >= fsstate->num_tuples)
    7450             :     {
    7451             :         /* No point in another fetch if we already detected EOF, though */
    7452         378 :         if (!fsstate->eof_reached)
    7453             :         {
    7454             :             /* Mark the request as pending for a callback */
    7455         258 :             ExecAsyncRequestPending(areq);
    7456             :             /* Begin another fetch if requested and if no pending request */
    7457         258 :             if (fetch && !pendingAreq)
    7458         248 :                 fetch_more_data_begin(areq);
    7459             :         }
    7460             :         else
    7461             :         {
    7462             :             /* There's nothing more to do; just return a NULL pointer */
    7463         120 :             result = NULL;
    7464             :             /* Mark the request as complete */
    7465         120 :             ExecAsyncRequestDone(areq, result);
    7466             :         }
    7467         378 :         return;
    7468             :     }
    7469             : 
    7470             :     /* Get a tuple from the ForeignScan node */
    7471       12278 :     result = areq->requestee->ExecProcNodeReal(areq->requestee);
    7472       12278 :     if (!TupIsNull(result))
    7473             :     {
    7474             :         /* Mark the request as complete */
    7475       12214 :         ExecAsyncRequestDone(areq, result);
    7476       12214 :         return;
    7477             :     }
    7478             : 
    7479             :     /* We must have run out of tuples */
    7480             :     Assert(fsstate->next_tuple >= fsstate->num_tuples);
    7481             : 
    7482             :     /* Fetch some more tuples, if we've not detected EOF yet */
    7483          64 :     if (!fsstate->eof_reached)
    7484             :     {
    7485             :         /* Mark the request as pending for a callback */
    7486          64 :         ExecAsyncRequestPending(areq);
    7487             :         /* Begin another fetch if requested and if no pending request */
    7488          64 :         if (fetch && !pendingAreq)
    7489          60 :             fetch_more_data_begin(areq);
    7490             :     }
    7491             :     else
    7492             :     {
    7493             :         /* There's nothing more to do; just return a NULL pointer */
    7494           0 :         result = NULL;
    7495             :         /* Mark the request as complete */
    7496           0 :         ExecAsyncRequestDone(areq, result);
    7497             :     }
    7498             : }
    7499             : 
    7500             : /*
    7501             :  * Begin an asynchronous data fetch.
    7502             :  *
    7503             :  * Note: this function assumes there is no currently-in-progress asynchronous
    7504             :  * data fetch.
    7505             :  *
    7506             :  * Note: fetch_more_data must be called to fetch the result.
    7507             :  */
    7508             : static void
    7509         320 : fetch_more_data_begin(AsyncRequest *areq)
    7510             : {
    7511         320 :     ForeignScanState *node = (ForeignScanState *) areq->requestee;
    7512         320 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    7513             :     char        sql[64];
    7514             : 
    7515             :     Assert(!fsstate->conn_state->pendingAreq);
    7516             : 
    7517             :     /* Create the cursor synchronously. */
    7518         320 :     if (!fsstate->cursor_exists)
    7519         136 :         create_cursor(node);
    7520             : 
    7521             :     /* We will send this query, but not wait for the response. */
    7522         318 :     snprintf(sql, sizeof(sql), "FETCH %d FROM c%u",
    7523             :              fsstate->fetch_size, fsstate->cursor_number);
    7524             : 
    7525         318 :     if (!PQsendQuery(fsstate->conn, sql))
    7526           0 :         pgfdw_report_error(ERROR, NULL, fsstate->conn, false, fsstate->query);
    7527             : 
    7528             :     /* Remember that the request is in process */
    7529         318 :     fsstate->conn_state->pendingAreq = areq;
    7530         318 : }
    7531             : 
    7532             : /*
    7533             :  * Process a pending asynchronous request.
    7534             :  */
    7535             : void
    7536          18 : process_pending_request(AsyncRequest *areq)
    7537             : {
    7538          18 :     ForeignScanState *node = (ForeignScanState *) areq->requestee;
    7539          18 :     PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
    7540             : 
    7541             :     /* The request would have been pending for a callback */
    7542             :     Assert(areq->callback_pending);
    7543             : 
    7544             :     /* The request should be currently in-process */
    7545             :     Assert(fsstate->conn_state->pendingAreq == areq);
    7546             : 
    7547          18 :     fetch_more_data(node);
    7548             : 
    7549             :     /*
    7550             :      * If we didn't get any tuples, must be end of data; complete the request
    7551             :      * now.  Otherwise, we postpone completing the request until we are called
    7552             :      * from postgresForeignAsyncConfigureWait()/postgresForeignAsyncNotify().
    7553             :      */
    7554          18 :     if (fsstate->next_tuple >= fsstate->num_tuples)
    7555             :     {
    7556             :         /* Unlike AsyncNotify, we unset callback_pending ourselves */
    7557           0 :         areq->callback_pending = false;
    7558             :         /* Mark the request as complete */
    7559           0 :         ExecAsyncRequestDone(areq, NULL);
    7560             :         /* Unlike AsyncNotify, we call ExecAsyncResponse ourselves */
    7561           0 :         ExecAsyncResponse(areq);
    7562             :     }
    7563          18 : }
    7564             : 
    7565             : /*
    7566             :  * Complete a pending asynchronous request.
    7567             :  */
    7568             : static void
    7569          10 : complete_pending_request(AsyncRequest *areq)
    7570             : {
    7571             :     /* The request would have been pending for a callback */
    7572             :     Assert(areq->callback_pending);
    7573             : 
    7574             :     /* Unlike AsyncNotify, we unset callback_pending ourselves */
    7575          10 :     areq->callback_pending = false;
    7576             : 
    7577             :     /* We begin a fetch afterwards if necessary; don't fetch */
    7578          10 :     produce_tuple_asynchronously(areq, false);
    7579             : 
    7580             :     /* Unlike AsyncNotify, we call ExecAsyncResponse ourselves */
    7581          10 :     ExecAsyncResponse(areq);
    7582             : 
    7583             :     /* Also, we do instrumentation ourselves, if required */
    7584          10 :     if (areq->requestee->instrument)
    7585           2 :         InstrUpdateTupleCount(areq->requestee->instrument,
    7586           2 :                               TupIsNull(areq->result) ? 0.0 : 1.0);
    7587          10 : }
    7588             : 
    7589             : /*
    7590             :  * Create a tuple from the specified row of the PGresult.
    7591             :  *
    7592             :  * rel is the local representation of the foreign table, attinmeta is
    7593             :  * conversion data for the rel's tupdesc, and retrieved_attrs is an
    7594             :  * integer list of the table column numbers present in the PGresult.
    7595             :  * fsstate is the ForeignScan plan node's execution state.
    7596             :  * temp_context is a working context that can be reset after each tuple.
    7597             :  *
    7598             :  * Note: either rel or fsstate, but not both, can be NULL.  rel is NULL
    7599             :  * if we're processing a remote join, while fsstate is NULL in a non-query
    7600             :  * context such as ANALYZE, or if we're processing a non-scan query node.
    7601             :  */
    7602             : static HeapTuple
    7603      178786 : make_tuple_from_result_row(PGresult *res,
    7604             :                            int row,
    7605             :                            Relation rel,
    7606             :                            AttInMetadata *attinmeta,
    7607             :                            List *retrieved_attrs,
    7608             :                            ForeignScanState *fsstate,
    7609             :                            MemoryContext temp_context)
    7610             : {
    7611             :     HeapTuple   tuple;
    7612             :     TupleDesc   tupdesc;
    7613             :     Datum      *values;
    7614             :     bool       *nulls;
    7615      178786 :     ItemPointer ctid = NULL;
    7616             :     ConversionLocation errpos;
    7617             :     ErrorContextCallback errcallback;
    7618             :     MemoryContext oldcontext;
    7619             :     ListCell   *lc;
    7620             :     int         j;
    7621             : 
    7622             :     Assert(row < PQntuples(res));
    7623             : 
    7624             :     /*
    7625             :      * Do the following work in a temp context that we reset after each tuple.
    7626             :      * This cleans up not only the data we have direct access to, but any
    7627             :      * cruft the I/O functions might leak.
    7628             :      */
    7629      178786 :     oldcontext = MemoryContextSwitchTo(temp_context);
    7630             : 
    7631             :     /*
    7632             :      * Get the tuple descriptor for the row.  Use the rel's tupdesc if rel is
    7633             :      * provided, otherwise look to the scan node's ScanTupleSlot.
    7634             :      */
    7635      178786 :     if (rel)
    7636      106890 :         tupdesc = RelationGetDescr(rel);
    7637             :     else
    7638             :     {
    7639             :         Assert(fsstate);
    7640       71896 :         tupdesc = fsstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
    7641             :     }
    7642             : 
    7643      178786 :     values = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
    7644      178786 :     nulls = (bool *) palloc(tupdesc->natts * sizeof(bool));
    7645             :     /* Initialize to nulls for any columns not present in result */
    7646      178786 :     memset(nulls, true, tupdesc->natts * sizeof(bool));
    7647             : 
    7648             :     /*
    7649             :      * Set up and install callback to report where conversion error occurs.
    7650             :      */
    7651      178786 :     errpos.cur_attno = 0;
    7652      178786 :     errpos.rel = rel;
    7653      178786 :     errpos.fsstate = fsstate;
    7654      178786 :     errcallback.callback = conversion_error_callback;
    7655      178786 :     errcallback.arg = &errpos;
    7656      178786 :     errcallback.previous = error_context_stack;
    7657      178786 :     error_context_stack = &errcallback;
    7658             : 
    7659             :     /*
    7660             :      * i indexes columns in the relation, j indexes columns in the PGresult.
    7661             :      */
    7662      178786 :     j = 0;
    7663      667950 :     foreach(lc, retrieved_attrs)
    7664             :     {
    7665      489174 :         int         i = lfirst_int(lc);
    7666             :         char       *valstr;
    7667             : 
    7668             :         /* fetch next column's textual value */
    7669      489174 :         if (PQgetisnull(res, row, j))
    7670        1506 :             valstr = NULL;
    7671             :         else
    7672      487668 :             valstr = PQgetvalue(res, row, j);
    7673             : 
    7674             :         /*
    7675             :          * convert value to internal representation
    7676             :          *
    7677             :          * Note: we ignore system columns other than ctid and oid in result
    7678             :          */
    7679      489174 :         errpos.cur_attno = i;
    7680      489174 :         if (i > 0)
    7681             :         {
    7682             :             /* ordinary column */
    7683             :             Assert(i <= tupdesc->natts);
    7684      482948 :             nulls[i - 1] = (valstr == NULL);
    7685             :             /* Apply the input function even to nulls, to support domains */
    7686      482938 :             values[i - 1] = InputFunctionCall(&attinmeta->attinfuncs[i - 1],
    7687             :                                               valstr,
    7688      482948 :                                               attinmeta->attioparams[i - 1],
    7689      482948 :                                               attinmeta->atttypmods[i - 1]);
    7690             :         }
    7691        6226 :         else if (i == SelfItemPointerAttributeNumber)
    7692             :         {
    7693             :             /* ctid */
    7694        6226 :             if (valstr != NULL)
    7695             :             {
    7696             :                 Datum       datum;
    7697             : 
    7698        6226 :                 datum = DirectFunctionCall1(tidin, CStringGetDatum(valstr));
    7699        6226 :                 ctid = (ItemPointer) DatumGetPointer(datum);
    7700             :             }
    7701             :         }
    7702      489164 :         errpos.cur_attno = 0;
    7703             : 
    7704      489164 :         j++;
    7705             :     }
    7706             : 
    7707             :     /* Uninstall error context callback. */
    7708      178776 :     error_context_stack = errcallback.previous;
    7709             : 
    7710             :     /*
    7711             :      * Check we got the expected number of columns.  Note: j == 0 and
    7712             :      * PQnfields == 1 is expected, since deparse emits a NULL if no columns.
    7713             :      */
    7714      178776 :     if (j > 0 && j != PQnfields(res))
    7715           0 :         elog(ERROR, "remote query result does not match the foreign table");
    7716             : 
    7717             :     /*
    7718             :      * Build the result tuple in caller's memory context.
    7719             :      */
    7720      178776 :     MemoryContextSwitchTo(oldcontext);
    7721             : 
    7722      178776 :     tuple = heap_form_tuple(tupdesc, values, nulls);
    7723             : 
    7724             :     /*
    7725             :      * If we have a CTID to return, install it in both t_self and t_ctid.
    7726             :      * t_self is the normal place, but if the tuple is converted to a
    7727             :      * composite Datum, t_self will be lost; setting t_ctid allows CTID to be
    7728             :      * preserved during EvalPlanQual re-evaluations (see ROW_MARK_COPY code).
    7729             :      */
    7730      178776 :     if (ctid)
    7731        6226 :         tuple->t_self = tuple->t_data->t_ctid = *ctid;
    7732             : 
    7733             :     /*
    7734             :      * Stomp on the xmin, xmax, and cmin fields from the tuple created by
    7735             :      * heap_form_tuple.  heap_form_tuple actually creates the tuple with
    7736             :      * DatumTupleFields, not HeapTupleFields, but the executor expects
    7737             :      * HeapTupleFields and will happily extract system columns on that
    7738             :      * assumption.  If we don't do this then, for example, the tuple length
    7739             :      * ends up in the xmin field, which isn't what we want.
    7740             :      */
    7741      178776 :     HeapTupleHeaderSetXmax(tuple->t_data, InvalidTransactionId);
    7742      178776 :     HeapTupleHeaderSetXmin(tuple->t_data, InvalidTransactionId);
    7743      178776 :     HeapTupleHeaderSetCmin(tuple->t_data, InvalidTransactionId);
    7744             : 
    7745             :     /* Clean up */
    7746      178776 :     MemoryContextReset(temp_context);
    7747             : 
    7748      178776 :     return tuple;
    7749             : }
    7750             : 
    7751             : /*
    7752             :  * Callback function which is called when error occurs during column value
    7753             :  * conversion.  Print names of column and relation.
    7754             :  *
    7755             :  * Note that this function mustn't do any catalog lookups, since we are in
    7756             :  * an already-failed transaction.  Fortunately, we can get the needed info
    7757             :  * from the relation or the query's rangetable instead.
    7758             :  */
    7759             : static void
    7760          10 : conversion_error_callback(void *arg)
    7761             : {
    7762          10 :     ConversionLocation *errpos = (ConversionLocation *) arg;
    7763          10 :     Relation    rel = errpos->rel;
    7764          10 :     ForeignScanState *fsstate = errpos->fsstate;
    7765          10 :     const char *attname = NULL;
    7766          10 :     const char *relname = NULL;
    7767          10 :     bool        is_wholerow = false;
    7768             : 
    7769             :     /*
    7770             :      * If we're in a scan node, always use aliases from the rangetable, for
    7771             :      * consistency between the simple-relation and remote-join cases.  Look at
    7772             :      * the relation's tupdesc only if we're not in a scan node.
    7773             :      */
    7774          10 :     if (fsstate)
    7775             :     {
    7776             :         /* ForeignScan case */
    7777           8 :         ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
    7778           8 :         int         varno = 0;
    7779           8 :         AttrNumber  colno = 0;
    7780             : 
    7781           8 :         if (fsplan->scan.scanrelid > 0)
    7782             :         {
    7783             :             /* error occurred in a scan against a foreign table */
    7784           2 :             varno = fsplan->scan.scanrelid;
    7785           2 :             colno = errpos->cur_attno;
    7786             :         }
    7787             :         else
    7788             :         {
    7789             :             /* error occurred in a scan against a foreign join */
    7790             :             TargetEntry *tle;
    7791             : 
    7792           6 :             tle = list_nth_node(TargetEntry, fsplan->fdw_scan_tlist,
    7793             :                                 errpos->cur_attno - 1);
    7794             : 
    7795             :             /*
    7796             :              * Target list can have Vars and expressions.  For Vars, we can
    7797             :              * get some information, however for expressions we can't.  Thus
    7798             :              * for expressions, just show generic context message.
    7799             :              */
    7800           6 :             if (IsA(tle->expr, Var))
    7801             :             {
    7802           4 :                 Var        *var = (Var *) tle->expr;
    7803             : 
    7804           4 :                 varno = var->varno;
    7805           4 :                 colno = var->varattno;
    7806             :             }
    7807             :         }
    7808             : 
    7809           8 :         if (varno > 0)
    7810             :         {
    7811           6 :             EState     *estate = fsstate->ss.ps.state;
    7812           6 :             RangeTblEntry *rte = exec_rt_fetch(varno, estate);
    7813             : 
    7814           6 :             relname = rte->eref->aliasname;
    7815             : 
    7816           6 :             if (colno == 0)
    7817           2 :                 is_wholerow = true;
    7818           4 :             else if (colno > 0 && colno <= list_length(rte->eref->colnames))
    7819           4 :                 attname = strVal(list_nth(rte->eref->colnames, colno - 1));
    7820           0 :             else if (colno == SelfItemPointerAttributeNumber)
    7821           0 :                 attname = "ctid";
    7822             :         }
    7823             :     }
    7824           2 :     else if (rel)
    7825             :     {
    7826             :         /* Non-ForeignScan case (we should always have a rel here) */
    7827           2 :         TupleDesc   tupdesc = RelationGetDescr(rel);
    7828             : 
    7829           2 :         relname = RelationGetRelationName(rel);
    7830           2 :         if (errpos->cur_attno > 0 && errpos->cur_attno <= tupdesc->natts)
    7831           2 :         {
    7832           2 :             Form_pg_attribute attr = TupleDescAttr(tupdesc,
    7833           2 :                                                    errpos->cur_attno - 1);
    7834             : 
    7835           2 :             attname = NameStr(attr->attname);
    7836             :         }
    7837           0 :         else if (errpos->cur_attno == SelfItemPointerAttributeNumber)
    7838           0 :             attname = "ctid";
    7839             :     }
    7840             : 
    7841          10 :     if (relname && is_wholerow)
    7842           2 :         errcontext("whole-row reference to foreign table \"%s\"", relname);
    7843           8 :     else if (relname && attname)
    7844           6 :         errcontext("column \"%s\" of foreign table \"%s\"", attname, relname);
    7845             :     else
    7846           2 :         errcontext("processing expression at position %d in select list",
    7847           2 :                    errpos->cur_attno);
    7848          10 : }
    7849             : 
    7850             : /*
    7851             :  * Given an EquivalenceClass and a foreign relation, find an EC member
    7852             :  * that can be used to sort the relation remotely according to a pathkey
    7853             :  * using this EC.
    7854             :  *
    7855             :  * If there is more than one suitable candidate, return an arbitrary
    7856             :  * one of them.  If there is none, return NULL.
    7857             :  *
    7858             :  * This checks that the EC member expression uses only Vars from the given
    7859             :  * rel and is shippable.  Caller must separately verify that the pathkey's
    7860             :  * ordering operator is shippable.
    7861             :  */
    7862             : EquivalenceMember *
    7863        3600 : find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
    7864             : {
    7865        3600 :     PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
    7866             :     EquivalenceMemberIterator it;
    7867             :     EquivalenceMember *em;
    7868             : 
    7869        3600 :     setup_eclass_member_iterator(&it, ec, rel->relids);
    7870        6010 :     while ((em = eclass_member_iterator_next(&it)) != NULL)
    7871             :     {
    7872             :         /*
    7873             :          * Note we require !bms_is_empty, else we'd accept constant
    7874             :          * expressions which are not suitable for the purpose.
    7875             :          */
    7876        5450 :         if (bms_is_subset(em->em_relids, rel->relids) &&
    7877        6194 :             !bms_is_empty(em->em_relids) &&
    7878        6168 :             bms_is_empty(bms_intersect(em->em_relids, fpinfo->hidden_subquery_rels)) &&
    7879        3072 :             is_foreign_expr(root, rel, em->em_expr))
    7880        3040 :             return em;
    7881             :     }
    7882             : 
    7883         560 :     return NULL;
    7884             : }
    7885             : 
    7886             : /*
    7887             :  * Find an EquivalenceClass member that is to be computed as a sort column
    7888             :  * in the given rel's reltarget, and is shippable.
    7889             :  *
    7890             :  * If there is more than one suitable candidate, return an arbitrary
    7891             :  * one of them.  If there is none, return NULL.
    7892             :  *
    7893             :  * This checks that the EC member expression uses only Vars from the given
    7894             :  * rel and is shippable.  Caller must separately verify that the pathkey's
    7895             :  * ordering operator is shippable.
    7896             :  */
    7897             : EquivalenceMember *
    7898         510 : find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec,
    7899             :                        RelOptInfo *rel)
    7900             : {
    7901         510 :     PathTarget *target = rel->reltarget;
    7902             :     ListCell   *lc1;
    7903             :     int         i;
    7904             : 
    7905         510 :     i = 0;
    7906         850 :     foreach(lc1, target->exprs)
    7907             :     {
    7908         850 :         Expr       *expr = (Expr *) lfirst(lc1);
    7909         850 :         Index       sgref = get_pathtarget_sortgroupref(target, i);
    7910             :         ListCell   *lc2;
    7911             : 
    7912             :         /* Ignore non-sort expressions */
    7913        1530 :         if (sgref == 0 ||
    7914         680 :             get_sortgroupref_clause_noerr(sgref,
    7915         680 :                                           root->parse->sortClause) == NULL)
    7916             :         {
    7917         186 :             i++;
    7918         186 :             continue;
    7919             :         }
    7920             : 
    7921             :         /* We ignore binary-compatible relabeling on both ends */
    7922         664 :         while (expr && IsA(expr, RelabelType))
    7923           0 :             expr = ((RelabelType *) expr)->arg;
    7924             : 
    7925             :         /*
    7926             :          * Locate an EquivalenceClass member matching this expr, if any.
    7927             :          * Ignore child members.
    7928             :          */
    7929         826 :         foreach(lc2, ec->ec_members)
    7930             :         {
    7931         672 :             EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2);
    7932             :             Expr       *em_expr;
    7933             : 
    7934             :             /* Don't match constants */
    7935         672 :             if (em->em_is_const)
    7936           0 :                 continue;
    7937             : 
    7938             :             /* Child members should not exist in ec_members */
    7939             :             Assert(!em->em_is_child);
    7940             : 
    7941             :             /* Match if same expression (after stripping relabel) */
    7942         672 :             em_expr = em->em_expr;
    7943         696 :             while (em_expr && IsA(em_expr, RelabelType))
    7944          24 :                 em_expr = ((RelabelType *) em_expr)->arg;
    7945             : 
    7946         672 :             if (!equal(em_expr, expr))
    7947         162 :                 continue;
    7948             : 
    7949             :             /* Check that expression (including relabels!) is shippable */
    7950         510 :             if (is_foreign_expr(root, rel, em->em_expr))
    7951         510 :                 return em;
    7952             :         }
    7953             : 
    7954         154 :         i++;
    7955             :     }
    7956             : 
    7957           0 :     return NULL;
    7958             : }
    7959             : 
    7960             : /*
    7961             :  * Determine batch size for a given foreign table. The option specified for
    7962             :  * a table has precedence.
    7963             :  */
    7964             : static int
    7965         282 : get_batch_size_option(Relation rel)
    7966             : {
    7967         282 :     Oid         foreigntableid = RelationGetRelid(rel);
    7968             :     ForeignTable *table;
    7969             :     ForeignServer *server;
    7970             :     List       *options;
    7971             :     ListCell   *lc;
    7972             : 
    7973             :     /* we use 1 by default, which means "no batching" */
    7974         282 :     int         batch_size = 1;
    7975             : 
    7976             :     /*
    7977             :      * Load options for table and server. We append server options after table
    7978             :      * options, because table options take precedence.
    7979             :      */
    7980         282 :     table = GetForeignTable(foreigntableid);
    7981         282 :     server = GetForeignServer(table->serverid);
    7982             : 
    7983         282 :     options = NIL;
    7984         282 :     options = list_concat(options, table->options);
    7985         282 :     options = list_concat(options, server->options);
    7986             : 
    7987             :     /* See if either table or server specifies batch_size. */
    7988        1482 :     foreach(lc, options)
    7989             :     {
    7990        1266 :         DefElem    *def = (DefElem *) lfirst(lc);
    7991             : 
    7992        1266 :         if (strcmp(def->defname, "batch_size") == 0)
    7993             :         {
    7994          66 :             (void) parse_int(defGetString(def), &batch_size, 0, NULL);
    7995          66 :             break;
    7996             :         }
    7997             :     }
    7998             : 
    7999         282 :     return batch_size;
    8000             : }

Generated by: LCOV version 1.16