LCOV - differential code coverage report
Current view: top level - contrib/postgres_fdw - postgres_fdw.c (source / functions) Coverage Total Hit UNC UIC UBC GBC GIC GNC CBC ECB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 92.2 % 2348 2166 3 179 2 41 2123 8
Current Date: 2024-04-14 14:21:10 Functions: 98.9 % 89 88 1 11 77
Baseline: 16@8cea358b128 Branches: 75.3 % 1741 1311 6 2 422 5 7 28 1271 4
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (60,120] days: 100.0 % 5 5 5
(120,180] days: 91.9 % 37 34 3 34
(240..) days: 92.2 % 2306 2127 179 2 2 2123
Function coverage date bins:
(120,180] days: 100.0 % 1 1 1
(240..) days: 98.9 % 88 87 1 10 77
Branch coverage date bins:
(120,180] days: 82.4 % 34 28 6 28
(240..) days: 75.0 % 1711 1283 2 422 5 7 1271 4

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

Generated by: LCOV version 2.1-beta2-3-g6141622