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

Generated by: LCOV version 2.3.2-1