LCOV - differential code coverage report
Current view: top level - contrib/postgres_fdw - postgres_fdw.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GNC CBC EUB ECB DUB DCB
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 93.2 % 2321 2163 26 2 130 2 156 2005 1 1 33 190
Current Date: 2025-09-06 07:49:51 +0900 Functions: 98.9 % 89 88 1 19 69
Baseline: lcov-20250906-005545-baseline Branches: 76.0 % 1703 1295 39 2 367 1 105 1189 2
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 84.8 % 211 179 26 6 156 23 1
(360..) days: 94.0 % 2110 1984 2 124 2 1982 1
Function coverage date bins:
(30,360] days: 100.0 % 1 1 1
(360..) days: 98.9 % 88 87 1 19 68
Branch coverage date bins:
(30,360] days: 71.2 % 160 114 39 7 105 9
(360..) days: 76.4 % 1545 1181 2 360 1 1180 2

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

Generated by: LCOV version 2.4-beta