PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
postgres_fdw.c File Reference
#include "postgres.h"
#include "postgres_fdw.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/pg_class.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/vacuum.h"
#include "foreign/fdwapi.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
#include "optimizer/clauses.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/var.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/sampling.h"
#include "utils/selfuncs.h"
Include dependency graph for postgres_fdw.c:

Go to the source code of this file.

Data Structures

struct  PgFdwScanState
 
struct  PgFdwModifyState
 
struct  PgFdwDirectModifyState
 
struct  PgFdwAnalyzeState
 
struct  ConversionLocation
 
struct  ec_member_foreign_arg
 

Macros

#define DEFAULT_FDW_STARTUP_COST   100.0
 
#define DEFAULT_FDW_TUPLE_COST   0.01
 
#define DEFAULT_FDW_SORT_MULTIPLIER   1.2
 

Typedefs

typedef struct PgFdwScanState PgFdwScanState
 
typedef struct PgFdwModifyState PgFdwModifyState
 
typedef struct
PgFdwDirectModifyState 
PgFdwDirectModifyState
 
typedef struct PgFdwAnalyzeState PgFdwAnalyzeState
 
typedef struct ConversionLocation ConversionLocation
 

Enumerations

enum  FdwScanPrivateIndex { FdwScanPrivateSelectSql, FdwScanPrivateRetrievedAttrs, FdwScanPrivateFetchSize, FdwScanPrivateRelations }
 
enum  FdwModifyPrivateIndex { FdwModifyPrivateUpdateSql, FdwModifyPrivateTargetAttnums, FdwModifyPrivateHasReturning, FdwModifyPrivateRetrievedAttrs }
 
enum  FdwDirectModifyPrivateIndex { FdwDirectModifyPrivateUpdateSql, FdwDirectModifyPrivateHasReturning, FdwDirectModifyPrivateRetrievedAttrs, FdwDirectModifyPrivateSetProcessed }
 

Functions

 PG_FUNCTION_INFO_V1 (postgres_fdw_handler)
 
static void postgresGetForeignRelSize (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
 
static void postgresGetForeignPaths (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
 
static ForeignScanpostgresGetForeignPlan (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan)
 
static void postgresBeginForeignScan (ForeignScanState *node, int eflags)
 
static TupleTableSlotpostgresIterateForeignScan (ForeignScanState *node)
 
static void postgresReScanForeignScan (ForeignScanState *node)
 
static void postgresEndForeignScan (ForeignScanState *node)
 
static void postgresAddForeignUpdateTargets (Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
 
static ListpostgresPlanForeignModify (PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index)
 
static void postgresBeginForeignModify (ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, List *fdw_private, int subplan_index, int eflags)
 
static TupleTableSlotpostgresExecForeignInsert (EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
 
static TupleTableSlotpostgresExecForeignUpdate (EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
 
static TupleTableSlotpostgresExecForeignDelete (EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
 
static void postgresEndForeignModify (EState *estate, ResultRelInfo *resultRelInfo)
 
static int postgresIsForeignRelUpdatable (Relation rel)
 
static bool postgresPlanDirectModify (PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index)
 
static void postgresBeginDirectModify (ForeignScanState *node, int eflags)
 
static TupleTableSlotpostgresIterateDirectModify (ForeignScanState *node)
 
static void postgresEndDirectModify (ForeignScanState *node)
 
static void postgresExplainForeignScan (ForeignScanState *node, ExplainState *es)
 
static void postgresExplainForeignModify (ModifyTableState *mtstate, ResultRelInfo *rinfo, List *fdw_private, int subplan_index, ExplainState *es)
 
static void postgresExplainDirectModify (ForeignScanState *node, ExplainState *es)
 
static bool postgresAnalyzeForeignTable (Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages)
 
static ListpostgresImportForeignSchema (ImportForeignSchemaStmt *stmt, Oid serverOid)
 
static void postgresGetForeignJoinPaths (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
 
static bool postgresRecheckForeignScan (ForeignScanState *node, TupleTableSlot *slot)
 
static void postgresGetForeignUpperPaths (PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel)
 
static void estimate_path_cost_size (PlannerInfo *root, RelOptInfo *baserel, List *join_conds, List *pathkeys, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost)
 
static void get_remote_estimate (const char *sql, PGconn *conn, double *rows, int *width, Cost *startup_cost, Cost *total_cost)
 
static bool ec_member_matches_foreign (PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
 
static void create_cursor (ForeignScanState *node)
 
static void fetch_more_data (ForeignScanState *node)
 
static void close_cursor (PGconn *conn, unsigned int cursor_number)
 
static void prepare_foreign_modify (PgFdwModifyState *fmstate)
 
static const char ** convert_prep_stmt_params (PgFdwModifyState *fmstate, ItemPointer tupleid, TupleTableSlot *slot)
 
static void store_returning_result (PgFdwModifyState *fmstate, TupleTableSlot *slot, PGresult *res)
 
static void execute_dml_stmt (ForeignScanState *node)
 
static TupleTableSlotget_returning_data (ForeignScanState *node)
 
static void prepare_query_params (PlanState *node, List *fdw_exprs, int numParams, FmgrInfo **param_flinfo, List **param_exprs, const char ***param_values)
 
static void process_query_params (ExprContext *econtext, FmgrInfo *param_flinfo, List *param_exprs, const char **param_values)
 
static int postgresAcquireSampleRowsFunc (Relation relation, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
 
static void analyze_row_processor (PGresult *res, int row, PgFdwAnalyzeState *astate)
 
static HeapTuple make_tuple_from_result_row (PGresult *res, int row, Relation rel, AttInMetadata *attinmeta, List *retrieved_attrs, ForeignScanState *fsstate, MemoryContext temp_context)
 
static void conversion_error_callback (void *arg)
 
static bool foreign_join_ok (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinPathExtraData *extra)
 
static bool foreign_grouping_ok (PlannerInfo *root, RelOptInfo *grouped_rel)
 
static Listget_useful_pathkeys_for_relation (PlannerInfo *root, RelOptInfo *rel)
 
static Listget_useful_ecs_for_relation (PlannerInfo *root, RelOptInfo *rel)
 
static void add_paths_with_pathkeys_for_rel (PlannerInfo *root, RelOptInfo *rel, Path *epq_path)
 
static void add_foreign_grouping_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel)
 
static void apply_server_options (PgFdwRelationInfo *fpinfo)
 
static void apply_table_options (PgFdwRelationInfo *fpinfo)
 
static void merge_fdw_options (PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_o, const PgFdwRelationInfo *fpinfo_i)
 
Datum postgres_fdw_handler (PG_FUNCTION_ARGS)
 
int set_transmission_modes (void)
 
void reset_transmission_modes (int nestlevel)
 
Exprfind_em_expr_for_rel (EquivalenceClass *ec, RelOptInfo *rel)
 

Variables

 PG_MODULE_MAGIC
 

Macro Definition Documentation

#define DEFAULT_FDW_SORT_MULTIPLIER   1.2

Definition at line 54 of file postgres_fdw.c.

Referenced by estimate_path_cost_size().

#define DEFAULT_FDW_STARTUP_COST   100.0

Definition at line 48 of file postgres_fdw.c.

Referenced by postgresGetForeignRelSize().

#define DEFAULT_FDW_TUPLE_COST   0.01

Definition at line 51 of file postgres_fdw.c.

Referenced by postgresGetForeignRelSize().

Typedef Documentation

Enumeration Type Documentation

Enumerator
FdwDirectModifyPrivateUpdateSql 
FdwDirectModifyPrivateHasReturning 
FdwDirectModifyPrivateRetrievedAttrs 
FdwDirectModifyPrivateSetProcessed 

Definition at line 110 of file postgres_fdw.c.

111 {
112  /* SQL statement to execute remotely (as a String node) */
114  /* has-returning flag (as an integer Value node) */
116  /* Integer list of attribute numbers retrieved by RETURNING */
118  /* set-processed flag (as an integer Value node) */
120 };
Enumerator
FdwModifyPrivateUpdateSql 
FdwModifyPrivateTargetAttnums 
FdwModifyPrivateHasReturning 
FdwModifyPrivateRetrievedAttrs 

Definition at line 89 of file postgres_fdw.c.

90 {
91  /* SQL statement to execute remotely (as a String node) */
93  /* Integer list of target attribute numbers for INSERT/UPDATE */
95  /* has-returning flag (as an integer Value node) */
97  /* Integer list of attribute numbers retrieved by RETURNING */
99 };
Enumerator
FdwScanPrivateSelectSql 
FdwScanPrivateRetrievedAttrs 
FdwScanPrivateFetchSize 
FdwScanPrivateRelations 

Definition at line 63 of file postgres_fdw.c.

64 {
65  /* SQL statement to execute remotely (as a String node) */
67  /* Integer list of attribute numbers retrieved by the SELECT */
69  /* Integer representing the desired fetch_size */
71 
72  /*
73  * String describing join i.e. names of relations being joined and types
74  * of join, added when the scan is join
75  */
77 };

Function Documentation

static void add_foreign_grouping_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo grouped_rel 
)
static

Definition at line 4842 of file postgres_fdw.c.

References add_path(), create_foreignscan_path(), estimate_path_cost_size(), RelOptInfo::fdw_private, foreign_grouping_ok(), Query::groupClause, Query::groupingSets, Query::hasAggs, PlannerInfo::hasHavingQual, merge_fdw_options(), NIL, NULL, PgFdwRelationInfo::outerrel, parse(), PlannerInfo::parse, PgFdwRelationInfo::rows, PgFdwRelationInfo::server, PgFdwRelationInfo::startup_cost, PgFdwRelationInfo::table, PgFdwRelationInfo::total_cost, PlannerInfo::upper_targets, UPPERREL_GROUP_AGG, PgFdwRelationInfo::user, and PgFdwRelationInfo::width.

Referenced by postgresGetForeignUpperPaths().

4844 {
4845  Query *parse = root->parse;
4846  PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
4847  PgFdwRelationInfo *fpinfo = grouped_rel->fdw_private;
4848  ForeignPath *grouppath;
4849  PathTarget *grouping_target;
4850  double rows;
4851  int width;
4852  Cost startup_cost;
4853  Cost total_cost;
4854 
4855  /* Nothing to be done, if there is no grouping or aggregation required. */
4856  if (!parse->groupClause && !parse->groupingSets && !parse->hasAggs &&
4857  !root->hasHavingQual)
4858  return;
4859 
4860  grouping_target = root->upper_targets[UPPERREL_GROUP_AGG];
4861 
4862  /* save the input_rel as outerrel in fpinfo */
4863  fpinfo->outerrel = input_rel;
4864 
4865  /*
4866  * Copy foreign table, foreign server, user mapping, FDW options etc.
4867  * details from the input relation's fpinfo.
4868  */
4869  fpinfo->table = ifpinfo->table;
4870  fpinfo->server = ifpinfo->server;
4871  fpinfo->user = ifpinfo->user;
4872  merge_fdw_options(fpinfo, ifpinfo , NULL);
4873 
4874  /* Assess if it is safe to push down aggregation and grouping. */
4875  if (!foreign_grouping_ok(root, grouped_rel))
4876  return;
4877 
4878  /* Estimate the cost of push down */
4879  estimate_path_cost_size(root, grouped_rel, NIL, NIL, &rows,
4880  &width, &startup_cost, &total_cost);
4881 
4882  /* Now update this information in the fpinfo */
4883  fpinfo->rows = rows;
4884  fpinfo->width = width;
4885  fpinfo->startup_cost = startup_cost;
4886  fpinfo->total_cost = total_cost;
4887 
4888  /* Create and add foreign path to the grouping relation. */
4889  grouppath = create_foreignscan_path(root,
4890  grouped_rel,
4891  grouping_target,
4892  rows,
4893  startup_cost,
4894  total_cost,
4895  NIL, /* no pathkeys */
4896  NULL, /* no required_outer */
4897  NULL,
4898  NIL); /* no fdw_private */
4899 
4900  /* Add generated path into grouped_rel by add_path(). */
4901  add_path(grouped_rel, (Path *) grouppath);
4902 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:154
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:412
bool hasAggs
Definition: parsenodes.h:123
ForeignServer * server
Definition: postgres_fdw.h:76
List * groupingSets
Definition: parsenodes.h:148
RelOptInfo * outerrel
Definition: postgres_fdw.h:89
static void merge_fdw_options(PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_o, const PgFdwRelationInfo *fpinfo_i)
ForeignPath * create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_private)
Definition: pathnode.c:1961
UserMapping * user
Definition: postgres_fdw.h:77
static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel)
void * fdw_private
Definition: relation.h:576
#define NULL
Definition: c.h:229
static void estimate_path_cost_size(PlannerInfo *root, RelOptInfo *baserel, List *join_conds, List *pathkeys, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost)
ForeignTable * table
Definition: postgres_fdw.h:75
List * groupClause
Definition: parsenodes.h:146
bool hasHavingQual
Definition: relation.h:301
Definition: relation.h:946
double Cost
Definition: nodes.h:639
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: relation.h:274
static void add_paths_with_pathkeys_for_rel ( PlannerInfo root,
RelOptInfo rel,
Path epq_path 
)
static

Definition at line 4316 of file postgres_fdw.c.

References add_path(), create_foreignscan_path(), estimate_path_cost_size(), get_useful_pathkeys_for_relation(), lfirst, NIL, and NULL.

Referenced by postgresGetForeignJoinPaths(), and postgresGetForeignPaths().

4318 {
4319  List *useful_pathkeys_list = NIL; /* List of all pathkeys */
4320  ListCell *lc;
4321 
4322  useful_pathkeys_list = get_useful_pathkeys_for_relation(root, rel);
4323 
4324  /* Create one path for each set of pathkeys we found above. */
4325  foreach(lc, useful_pathkeys_list)
4326  {
4327  double rows;
4328  int width;
4329  Cost startup_cost;
4330  Cost total_cost;
4331  List *useful_pathkeys = lfirst(lc);
4332 
4333  estimate_path_cost_size(root, rel, NIL, useful_pathkeys,
4334  &rows, &width, &startup_cost, &total_cost);
4335 
4336  add_path(rel, (Path *)
4337  create_foreignscan_path(root, rel,
4338  NULL,
4339  rows,
4340  startup_cost,
4341  total_cost,
4342  useful_pathkeys,
4343  NULL,
4344  epq_path,
4345  NIL));
4346  }
4347 }
#define NIL
Definition: pg_list.h:69
static List * get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition: postgres_fdw.c:778
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:412
ForeignPath * create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_private)
Definition: pathnode.c:1961
#define NULL
Definition: c.h:229
static void estimate_path_cost_size(PlannerInfo *root, RelOptInfo *baserel, List *join_conds, List *pathkeys, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost)
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45
Definition: relation.h:946
double Cost
Definition: nodes.h:639
static void analyze_row_processor ( PGresult res,
int  row,
PgFdwAnalyzeState astate 
)
static

Definition at line 3711 of file postgres_fdw.c.

References PgFdwAnalyzeState::anl_cxt, Assert, PgFdwAnalyzeState::attinmeta, heap_freetuple(), make_tuple_from_result_row(), MemoryContextSwitchTo(), NULL, PgFdwAnalyzeState::numrows, ReservoirStateData::randstate, PgFdwAnalyzeState::rel, reservoir_get_next_S(), PgFdwAnalyzeState::retrieved_attrs, PgFdwAnalyzeState::rows, PgFdwAnalyzeState::rowstoskip, PgFdwAnalyzeState::rstate, sampler_random_fract(), PgFdwAnalyzeState::samplerows, PgFdwAnalyzeState::targrows, and PgFdwAnalyzeState::temp_cxt.

Referenced by postgresAcquireSampleRowsFunc().

3712 {
3713  int targrows = astate->targrows;
3714  int pos; /* array index to store tuple in */
3715  MemoryContext oldcontext;
3716 
3717  /* Always increment sample row counter. */
3718  astate->samplerows += 1;
3719 
3720  /*
3721  * Determine the slot where this sample row should be stored. Set pos to
3722  * negative value to indicate the row should be skipped.
3723  */
3724  if (astate->numrows < targrows)
3725  {
3726  /* First targrows rows are always included into the sample */
3727  pos = astate->numrows++;
3728  }
3729  else
3730  {
3731  /*
3732  * Now we start replacing tuples in the sample until we reach the end
3733  * of the relation. Same algorithm as in acquire_sample_rows in
3734  * analyze.c; see Jeff Vitter's paper.
3735  */
3736  if (astate->rowstoskip < 0)
3737  astate->rowstoskip = reservoir_get_next_S(&astate->rstate, astate->samplerows, targrows);
3738 
3739  if (astate->rowstoskip <= 0)
3740  {
3741  /* Choose a random reservoir element to replace. */
3742  pos = (int) (targrows * sampler_random_fract(astate->rstate.randstate));
3743  Assert(pos >= 0 && pos < targrows);
3744  heap_freetuple(astate->rows[pos]);
3745  }
3746  else
3747  {
3748  /* Skip this tuple. */
3749  pos = -1;
3750  }
3751 
3752  astate->rowstoskip -= 1;
3753  }
3754 
3755  if (pos >= 0)
3756  {
3757  /*
3758  * Create sample tuple from current result row, and store it in the
3759  * position determined above. The tuple has to be created in anl_cxt.
3760  */
3761  oldcontext = MemoryContextSwitchTo(astate->anl_cxt);
3762 
3763  astate->rows[pos] = make_tuple_from_result_row(res, row,
3764  astate->rel,
3765  astate->attinmeta,
3766  astate->retrieved_attrs,
3767  NULL,
3768  astate->temp_cxt);
3769 
3770  MemoryContextSwitchTo(oldcontext);
3771  }
3772 }
static HeapTuple make_tuple_from_result_row(PGresult *res, int row, Relation rel, AttInMetadata *attinmeta, List *retrieved_attrs, ForeignScanState *fsstate, MemoryContext temp_context)
HeapTuple * rows
Definition: postgres_fdw.c:228
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
double sampler_random_fract(SamplerRandomState randstate)
Definition: sampling.c:238
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
ReservoirStateData rstate
Definition: postgres_fdw.c:235
AttInMetadata * attinmeta
Definition: postgres_fdw.c:224
MemoryContext temp_cxt
Definition: postgres_fdw.c:239
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
MemoryContext anl_cxt
Definition: postgres_fdw.c:238
SamplerRandomState randstate
Definition: sampling.h:50
double reservoir_get_next_S(ReservoirState rs, double t, int n)
Definition: sampling.c:142
static void apply_server_options ( PgFdwRelationInfo fpinfo)
static

Definition at line 4355 of file postgres_fdw.c.

References defGetBoolean(), defGetString(), DefElem::defname, ExtractExtensionList(), PgFdwRelationInfo::fdw_startup_cost, PgFdwRelationInfo::fdw_tuple_cost, PgFdwRelationInfo::fetch_size, lfirst, NULL, ForeignServer::options, PgFdwRelationInfo::server, PgFdwRelationInfo::shippable_extensions, and PgFdwRelationInfo::use_remote_estimate.

Referenced by postgresGetForeignRelSize().

4356 {
4357  ListCell *lc;
4358 
4359  foreach(lc, fpinfo->server->options)
4360  {
4361  DefElem *def = (DefElem *) lfirst(lc);
4362 
4363  if (strcmp(def->defname, "use_remote_estimate") == 0)
4364  fpinfo->use_remote_estimate = defGetBoolean(def);
4365  else if (strcmp(def->defname, "fdw_startup_cost") == 0)
4366  fpinfo->fdw_startup_cost = strtod(defGetString(def), NULL);
4367  else if (strcmp(def->defname, "fdw_tuple_cost") == 0)
4368  fpinfo->fdw_tuple_cost = strtod(defGetString(def), NULL);
4369  else if (strcmp(def->defname, "extensions") == 0)
4370  fpinfo->shippable_extensions =
4371  ExtractExtensionList(defGetString(def), false);
4372  else if (strcmp(def->defname, "fetch_size") == 0)
4373  fpinfo->fetch_size = strtol(defGetString(def), NULL, 10);
4374  }
4375 }
ForeignServer * server
Definition: postgres_fdw.h:76
bool defGetBoolean(DefElem *def)
Definition: define.c:111
char * defGetString(DefElem *def)
Definition: define.c:49
List * ExtractExtensionList(const char *extensionsString, bool warnOnMissing)
Definition: option.c:328
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
char * defname
Definition: parsenodes.h:720
List * shippable_extensions
Definition: postgres_fdw.h:72
List * options
Definition: foreign.h:53
static void apply_table_options ( PgFdwRelationInfo fpinfo)
static

Definition at line 4383 of file postgres_fdw.c.

References defGetBoolean(), defGetString(), DefElem::defname, PgFdwRelationInfo::fetch_size, lfirst, NULL, ForeignTable::options, PgFdwRelationInfo::table, and PgFdwRelationInfo::use_remote_estimate.

Referenced by postgresGetForeignRelSize().

4384 {
4385  ListCell *lc;
4386 
4387  foreach(lc, fpinfo->table->options)
4388  {
4389  DefElem *def = (DefElem *) lfirst(lc);
4390 
4391  if (strcmp(def->defname, "use_remote_estimate") == 0)
4392  fpinfo->use_remote_estimate = defGetBoolean(def);
4393  else if (strcmp(def->defname, "fetch_size") == 0)
4394  fpinfo->fetch_size = strtol(defGetString(def), NULL, 10);
4395  }
4396 }
bool defGetBoolean(DefElem *def)
Definition: define.c:111
char * defGetString(DefElem *def)
Definition: define.c:49
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
ForeignTable * table
Definition: postgres_fdw.h:75
List * options
Definition: foreign.h:68
char * defname
Definition: parsenodes.h:720
static void close_cursor ( PGconn conn,
unsigned int  cursor_number 
)
static

Definition at line 3115 of file postgres_fdw.c.

References ERROR, pgfdw_exec_query(), pgfdw_report_error(), PGRES_COMMAND_OK, PQclear(), PQresultStatus(), and snprintf().

Referenced by postgresAcquireSampleRowsFunc(), and postgresEndForeignScan().

3116 {
3117  char sql[64];
3118  PGresult *res;
3119 
3120  snprintf(sql, sizeof(sql), "CLOSE c%u", cursor_number);
3121 
3122  /*
3123  * We don't use a PG_TRY block here, so be careful not to throw error
3124  * without releasing the PGresult.
3125  */
3126  res = pgfdw_exec_query(conn, sql);
3127  if (PQresultStatus(res) != PGRES_COMMAND_OK)
3128  pgfdw_report_error(ERROR, res, conn, true, sql);
3129  PQclear(res);
3130 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
static unsigned int cursor_number
Definition: connection.c:60
void PQclear(PGresult *res)
Definition: fe-exec.c:650
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
static void conversion_error_callback ( void *  arg)
static

Definition at line 5083 of file postgres_fdw.c.

References tupleDesc::attrs, castNode, ConversionLocation::cur_attno, errcontext, EState::es_range_table, TargetEntry::expr, ForeignScan::fdw_scan_tlist, ConversionLocation::fsstate, get_rel_name(), get_relid_attribute_name(), IsA, list_nth_node, NameStr, tupleDesc::natts, NULL, ObjectIdAttributeNumber, PlanState::plan, ScanState::ps, ConversionLocation::rel, RelationGetDescr, RelationGetRelationName, RangeTblEntry::relid, rt_fetch, SelfItemPointerAttributeNumber, ForeignScanState::ss, PlanState::state, Var::varattno, and Var::varno.

Referenced by make_tuple_from_result_row().

5084 {
5085  const char *attname = NULL;
5086  const char *relname = NULL;
5087  bool is_wholerow = false;
5089 
5090  if (errpos->rel)
5091  {
5092  /* error occurred in a scan against a foreign table */
5093  TupleDesc tupdesc = RelationGetDescr(errpos->rel);
5094 
5095  if (errpos->cur_attno > 0 && errpos->cur_attno <= tupdesc->natts)
5096  attname = NameStr(tupdesc->attrs[errpos->cur_attno - 1]->attname);
5097  else if (errpos->cur_attno == SelfItemPointerAttributeNumber)
5098  attname = "ctid";
5099  else if (errpos->cur_attno == ObjectIdAttributeNumber)
5100  attname = "oid";
5101 
5102  relname = RelationGetRelationName(errpos->rel);
5103  }
5104  else
5105  {
5106  /* error occurred in a scan against a foreign join */
5107  ForeignScanState *fsstate = errpos->fsstate;
5108  ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
5109  EState *estate = fsstate->ss.ps.state;
5110  TargetEntry *tle;
5111 
5112  tle = list_nth_node(TargetEntry, fsplan->fdw_scan_tlist,
5113  errpos->cur_attno - 1);
5114 
5115  /*
5116  * Target list can have Vars and expressions. For Vars, we can get
5117  * it's relation, however for expressions we can't. Thus for
5118  * expressions, just show generic context message.
5119  */
5120  if (IsA(tle->expr, Var))
5121  {
5122  RangeTblEntry *rte;
5123  Var *var = (Var *) tle->expr;
5124 
5125  rte = rt_fetch(var->varno, estate->es_range_table);
5126 
5127  if (var->varattno == 0)
5128  is_wholerow = true;
5129  else
5130  attname = get_relid_attribute_name(rte->relid, var->varattno);
5131 
5132  relname = get_rel_name(rte->relid);
5133  }
5134  else
5135  errcontext("processing expression at position %d in select list",
5136  errpos->cur_attno);
5137  }
5138 
5139  if (relname)
5140  {
5141  if (is_wholerow)
5142  errcontext("whole-row reference to foreign table \"%s\"", relname);
5143  else if (attname)
5144  errcontext("column \"%s\" of foreign table \"%s\"", attname, relname);
5145  }
5146 }
ScanState ss
Definition: execnodes.h:1491
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
Form_pg_attribute * attrs
Definition: tupdesc.h:74
AttrNumber varattno
Definition: primnodes.h:168
List * fdw_scan_tlist
Definition: plannodes.h:591
EState * state
Definition: execnodes.h:805
List * es_range_table
Definition: execnodes.h:411
Definition: primnodes.h:163
int natts
Definition: tupdesc.h:73
PlanState ps
Definition: execnodes.h:1047
ForeignScanState * fsstate
Definition: postgres_fdw.c:256
#define list_nth_node(type, list, n)
Definition: pg_list.h:213
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Index varno
Definition: primnodes.h:166
char * get_relid_attribute_name(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:801
Plan * plan
Definition: execnodes.h:803
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1367
#define errcontext
Definition: elog.h:164
#define NameStr(name)
Definition: c.h:499
void * arg
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
AttrNumber cur_attno
Definition: postgres_fdw.c:248
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
static const char ** convert_prep_stmt_params ( PgFdwModifyState fmstate,
ItemPointer  tupleid,
TupleTableSlot slot 
)
static

Definition at line 3187 of file postgres_fdw.c.

References Assert, lfirst_int, MemoryContextSwitchTo(), NIL, NULL, OutputFunctionCall(), PgFdwModifyState::p_flinfo, PgFdwModifyState::p_nums, palloc(), PointerGetDatum, reset_transmission_modes(), set_transmission_modes(), slot_getattr(), PgFdwModifyState::target_attrs, PgFdwModifyState::temp_cxt, and value.

Referenced by postgresExecForeignDelete(), postgresExecForeignInsert(), and postgresExecForeignUpdate().

3190 {
3191  const char **p_values;
3192  int pindex = 0;
3193  MemoryContext oldcontext;
3194 
3195  oldcontext = MemoryContextSwitchTo(fmstate->temp_cxt);
3196 
3197  p_values = (const char **) palloc(sizeof(char *) * fmstate->p_nums);
3198 
3199  /* 1st parameter should be ctid, if it's in use */
3200  if (tupleid != NULL)
3201  {
3202  /* don't need set_transmission_modes for TID output */
3203  p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex],
3204  PointerGetDatum(tupleid));
3205  pindex++;
3206  }
3207 
3208  /* get following parameters from slot */
3209  if (slot != NULL && fmstate->target_attrs != NIL)
3210  {
3211  int nestlevel;
3212  ListCell *lc;
3213 
3214  nestlevel = set_transmission_modes();
3215 
3216  foreach(lc, fmstate->target_attrs)
3217  {
3218  int attnum = lfirst_int(lc);
3219  Datum value;
3220  bool isnull;
3221 
3222  value = slot_getattr(slot, attnum, &isnull);
3223  if (isnull)
3224  p_values[pindex] = NULL;
3225  else
3226  p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex],
3227  value);
3228  pindex++;
3229  }
3230 
3231  reset_transmission_modes(nestlevel);
3232  }
3233 
3234  Assert(pindex == fmstate->p_nums);
3235 
3236  MemoryContextSwitchTo(oldcontext);
3237 
3238  return p_values;
3239 }
#define NIL
Definition: pg_list.h:69
#define PointerGetDatum(X)
Definition: postgres.h:562
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int set_transmission_modes(void)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1667
#define lfirst_int(lc)
Definition: pg_list.h:107
FmgrInfo * p_flinfo
Definition: postgres_fdw.c:182
uintptr_t Datum
Definition: postgres.h:372
MemoryContext temp_cxt
Definition: postgres_fdw.c:185
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void reset_transmission_modes(int nestlevel)
void * palloc(Size size)
Definition: mcxt.c:849
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1143
static struct @121 value
static void create_cursor ( ForeignScanState node)
static

Definition at line 2919 of file postgres_fdw.c.

References appendStringInfo(), buf, conn, PgFdwScanState::conn, PgFdwScanState::cursor_exists, PgFdwScanState::cursor_number, PgFdwScanState::eof_reached, ERROR, ForeignScanState::fdw_state, PgFdwScanState::fetch_ct_2, initStringInfo(), MemoryContextSwitchTo(), PgFdwScanState::next_tuple, NULL, PgFdwScanState::num_tuples, PgFdwScanState::numParams, PgFdwScanState::param_exprs, PgFdwScanState::param_flinfo, PgFdwScanState::param_values, pfree(), pgfdw_get_result(), pgfdw_report_error(), PGRES_COMMAND_OK, PQclear(), PQresultStatus(), PQsendQueryParams(), process_query_params(), ScanState::ps, PlanState::ps_ExprContext, PgFdwScanState::query, ForeignScanState::ss, PgFdwScanState::tuples, and values.

Referenced by postgresIterateForeignScan().

2920 {
2921  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
2922  ExprContext *econtext = node->ss.ps.ps_ExprContext;
2923  int numParams = fsstate->numParams;
2924  const char **values = fsstate->param_values;
2925  PGconn *conn = fsstate->conn;
2927  PGresult *res;
2928 
2929  /*
2930  * Construct array of query parameter values in text format. We do the
2931  * conversions in the short-lived per-tuple context, so as not to cause a
2932  * memory leak over repeated scans.
2933  */
2934  if (numParams > 0)
2935  {
2936  MemoryContext oldcontext;
2937 
2938  oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
2939 
2940  process_query_params(econtext,
2941  fsstate->param_flinfo,
2942  fsstate->param_exprs,
2943  values);
2944 
2945  MemoryContextSwitchTo(oldcontext);
2946  }
2947 
2948  /* Construct the DECLARE CURSOR command */
2949  initStringInfo(&buf);
2950  appendStringInfo(&buf, "DECLARE c%u CURSOR FOR\n%s",
2951  fsstate->cursor_number, fsstate->query);
2952 
2953  /*
2954  * Notice that we pass NULL for paramTypes, thus forcing the remote server
2955  * to infer types for all parameters. Since we explicitly cast every
2956  * parameter (see deparse.c), the "inference" is trivial and will produce
2957  * the desired result. This allows us to avoid assuming that the remote
2958  * server has the same OIDs we do for the parameters' types.
2959  */
2960  if (!PQsendQueryParams(conn, buf.data, numParams,
2961  NULL, values, NULL, NULL, 0))
2962  pgfdw_report_error(ERROR, NULL, conn, false, buf.data);
2963 
2964  /*
2965  * Get the result, and check for success.
2966  *
2967  * We don't use a PG_TRY block here, so be careful not to throw error
2968  * without releasing the PGresult.
2969  */
2970  res = pgfdw_get_result(conn, buf.data);
2971  if (PQresultStatus(res) != PGRES_COMMAND_OK)
2972  pgfdw_report_error(ERROR, res, conn, true, fsstate->query);
2973  PQclear(res);
2974 
2975  /* Mark the cursor as created, and show no tuples have been retrieved */
2976  fsstate->cursor_exists = true;
2977  fsstate->tuples = NULL;
2978  fsstate->num_tuples = 0;
2979  fsstate->next_tuple = 0;
2980  fsstate->fetch_ct_2 = 0;
2981  fsstate->eof_reached = false;
2982 
2983  /* Clean up */
2984  pfree(buf.data);
2985 }
ScanState ss
Definition: execnodes.h:1491
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1183
List * param_exprs
Definition: postgres_fdw.c:142
ExprContext * ps_ExprContext
Definition: execnodes.h:833
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void process_query_params(ExprContext *econtext, FmgrInfo *param_flinfo, List *param_exprs, const char **param_values)
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
unsigned int cursor_number
Definition: postgres_fdw.c:138
PlanState ps
Definition: execnodes.h:1047
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define ERROR
Definition: elog.h:43
const char ** param_values
Definition: postgres_fdw.c:143
PGconn * conn
Definition: streamutil.c:42
static char * buf
Definition: pg_test_fsync.c:66
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
FmgrInfo * param_flinfo
Definition: postgres_fdw.c:141
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
void PQclear(PGresult *res)
Definition: fe-exec.c:650
PGresult * pgfdw_get_result(PGconn *conn, const char *query)
Definition: connection.c:474
#define NULL
Definition: c.h:229
HeapTuple * tuples
Definition: postgres_fdw.c:146
static Datum values[MAXATTR]
Definition: bootstrap.c:163
static bool ec_member_matches_foreign ( PlannerInfo root,
RelOptInfo rel,
EquivalenceClass ec,
EquivalenceMember em,
void *  arg 
)
static

Definition at line 2890 of file postgres_fdw.c.

References ec_member_foreign_arg::already_used, ec_member_foreign_arg::current, EquivalenceMember::em_expr, equal(), list_member(), and NULL.

Referenced by postgresGetForeignPaths().

2893 {
2895  Expr *expr = em->em_expr;
2896 
2897  /*
2898  * If we've identified what we're processing in the current scan, we only
2899  * want to match that expression.
2900  */
2901  if (state->current != NULL)
2902  return equal(expr, state->current);
2903 
2904  /*
2905  * Otherwise, ignore anything we've already processed.
2906  */
2907  if (list_member(state->already_used, expr))
2908  return false;
2909 
2910  /* This is the new target to process. */
2911  state->current = expr;
2912  return true;
2913 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
bool list_member(const List *list, const void *datum)
Definition: list.c:444
#define NULL
Definition: c.h:229
Definition: regguts.h:298
void * arg
static void estimate_path_cost_size ( PlannerInfo root,
RelOptInfo baserel,
List join_conds,
List pathkeys,
double *  p_rows,
int *  p_width,
Cost p_startup_cost,
Cost p_total_cost 
)
static

Definition at line 2497 of file postgres_fdw.c.

References AGGSPLIT_SIMPLE, appendStringInfoString(), Assert, RelOptInfo::baserestrictcost, build_tlist_to_deparse(), clamp_row_est(), classifyConditions(), clauselist_selectivity(), conn, PathTarget::cost, cost_qual_eval(), cpu_operator_cost, cpu_tuple_cost, StringInfoData::data, DEFAULT_FDW_SORT_MULTIPLIER, deparseSelectStmtForRel(), estimate_num_groups(), RelOptInfo::fdw_private, PgFdwRelationInfo::fdw_startup_cost, PgFdwRelationInfo::fdw_tuple_cost, AggClauseCosts::finalCost, get_agg_clause_costs(), get_remote_estimate(), get_sortgrouplist_exprs(), GetConnection(), Query::groupClause, PgFdwRelationInfo::grouped_tlist, Query::hasAggs, Query::havingQual, initStringInfo(), PgFdwRelationInfo::innerrel, IS_JOIN_REL, IS_UPPER_REL, JOIN_INNER, PgFdwRelationInfo::joinclause_sel, PgFdwRelationInfo::joinclauses, list_concat(), list_copy(), list_length(), PgFdwRelationInfo::local_conds_cost, PgFdwRelationInfo::local_conds_sel, MemSet, Min, NIL, NULL, PgFdwRelationInfo::outerrel, RelOptInfo::pages, PlannerInfo::parse, QualCost::per_tuple, PgFdwRelationInfo::rel_startup_cost, PgFdwRelationInfo::rel_total_cost, ReleaseConnection(), RelOptInfo::relid, RelOptInfo::reltarget, PgFdwRelationInfo::remote_conds, PgFdwRelationInfo::rows, RelOptInfo::rows, seq_page_cost, QualCost::startup, AggClauseCosts::transCost, RelOptInfo::tuples, PlannerInfo::upper_targets, UPPERREL_GROUP_AGG, PgFdwRelationInfo::use_remote_estimate, PgFdwRelationInfo::user, PgFdwRelationInfo::width, and PathTarget::width.

Referenced by add_foreign_grouping_paths(), add_paths_with_pathkeys_for_rel(), postgresGetForeignJoinPaths(), postgresGetForeignPaths(), and postgresGetForeignRelSize().

2503 {
2504  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
2505  double rows;
2506  double retrieved_rows;
2507  int width;
2508  Cost startup_cost;
2509  Cost total_cost;
2510  Cost cpu_per_tuple;
2511 
2512  /*
2513  * If the table or the server is configured to use remote estimates,
2514  * connect to the foreign server and execute EXPLAIN to estimate the
2515  * number of rows selected by the restriction+join clauses. Otherwise,
2516  * estimate rows using whatever statistics we have locally, in a way
2517  * similar to ordinary tables.
2518  */
2519  if (fpinfo->use_remote_estimate)
2520  {
2521  List *remote_param_join_conds;
2522  List *local_param_join_conds;
2523  StringInfoData sql;
2524  PGconn *conn;
2525  Selectivity local_sel;
2526  QualCost local_cost;
2527  List *fdw_scan_tlist = NIL;
2528  List *remote_conds;
2529 
2530  /* Required only to be passed to deparseSelectStmtForRel */
2531  List *retrieved_attrs;
2532 
2533  /*
2534  * param_join_conds might contain both clauses that are safe to send
2535  * across, and clauses that aren't.
2536  */
2537  classifyConditions(root, foreignrel, param_join_conds,
2538  &remote_param_join_conds, &local_param_join_conds);
2539 
2540  /* Build the list of columns to be fetched from the foreign server. */
2541  if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
2542  fdw_scan_tlist = build_tlist_to_deparse(foreignrel);
2543  else
2544  fdw_scan_tlist = NIL;
2545 
2546  /*
2547  * The complete list of remote conditions includes everything from
2548  * baserestrictinfo plus any extra join_conds relevant to this
2549  * particular path.
2550  */
2551  remote_conds = list_concat(list_copy(remote_param_join_conds),
2552  fpinfo->remote_conds);
2553 
2554  /*
2555  * Construct EXPLAIN query including the desired SELECT, FROM, and
2556  * WHERE clauses. Params and other-relation Vars are replaced by dummy
2557  * values, so don't request params_list.
2558  */
2559  initStringInfo(&sql);
2560  appendStringInfoString(&sql, "EXPLAIN ");
2561  deparseSelectStmtForRel(&sql, root, foreignrel, fdw_scan_tlist,
2562  remote_conds, pathkeys, false,
2563  &retrieved_attrs, NULL);
2564 
2565  /* Get the remote estimate */
2566  conn = GetConnection(fpinfo->user, false);
2567  get_remote_estimate(sql.data, conn, &rows, &width,
2568  &startup_cost, &total_cost);
2569  ReleaseConnection(conn);
2570 
2571  retrieved_rows = rows;
2572 
2573  /* Factor in the selectivity of the locally-checked quals */
2574  local_sel = clauselist_selectivity(root,
2575  local_param_join_conds,
2576  foreignrel->relid,
2577  JOIN_INNER,
2578  NULL);
2579  local_sel *= fpinfo->local_conds_sel;
2580 
2581  rows = clamp_row_est(rows * local_sel);
2582 
2583  /* Add in the eval cost of the locally-checked quals */
2584  startup_cost += fpinfo->local_conds_cost.startup;
2585  total_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
2586  cost_qual_eval(&local_cost, local_param_join_conds, root);
2587  startup_cost += local_cost.startup;
2588  total_cost += local_cost.per_tuple * retrieved_rows;
2589  }
2590  else
2591  {
2592  Cost run_cost = 0;
2593 
2594  /*
2595  * We don't support join conditions in this mode (hence, no
2596  * parameterized paths can be made).
2597  */
2598  Assert(param_join_conds == NIL);
2599 
2600  /*
2601  * Use rows/width estimates made by set_baserel_size_estimates() for
2602  * base foreign relations and set_joinrel_size_estimates() for join
2603  * between foreign relations.
2604  */
2605  rows = foreignrel->rows;
2606  width = foreignrel->reltarget->width;
2607 
2608  /* Back into an estimate of the number of retrieved rows. */
2609  retrieved_rows = clamp_row_est(rows / fpinfo->local_conds_sel);
2610 
2611  /*
2612  * We will come here again and again with different set of pathkeys
2613  * that caller wants to cost. We don't need to calculate the cost of
2614  * bare scan each time. Instead, use the costs if we have cached them
2615  * already.
2616  */
2617  if (fpinfo->rel_startup_cost > 0 && fpinfo->rel_total_cost > 0)
2618  {
2619  startup_cost = fpinfo->rel_startup_cost;
2620  run_cost = fpinfo->rel_total_cost - fpinfo->rel_startup_cost;
2621  }
2622  else if (IS_JOIN_REL(foreignrel))
2623  {
2624  PgFdwRelationInfo *fpinfo_i;
2625  PgFdwRelationInfo *fpinfo_o;
2626  QualCost join_cost;
2627  QualCost remote_conds_cost;
2628  double nrows;
2629 
2630  /* For join we expect inner and outer relations set */
2631  Assert(fpinfo->innerrel && fpinfo->outerrel);
2632 
2633  fpinfo_i = (PgFdwRelationInfo *) fpinfo->innerrel->fdw_private;
2634  fpinfo_o = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
2635 
2636  /* Estimate of number of rows in cross product */
2637  nrows = fpinfo_i->rows * fpinfo_o->rows;
2638  /* Clamp retrieved rows estimate to at most size of cross product */
2639  retrieved_rows = Min(retrieved_rows, nrows);
2640 
2641  /*
2642  * The cost of foreign join is estimated as cost of generating
2643  * rows for the joining relations + cost for applying quals on the
2644  * rows.
2645  */
2646 
2647  /*
2648  * Calculate the cost of clauses pushed down to the foreign server
2649  */
2650  cost_qual_eval(&remote_conds_cost, fpinfo->remote_conds, root);
2651  /* Calculate the cost of applying join clauses */
2652  cost_qual_eval(&join_cost, fpinfo->joinclauses, root);
2653 
2654  /*
2655  * Startup cost includes startup cost of joining relations and the
2656  * startup cost for join and other clauses. We do not include the
2657  * startup cost specific to join strategy (e.g. setting up hash
2658  * tables) since we do not know what strategy the foreign server
2659  * is going to use.
2660  */
2661  startup_cost = fpinfo_i->rel_startup_cost + fpinfo_o->rel_startup_cost;
2662  startup_cost += join_cost.startup;
2663  startup_cost += remote_conds_cost.startup;
2664  startup_cost += fpinfo->local_conds_cost.startup;
2665 
2666  /*
2667  * Run time cost includes:
2668  *
2669  * 1. Run time cost (total_cost - startup_cost) of relations being
2670  * joined
2671  *
2672  * 2. Run time cost of applying join clauses on the cross product
2673  * of the joining relations.
2674  *
2675  * 3. Run time cost of applying pushed down other clauses on the
2676  * result of join
2677  *
2678  * 4. Run time cost of applying nonpushable other clauses locally
2679  * on the result fetched from the foreign server.
2680  */
2681  run_cost = fpinfo_i->rel_total_cost - fpinfo_i->rel_startup_cost;
2682  run_cost += fpinfo_o->rel_total_cost - fpinfo_o->rel_startup_cost;
2683  run_cost += nrows * join_cost.per_tuple;
2684  nrows = clamp_row_est(nrows * fpinfo->joinclause_sel);
2685  run_cost += nrows * remote_conds_cost.per_tuple;
2686  run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
2687  }
2688  else if (IS_UPPER_REL(foreignrel))
2689  {
2690  PgFdwRelationInfo *ofpinfo;
2691  PathTarget *ptarget = root->upper_targets[UPPERREL_GROUP_AGG];
2692  AggClauseCosts aggcosts;
2693  double input_rows;
2694  int numGroupCols;
2695  double numGroups = 1;
2696 
2697  /*
2698  * This cost model is mixture of costing done for sorted and
2699  * hashed aggregates in cost_agg(). We are not sure which
2700  * strategy will be considered at remote side, thus for
2701  * simplicity, we put all startup related costs in startup_cost
2702  * and all finalization and run cost are added in total_cost.
2703  *
2704  * Also, core does not care about costing HAVING expressions and
2705  * adding that to the costs. So similarly, here too we are not
2706  * considering remote and local conditions for costing.
2707  */
2708 
2709  ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
2710 
2711  /* Get rows and width from input rel */
2712  input_rows = ofpinfo->rows;
2713  width = ofpinfo->width;
2714 
2715  /* Collect statistics about aggregates for estimating costs. */
2716  MemSet(&aggcosts, 0, sizeof(AggClauseCosts));
2717  if (root->parse->hasAggs)
2718  {
2719  get_agg_clause_costs(root, (Node *) fpinfo->grouped_tlist,
2720  AGGSPLIT_SIMPLE, &aggcosts);
2721  get_agg_clause_costs(root, (Node *) root->parse->havingQual,
2722  AGGSPLIT_SIMPLE, &aggcosts);
2723  }
2724 
2725  /* Get number of grouping columns and possible number of groups */
2726  numGroupCols = list_length(root->parse->groupClause);
2727  numGroups = estimate_num_groups(root,
2729  fpinfo->grouped_tlist),
2730  input_rows, NULL);
2731 
2732  /*
2733  * Number of rows expected from foreign server will be same as
2734  * that of number of groups.
2735  */
2736  rows = retrieved_rows = numGroups;
2737 
2738  /*-----
2739  * Startup cost includes:
2740  * 1. Startup cost for underneath input * relation
2741  * 2. Cost of performing aggregation, per cost_agg()
2742  * 3. Startup cost for PathTarget eval
2743  *-----
2744  */
2745  startup_cost = ofpinfo->rel_startup_cost;
2746  startup_cost += aggcosts.transCost.startup;
2747  startup_cost += aggcosts.transCost.per_tuple * input_rows;
2748  startup_cost += (cpu_operator_cost * numGroupCols) * input_rows;
2749  startup_cost += ptarget->cost.startup;
2750 
2751  /*-----
2752  * Run time cost includes:
2753  * 1. Run time cost of underneath input relation
2754  * 2. Run time cost of performing aggregation, per cost_agg()
2755  * 3. PathTarget eval cost for each output row
2756  *-----
2757  */
2758  run_cost = ofpinfo->rel_total_cost - ofpinfo->rel_startup_cost;
2759  run_cost += aggcosts.finalCost * numGroups;
2760  run_cost += cpu_tuple_cost * numGroups;
2761  run_cost += ptarget->cost.per_tuple * numGroups;
2762  }
2763  else
2764  {
2765  /* Clamp retrieved rows estimates to at most foreignrel->tuples. */
2766  retrieved_rows = Min(retrieved_rows, foreignrel->tuples);
2767 
2768  /*
2769  * Cost as though this were a seqscan, which is pessimistic. We
2770  * effectively imagine the local_conds are being evaluated
2771  * remotely, too.
2772  */
2773  startup_cost = 0;
2774  run_cost = 0;
2775  run_cost += seq_page_cost * foreignrel->pages;
2776 
2777  startup_cost += foreignrel->baserestrictcost.startup;
2778  cpu_per_tuple = cpu_tuple_cost + foreignrel->baserestrictcost.per_tuple;
2779  run_cost += cpu_per_tuple * foreignrel->tuples;
2780  }
2781 
2782  /*
2783  * Without remote estimates, we have no real way to estimate the cost
2784  * of generating sorted output. It could be free if the query plan
2785  * the remote side would have chosen generates properly-sorted output
2786  * anyway, but in most cases it will cost something. Estimate a value
2787  * high enough that we won't pick the sorted path when the ordering
2788  * isn't locally useful, but low enough that we'll err on the side of
2789  * pushing down the ORDER BY clause when it's useful to do so.
2790  */
2791  if (pathkeys != NIL)
2792  {
2793  startup_cost *= DEFAULT_FDW_SORT_MULTIPLIER;
2794  run_cost *= DEFAULT_FDW_SORT_MULTIPLIER;
2795  }
2796 
2797  total_cost = startup_cost + run_cost;
2798  }
2799 
2800  /*
2801  * Cache the costs for scans without any pathkeys or parameterization
2802  * before adding the costs for transferring data from the foreign server.
2803  * These costs are useful for costing the join between this relation and
2804  * another foreign relation or to calculate the costs of paths with
2805  * pathkeys for this relation, when the costs can not be obtained from the
2806  * foreign server. This function will be called at least once for every
2807  * foreign relation without pathkeys and parameterization.
2808  */
2809  if (pathkeys == NIL && param_join_conds == NIL)
2810  {
2811  fpinfo->rel_startup_cost = startup_cost;
2812  fpinfo->rel_total_cost = total_cost;
2813  }
2814 
2815  /*
2816  * Add some additional cost factors to account for connection overhead
2817  * (fdw_startup_cost), transferring data across the network
2818  * (fdw_tuple_cost per retrieved row), and local manipulation of the data
2819  * (cpu_tuple_cost per retrieved row).
2820  */
2821  startup_cost += fpinfo->fdw_startup_cost;
2822  total_cost += fpinfo->fdw_startup_cost;
2823  total_cost += fpinfo->fdw_tuple_cost * retrieved_rows;
2824  total_cost += cpu_tuple_cost * retrieved_rows;
2825 
2826  /* Return results. */
2827  *p_rows = rows;
2828  *p_width = width;
2829  *p_startup_cost = startup_cost;
2830  *p_total_cost = total_cost;
2831 }
#define NIL
Definition: pg_list.h:69
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset)
Definition: selfuncs.c:3278
Query * parse
Definition: relation.h:154
void get_agg_clause_costs(PlannerInfo *root, Node *clause, AggSplit aggsplit, AggClauseCosts *costs)
Definition: clauses.c:467
bool hasAggs
Definition: parsenodes.h:123
#define Min(x, y)
Definition: c.h:806
#define IS_UPPER_REL(rel)
Definition: relation.h:512
#define IS_JOIN_REL(rel)
Definition: relation.h:509
void classifyConditions(PlannerInfo *root, RelOptInfo *baserel, List *input_conds, List **remote_conds, List **local_conds)
Definition: deparse.c:200
List * list_copy(const List *oldlist)
Definition: list.c:1160
Definition: nodes.h:509
#define MemSet(start, val, len)
Definition: c.h:857
List * list_concat(List *list1, List *list2)
Definition: list.c:321
double Selectivity
Definition: nodes.h:638
QualCost transCost
Definition: relation.h:62
RelOptInfo * outerrel
Definition: postgres_fdw.h:89
Cost startup
Definition: relation.h:45
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
Cost per_tuple
Definition: relation.h:46
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:3428
PGconn * conn
Definition: streamutil.c:42
Selectivity local_conds_sel
Definition: postgres_fdw.h:54
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
Selectivity joinclause_sel
Definition: postgres_fdw.h:57
double cpu_operator_cost
Definition: costsize.c:108
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
UserMapping * user
Definition: postgres_fdw.h:77
void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List *tlist, List *remote_conds, List *pathkeys, bool is_subquery, List **retrieved_attrs, List **params_list)
Definition: deparse.c:925
Cost finalCost
Definition: relation.h:63
void * fdw_private
Definition: relation.h:576
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define DEFAULT_FDW_SORT_MULTIPLIER
Definition: postgres_fdw.c:54
QualCost cost
Definition: relation.h:884
static int list_length(const List *l)
Definition: pg_list.h:89
List * get_sortgrouplist_exprs(List *sgClauses, List *targetList)
Definition: tlist.c:395
double cpu_tuple_cost
Definition: costsize.c:106
static void get_remote_estimate(const char *sql, PGconn *conn, double *rows, int *width, Cost *startup_cost, Cost *total_cost)
RelOptInfo * innerrel
Definition: postgres_fdw.h:90
List * build_tlist_to_deparse(RelOptInfo *foreignrel)
Definition: deparse.c:868
List * groupClause
Definition: parsenodes.h:146
Selectivity clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
Definition: clausesel.c:99
Node * havingQual
Definition: parsenodes.h:150
double clamp_row_est(double nrows)
Definition: costsize.c:173
double seq_page_cost
Definition: costsize.c:104
Definition: pg_list.h:45
double Cost
Definition: nodes.h:639
QualCost local_conds_cost
Definition: postgres_fdw.h:53
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: relation.h:274
static void execute_dml_stmt ( ForeignScanState node)
static

Definition at line 3278 of file postgres_fdw.c.

References PgFdwDirectModifyState::conn, ERROR, ForeignScanState::fdw_state, PgFdwDirectModifyState::has_returning, NULL, PgFdwDirectModifyState::num_tuples, PgFdwDirectModifyState::numParams, PgFdwDirectModifyState::param_exprs, PgFdwDirectModifyState::param_flinfo, PgFdwDirectModifyState::param_values, pgfdw_get_result(), pgfdw_report_error(), PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQcmdTuples(), PQntuples(), PQresultStatus(), PQsendQueryParams(), process_query_params(), ScanState::ps, PlanState::ps_ExprContext, PgFdwDirectModifyState::query, PgFdwDirectModifyState::result, ForeignScanState::ss, and values.

Referenced by postgresIterateDirectModify().

3279 {
3281  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3282  int numParams = dmstate->numParams;
3283  const char **values = dmstate->param_values;
3284 
3285  /*
3286  * Construct array of query parameter values in text format.
3287  */
3288  if (numParams > 0)
3289  process_query_params(econtext,
3290  dmstate->param_flinfo,
3291  dmstate->param_exprs,
3292  values);
3293 
3294  /*
3295  * Notice that we pass NULL for paramTypes, thus forcing the remote server
3296  * to infer types for all parameters. Since we explicitly cast every
3297  * parameter (see deparse.c), the "inference" is trivial and will produce
3298  * the desired result. This allows us to avoid assuming that the remote
3299  * server has the same OIDs we do for the parameters' types.
3300  */
3301  if (!PQsendQueryParams(dmstate->conn, dmstate->query, numParams,
3302  NULL, values, NULL, NULL, 0))
3303  pgfdw_report_error(ERROR, NULL, dmstate->conn, false, dmstate->query);
3304 
3305  /*
3306  * Get the result, and check for success.
3307  *
3308  * We don't use a PG_TRY block here, so be careful not to throw error
3309  * without releasing the PGresult.
3310  */
3311  dmstate->result = pgfdw_get_result(dmstate->conn, dmstate->query);
3312  if (PQresultStatus(dmstate->result) !=
3314  pgfdw_report_error(ERROR, dmstate->result, dmstate->conn, true,
3315  dmstate->query);
3316 
3317  /* Get the number of rows affected. */
3318  if (dmstate->has_returning)
3319  dmstate->num_tuples = PQntuples(dmstate->result);
3320  else
3321  dmstate->num_tuples = atoi(PQcmdTuples(dmstate->result));
3322 }
ScanState ss
Definition: execnodes.h:1491
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1183
const char ** param_values
Definition: postgres_fdw.c:207
char * PQcmdTuples(PGresult *res)
Definition: fe-exec.c:3014
ExprContext * ps_ExprContext
Definition: execnodes.h:833
static void process_query_params(ExprContext *econtext, FmgrInfo *param_flinfo, List *param_exprs, const char **param_values)
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
PGresult * pgfdw_get_result(PGconn *conn, const char *query)
Definition: connection.c:474
#define NULL
Definition: c.h:229
static Datum values[MAXATTR]
Definition: bootstrap.c:163
static void fetch_more_data ( ForeignScanState node)
static

Definition at line 2991 of file postgres_fdw.c.

References Assert, PgFdwScanState::attinmeta, PgFdwScanState::batch_cxt, conn, PgFdwScanState::conn, PgFdwScanState::cursor_number, PgFdwScanState::eof_reached, ERROR, ForeignScanState::fdw_state, PgFdwScanState::fetch_ct_2, PgFdwScanState::fetch_size, i, IsA, make_tuple_from_result_row(), MemoryContextReset(), MemoryContextSwitchTo(), PgFdwScanState::next_tuple, NULL, PgFdwScanState::num_tuples, palloc0(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgfdw_exec_query(), pgfdw_report_error(), PGRES_TUPLES_OK, PlanState::plan, PQclear(), PQntuples(), PQresultStatus(), ScanState::ps, PgFdwScanState::query, PgFdwScanState::rel, PgFdwScanState::retrieved_attrs, snprintf(), ForeignScanState::ss, PgFdwScanState::temp_cxt, and PgFdwScanState::tuples.

Referenced by postgresIterateForeignScan().

2992 {
2993  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
2994  PGresult *volatile res = NULL;
2995  MemoryContext oldcontext;
2996 
2997  /*
2998  * We'll store the tuples in the batch_cxt. First, flush the previous
2999  * batch.
3000  */
3001  fsstate->tuples = NULL;
3002  MemoryContextReset(fsstate->batch_cxt);
3003  oldcontext = MemoryContextSwitchTo(fsstate->batch_cxt);
3004 
3005  /* PGresult must be released before leaving this function. */
3006  PG_TRY();
3007  {
3008  PGconn *conn = fsstate->conn;
3009  char sql[64];
3010  int numrows;
3011  int i;
3012 
3013  snprintf(sql, sizeof(sql), "FETCH %d FROM c%u",
3014  fsstate->fetch_size, fsstate->cursor_number);
3015 
3016  res = pgfdw_exec_query(conn, sql);
3017  /* On error, report the original query, not the FETCH. */
3018  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3019  pgfdw_report_error(ERROR, res, conn, false, fsstate->query);
3020 
3021  /* Convert the data into HeapTuples */
3022  numrows = PQntuples(res);
3023  fsstate->tuples = (HeapTuple *) palloc0(numrows * sizeof(HeapTuple));
3024  fsstate->num_tuples = numrows;
3025  fsstate->next_tuple = 0;
3026 
3027  for (i = 0; i < numrows; i++)
3028  {
3029  Assert(IsA(node->ss.ps.plan, ForeignScan));
3030 
3031  fsstate->tuples[i] =
3033  fsstate->rel,
3034  fsstate->attinmeta,
3035  fsstate->retrieved_attrs,
3036  node,
3037  fsstate->temp_cxt);
3038  }
3039 
3040  /* Update fetch_ct_2 */
3041  if (fsstate->fetch_ct_2 < 2)
3042  fsstate->fetch_ct_2++;
3043 
3044  /* Must be EOF if we didn't get as many tuples as we asked for. */
3045  fsstate->eof_reached = (numrows < fsstate->fetch_size);
3046 
3047  PQclear(res);
3048  res = NULL;
3049  }
3050  PG_CATCH();
3051  {
3052  if (res)
3053  PQclear(res);
3054  PG_RE_THROW();
3055  }
3056  PG_END_TRY();
3057 
3058  MemoryContextSwitchTo(oldcontext);
3059 }
ScanState ss
Definition: execnodes.h:1491
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
static HeapTuple make_tuple_from_result_row(PGresult *res, int row, Relation rel, AttInMetadata *attinmeta, List *retrieved_attrs, ForeignScanState *fsstate, MemoryContext temp_context)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
List * retrieved_attrs
Definition: postgres_fdw.c:134
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
unsigned int cursor_number
Definition: postgres_fdw.c:138
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
PGconn * conn
Definition: streamutil.c:42
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
AttInMetadata * attinmeta
Definition: postgres_fdw.c:130
void * palloc0(Size size)
Definition: mcxt.c:878
MemoryContext temp_cxt
Definition: postgres_fdw.c:156
Plan * plan
Definition: execnodes.h:803
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
HeapTuple * tuples
Definition: postgres_fdw.c:146
#define PG_RE_THROW()
Definition: elog.h:314
int i
#define PG_TRY()
Definition: elog.h:284
MemoryContext batch_cxt
Definition: postgres_fdw.c:155
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
#define PG_END_TRY()
Definition: elog.h:300
Expr* find_em_expr_for_rel ( EquivalenceClass ec,
RelOptInfo rel 
)

Definition at line 5153 of file postgres_fdw.c.

References bms_is_subset(), EquivalenceClass::ec_members, EquivalenceMember::em_expr, EquivalenceMember::em_relids, lfirst, NULL, and RelOptInfo::relids.

Referenced by appendOrderByClause(), and get_useful_pathkeys_for_relation().

5154 {
5155  ListCell *lc_em;
5156 
5157  foreach(lc_em, ec->ec_members)
5158  {
5159  EquivalenceMember *em = lfirst(lc_em);
5160 
5161  if (bms_is_subset(em->em_relids, rel->relids))
5162  {
5163  /*
5164  * If there is more than one equivalence member whose Vars are
5165  * taken entirely from this relation, we'll be content to choose
5166  * any one of those.
5167  */
5168  return em->em_expr;
5169  }
5170  }
5171 
5172  /* We didn't find any suitable equivalence class expression */
5173  return NULL;
5174 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
Relids relids
Definition: relation.h:524
Relids em_relids
Definition: relation.h:821
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
List * ec_members
Definition: relation.h:772
static bool foreign_grouping_ok ( PlannerInfo root,
RelOptInfo grouped_rel 
)
static

Definition at line 4591 of file postgres_fdw.c.

References add_to_flat_tlist(), appendStringInfo(), apply_pathtarget_labeling_to_tlist(), Assert, RestrictInfo::clause, copy_pathtarget(), StringInfoData::data, PathTarget::exprs, RelOptInfo::fdw_private, get_pathtarget_sortgroupref, get_sortgroupref_clause_noerr(), Query::groupClause, PgFdwRelationInfo::grouped_tlist, Query::groupingSets, PlannerInfo::hasHavingQual, Query::havingQual, i, is_foreign_expr(), IsA, lappend(), lfirst, lfirst_node, list_concat(), list_make1, PgFdwRelationInfo::local_conds, make_restrictinfo(), makeStringInfo(), NIL, NULL, PgFdwRelationInfo::outerrel, PlannerInfo::parse, pull_var_clause(), PgFdwRelationInfo::pushdown_safe, PVC_INCLUDE_AGGREGATES, PlannerInfo::qual_security_level, PgFdwRelationInfo::rel_startup_cost, PgFdwRelationInfo::rel_total_cost, PgFdwRelationInfo::relation_name, RelOptInfo::relids, PgFdwRelationInfo::remote_conds, PathTarget::sortgrouprefs, PlannerInfo::upper_targets, and UPPERREL_GROUP_AGG.

Referenced by add_foreign_grouping_paths().

4592 {
4593  Query *query = root->parse;
4594  PathTarget *grouping_target;
4595  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
4596  PgFdwRelationInfo *ofpinfo;
4597  List *aggvars;
4598  ListCell *lc;
4599  int i;
4600  List *tlist = NIL;
4601 
4602  /* Grouping Sets are not pushable */
4603  if (query->groupingSets)
4604  return false;
4605 
4606  /* Get the fpinfo of the underlying scan relation. */
4607  ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
4608 
4609  /*
4610  * If underneath input relation has any local conditions, those conditions
4611  * are required to be applied before performing aggregation. Hence the
4612  * aggregate cannot be pushed down.
4613  */
4614  if (ofpinfo->local_conds)
4615  return false;
4616 
4617  /*
4618  * The targetlist expected from this node and the targetlist pushed down
4619  * to the foreign server may be different. The latter requires
4620  * sortgrouprefs to be set to push down GROUP BY clause, but should not
4621  * have those arising from ORDER BY clause. These sortgrouprefs may be
4622  * different from those in the plan's targetlist. Use a copy of path
4623  * target to record the new sortgrouprefs.
4624  */
4625  grouping_target = copy_pathtarget(root->upper_targets[UPPERREL_GROUP_AGG]);
4626 
4627  /*
4628  * Evaluate grouping targets and check whether they are safe to push down
4629  * to the foreign side. All GROUP BY expressions will be part of the
4630  * grouping target and thus there is no need to evaluate it separately.
4631  * While doing so, add required expressions into target list which can
4632  * then be used to pass to foreign server.
4633  */
4634  i = 0;
4635  foreach(lc, grouping_target->exprs)
4636  {
4637  Expr *expr = (Expr *) lfirst(lc);
4638  Index sgref = get_pathtarget_sortgroupref(grouping_target, i);
4639  ListCell *l;
4640 
4641  /* Check whether this expression is part of GROUP BY clause */
4642  if (sgref && get_sortgroupref_clause_noerr(sgref, query->groupClause))
4643  {
4644  /*
4645  * If any of the GROUP BY expression is not shippable we can not
4646  * push down aggregation to the foreign server.
4647  */
4648  if (!is_foreign_expr(root, grouped_rel, expr))
4649  return false;
4650 
4651  /* Pushable, add to tlist */
4652  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4653  }
4654  else
4655  {
4656  /* Check entire expression whether it is pushable or not */
4657  if (is_foreign_expr(root, grouped_rel, expr))
4658  {
4659  /* Pushable, add to tlist */
4660  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4661  }
4662  else
4663  {
4664  /*
4665  * If we have sortgroupref set, then it means that we have an
4666  * ORDER BY entry pointing to this expression. Since we are
4667  * not pushing ORDER BY with GROUP BY, clear it.
4668  */
4669  if (sgref)
4670  grouping_target->sortgrouprefs[i] = 0;
4671 
4672  /* Not matched exactly, pull the var with aggregates then */
4673  aggvars = pull_var_clause((Node *) expr,
4675 
4676  if (!is_foreign_expr(root, grouped_rel, (Expr *) aggvars))
4677  return false;
4678 
4679  /*
4680  * Add aggregates, if any, into the targetlist. Plain var
4681  * nodes should be either same as some GROUP BY expression or
4682  * part of some GROUP BY expression. In later case, the query
4683  * cannot refer plain var nodes without the surrounding
4684  * expression. In both the cases, they are already part of
4685  * the targetlist and thus no need to add them again. In fact
4686  * adding pulled plain var nodes in SELECT clause will cause
4687  * an error on the foreign server if they are not same as some
4688  * GROUP BY expression.
4689  */
4690  foreach(l, aggvars)
4691  {
4692  Expr *expr = (Expr *) lfirst(l);
4693 
4694  if (IsA(expr, Aggref))
4695  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4696  }
4697  }
4698  }
4699 
4700  i++;
4701  }
4702 
4703  /*
4704  * Classify the pushable and non-pushable having clauses and save them in
4705  * remote_conds and local_conds of the grouped rel's fpinfo.
4706  */
4707  if (root->hasHavingQual && query->havingQual)
4708  {
4709  ListCell *lc;
4710 
4711  foreach(lc, (List *) query->havingQual)
4712  {
4713  Expr *expr = (Expr *) lfirst(lc);
4714  RestrictInfo *rinfo;
4715 
4716  /*
4717  * Currently, the core code doesn't wrap havingQuals in
4718  * RestrictInfos, so we must make our own.
4719  */
4720  Assert(!IsA(expr, RestrictInfo));
4721  rinfo = make_restrictinfo(expr,
4722  true,
4723  false,
4724  false,
4725  root->qual_security_level,
4726  grouped_rel->relids,
4727  NULL,
4728  NULL);
4729  if (is_foreign_expr(root, grouped_rel, expr))
4730  fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
4731  else
4732  fpinfo->local_conds = lappend(fpinfo->local_conds, rinfo);
4733  }
4734  }
4735 
4736  /*
4737  * If there are any local conditions, pull Vars and aggregates from it and
4738  * check whether they are safe to pushdown or not.
4739  */
4740  if (fpinfo->local_conds)
4741  {
4742  List *aggvars = NIL;
4743  ListCell *lc;
4744 
4745  foreach(lc, fpinfo->local_conds)
4746  {
4747  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
4748 
4749  aggvars = list_concat(aggvars,
4750  pull_var_clause((Node *) rinfo->clause,
4752  }
4753 
4754  foreach(lc, aggvars)
4755  {
4756  Expr *expr = (Expr *) lfirst(lc);
4757 
4758  /*
4759  * If aggregates within local conditions are not safe to push
4760  * down, then we cannot push down the query. Vars are already
4761  * part of GROUP BY clause which are checked above, so no need to
4762  * access them again here.
4763  */
4764  if (IsA(expr, Aggref))
4765  {
4766  if (!is_foreign_expr(root, grouped_rel, expr))
4767  return false;
4768 
4769  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4770  }
4771  }
4772  }
4773 
4774  /* Transfer any sortgroupref data to the replacement tlist */
4775  apply_pathtarget_labeling_to_tlist(tlist, grouping_target);
4776 
4777  /* Store generated targetlist */
4778  fpinfo->grouped_tlist = tlist;
4779 
4780  /* Safe to pushdown */
4781  fpinfo->pushdown_safe = true;
4782 
4783  /*
4784  * Set cached relation costs to some negative value, so that we can detect
4785  * when they are set to some sensible costs, during one (usually the
4786  * first) of the calls to estimate_path_cost_size().
4787  */
4788  fpinfo->rel_startup_cost = -1;
4789  fpinfo->rel_total_cost = -1;
4790 
4791  /*
4792  * Set the string describing this grouped relation to be used in EXPLAIN
4793  * output of corresponding ForeignScan.
4794  */
4795  fpinfo->relation_name = makeStringInfo();
4796  appendStringInfo(fpinfo->relation_name, "Aggregate on (%s)",
4797  ofpinfo->relation_name->data);
4798 
4799  return true;
4800 }
#define NIL
Definition: pg_list.h:69
PathTarget * copy_pathtarget(PathTarget *src)
Definition: tlist.c:629
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Query * parse
Definition: relation.h:154
RestrictInfo * make_restrictinfo(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:57
StringInfo makeStringInfo(void)
Definition: stringinfo.c:29
List * groupingSets
Definition: parsenodes.h:148
Definition: nodes.h:509
List * list_concat(List *list1, List *list2)
Definition: list.c:321
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
RelOptInfo * outerrel
Definition: postgres_fdw.h:89
#define PVC_INCLUDE_AGGREGATES
Definition: var.h:20
#define list_make1(x1)
Definition: pg_list.h:139
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define lfirst_node(type, lc)
Definition: pg_list.h:109
Index * sortgrouprefs
Definition: relation.h:883
Relids relids
Definition: relation.h:524
#define get_pathtarget_sortgroupref(target, colno)
Definition: relation.h:889
List * lappend(List *list, void *datum)
Definition: list.c:128
Expr * clause
Definition: relation.h:1746
List * exprs
Definition: relation.h:882
void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
Definition: tlist.c:736
SortGroupClause * get_sortgroupref_clause_noerr(Index sortref, List *clauses)
Definition: tlist.c:446
unsigned int Index
Definition: c.h:365
StringInfo relation_name
Definition: postgres_fdw.h:86
void * fdw_private
Definition: relation.h:576
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition: tlist.c:135
#define lfirst(lc)
Definition: pg_list.h:106
Index qual_security_level
Definition: relation.h:293
List * groupClause
Definition: parsenodes.h:146
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition: deparse.c:226
int i
bool hasHavingQual
Definition: relation.h:301
Node * havingQual
Definition: parsenodes.h:150
Definition: pg_list.h:45
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: relation.h:274
static bool foreign_join_ok ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinPathExtraData extra 
)
static

Definition at line 4061 of file postgres_fdw.c.

References appendStringInfo(), Assert, bms_add_members(), bms_is_subset(), bms_nonempty_difference(), bms_union(), RestrictInfo::clause, StringInfoData::data, elog, ERROR, RelOptInfo::fdw_private, get_jointype_name(), PgFdwRelationInfo::innerrel, is_foreign_expr(), IS_OUTER_JOIN, RestrictInfo::is_pushed_down, JOIN_FULL, JOIN_INNER, JOIN_LEFT, PlannerInfo::join_rel_list, JOIN_RIGHT, PgFdwRelationInfo::joinclauses, PgFdwRelationInfo::jointype, lappend(), lfirst, lfirst_node, list_concat(), list_copy(), list_length(), PgFdwRelationInfo::local_conds, PgFdwRelationInfo::lower_subquery_rels, PgFdwRelationInfo::make_innerrel_subquery, PgFdwRelationInfo::make_outerrel_subquery, makeStringInfo(), merge_fdw_options(), NIL, NULL, PgFdwRelationInfo::outerrel, PlannerInfo::parse, PlaceHolderInfo::ph_eval_at, PlannerInfo::placeholder_list, PgFdwRelationInfo::pushdown_safe, PgFdwRelationInfo::rel_startup_cost, PgFdwRelationInfo::rel_total_cost, PgFdwRelationInfo::relation_index, PgFdwRelationInfo::relation_name, RelOptInfo::relids, PgFdwRelationInfo::remote_conds, JoinPathExtraData::restrictlist, Query::rtable, PgFdwRelationInfo::server, PgFdwRelationInfo::use_remote_estimate, and PgFdwRelationInfo::user.

Referenced by postgresGetForeignJoinPaths().

4064 {
4065  PgFdwRelationInfo *fpinfo;
4066  PgFdwRelationInfo *fpinfo_o;
4067  PgFdwRelationInfo *fpinfo_i;
4068  ListCell *lc;
4069  List *joinclauses;
4070 
4071  /*
4072  * We support pushing down INNER, LEFT, RIGHT and FULL OUTER joins.
4073  * Constructing queries representing SEMI and ANTI joins is hard, hence
4074  * not considered right now.
4075  */
4076  if (jointype != JOIN_INNER && jointype != JOIN_LEFT &&
4077  jointype != JOIN_RIGHT && jointype != JOIN_FULL)
4078  return false;
4079 
4080  /*
4081  * If either of the joining relations is marked as unsafe to pushdown, the
4082  * join can not be pushed down.
4083  */
4084  fpinfo = (PgFdwRelationInfo *) joinrel->fdw_private;
4085  fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private;
4086  fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private;
4087  if (!fpinfo_o || !fpinfo_o->pushdown_safe ||
4088  !fpinfo_i || !fpinfo_i->pushdown_safe)
4089  return false;
4090 
4091  /*
4092  * If joining relations have local conditions, those conditions are
4093  * required to be applied before joining the relations. Hence the join can
4094  * not be pushed down.
4095  */
4096  if (fpinfo_o->local_conds || fpinfo_i->local_conds)
4097  return false;
4098 
4099  /*
4100  * Merge FDW options. We might be tempted to do this after we have deemed
4101  * the foreign join to be OK. But we must do this beforehand so that we
4102  * know which quals can be evaluated on the foreign server, which might
4103  * depend on shippable_extensions.
4104  */
4105  fpinfo->server = fpinfo_o->server;
4106  merge_fdw_options(fpinfo, fpinfo_o, fpinfo_i);
4107 
4108  /*
4109  * Separate restrict list into join quals and pushed-down (other) quals.
4110  *
4111  * Join quals belonging to an outer join must all be shippable, else we
4112  * cannot execute the join remotely. Add such quals to 'joinclauses'.
4113  *
4114  * Add other quals to fpinfo->remote_conds if they are shippable, else to
4115  * fpinfo->local_conds. In an inner join it's okay to execute conditions
4116  * either locally or remotely; the same is true for pushed-down conditions
4117  * at an outer join.
4118  *
4119  * Note we might return failure after having already scribbled on
4120  * fpinfo->remote_conds and fpinfo->local_conds. That's okay because we
4121  * won't consult those lists again if we deem the join unshippable.
4122  */
4123  joinclauses = NIL;
4124  foreach(lc, extra->restrictlist)
4125  {
4126  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
4127  bool is_remote_clause = is_foreign_expr(root, joinrel,
4128  rinfo->clause);
4129 
4130  if (IS_OUTER_JOIN(jointype) && !rinfo->is_pushed_down)
4131  {
4132  if (!is_remote_clause)
4133  return false;
4134  joinclauses = lappend(joinclauses, rinfo);
4135  }
4136  else
4137  {
4138  if (is_remote_clause)
4139  fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
4140  else
4141  fpinfo->local_conds = lappend(fpinfo->local_conds, rinfo);
4142  }
4143  }
4144 
4145  /*
4146  * deparseExplicitTargetList() isn't smart enough to handle anything other
4147  * than a Var. In particular, if there's some PlaceHolderVar that would
4148  * need to be evaluated within this join tree (because there's an upper
4149  * reference to a quantity that may go to NULL as a result of an outer
4150  * join), then we can't try to push the join down because we'll fail when
4151  * we get to deparseExplicitTargetList(). However, a PlaceHolderVar that
4152  * needs to be evaluated *at the top* of this join tree is OK, because we
4153  * can do that locally after fetching the results from the remote side.
4154  */
4155  foreach(lc, root->placeholder_list)
4156  {
4157  PlaceHolderInfo *phinfo = lfirst(lc);
4158  Relids relids = joinrel->relids;
4159 
4160  if (bms_is_subset(phinfo->ph_eval_at, relids) &&
4161  bms_nonempty_difference(relids, phinfo->ph_eval_at))
4162  return false;
4163  }
4164 
4165  /* Save the join clauses, for later use. */
4166  fpinfo->joinclauses = joinclauses;
4167 
4168  fpinfo->outerrel = outerrel;
4169  fpinfo->innerrel = innerrel;
4170  fpinfo->jointype = jointype;
4171 
4172  /*
4173  * By default, both the input relations are not required to be deparsed
4174  * as subqueries, but there might be some relations covered by the input
4175  * relations that are required to be deparsed as subqueries, so save the
4176  * relids of those relations for later use by the deparser.
4177  */
4178  fpinfo->make_outerrel_subquery = false;
4179  fpinfo->make_innerrel_subquery = false;
4180  Assert(bms_is_subset(fpinfo_o->lower_subquery_rels, outerrel->relids));
4181  Assert(bms_is_subset(fpinfo_i->lower_subquery_rels, innerrel->relids));
4183  fpinfo_i->lower_subquery_rels);
4184 
4185  /*
4186  * Pull the other remote conditions from the joining relations into join
4187  * clauses or other remote clauses (remote_conds) of this relation
4188  * wherever possible. This avoids building subqueries at every join step.
4189  *
4190  * For an inner join, clauses from both the relations are added to the
4191  * other remote clauses. For LEFT and RIGHT OUTER join, the clauses from
4192  * the outer side are added to remote_conds since those can be evaluated
4193  * after the join is evaluated. The clauses from inner side are added to
4194  * the joinclauses, since they need to be evaluated while constructing the
4195  * join.
4196  *
4197  * For a FULL OUTER JOIN, the other clauses from either relation can not
4198  * be added to the joinclauses or remote_conds, since each relation acts
4199  * as an outer relation for the other.
4200  *
4201  * The joining sides can not have local conditions, thus no need to test
4202  * shippability of the clauses being pulled up.
4203  */
4204  switch (jointype)
4205  {
4206  case JOIN_INNER:
4207  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4208  list_copy(fpinfo_i->remote_conds));
4209  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4210  list_copy(fpinfo_o->remote_conds));
4211  break;
4212 
4213  case JOIN_LEFT:
4214  fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
4215  list_copy(fpinfo_i->remote_conds));
4216  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4217  list_copy(fpinfo_o->remote_conds));
4218  break;
4219 
4220  case JOIN_RIGHT:
4221  fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
4222  list_copy(fpinfo_o->remote_conds));
4223  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4224  list_copy(fpinfo_i->remote_conds));
4225  break;
4226 
4227  case JOIN_FULL:
4228 
4229  /*
4230  * In this case, if any of the input relations has conditions,
4231  * we need to deparse that relation as a subquery so that the
4232  * conditions can be evaluated before the join. Remember it in
4233  * the fpinfo of this relation so that the deparser can take
4234  * appropriate action. Also, save the relids of base relations
4235  * covered by that relation for later use by the deparser.
4236  */
4237  if (fpinfo_o->remote_conds)
4238  {
4239  fpinfo->make_outerrel_subquery = true;
4240  fpinfo->lower_subquery_rels =
4242  outerrel->relids);
4243  }
4244  if (fpinfo_i->remote_conds)
4245  {
4246  fpinfo->make_innerrel_subquery = true;
4247  fpinfo->lower_subquery_rels =
4249  innerrel->relids);
4250  }
4251  break;
4252 
4253  default:
4254  /* Should not happen, we have just check this above */
4255  elog(ERROR, "unsupported join type %d", jointype);
4256  }
4257 
4258  /*
4259  * For an inner join, all restrictions can be treated alike. Treating the
4260  * pushed down conditions as join conditions allows a top level full outer
4261  * join to be deparsed without requiring subqueries.
4262  */
4263  if (jointype == JOIN_INNER)
4264  {
4265  Assert(!fpinfo->joinclauses);
4266  fpinfo->joinclauses = fpinfo->remote_conds;
4267  fpinfo->remote_conds = NIL;
4268  }
4269 
4270  /* Mark that this join can be pushed down safely */
4271  fpinfo->pushdown_safe = true;
4272 
4273  /* Get user mapping */
4274  if (fpinfo->use_remote_estimate)
4275  {
4276  if (fpinfo_o->use_remote_estimate)
4277  fpinfo->user = fpinfo_o->user;
4278  else
4279  fpinfo->user = fpinfo_i->user;
4280  }
4281  else
4282  fpinfo->user = NULL;
4283 
4284  /*
4285  * Set cached relation costs to some negative value, so that we can detect
4286  * when they are set to some sensible costs, during one (usually the
4287  * first) of the calls to estimate_path_cost_size().
4288  */
4289  fpinfo->rel_startup_cost = -1;
4290  fpinfo->rel_total_cost = -1;
4291 
4292  /*
4293  * Set the string describing this join relation to be used in EXPLAIN
4294  * output of corresponding ForeignScan.
4295  */
4296  fpinfo->relation_name = makeStringInfo();
4297  appendStringInfo(fpinfo->relation_name, "(%s) %s JOIN (%s)",
4298  fpinfo_o->relation_name->data,
4299  get_jointype_name(fpinfo->jointype),
4300  fpinfo_i->relation_name->data);
4301 
4302  /*
4303  * Set the relation index. This is defined as the position of this
4304  * joinrel in the join_rel_list list plus the length of the rtable list.
4305  * Note that since this joinrel is at the end of the join_rel_list list
4306  * when we are called, we can get the position by list_length.
4307  */
4308  Assert(fpinfo->relation_index == 0); /* shouldn't be set yet */
4309  fpinfo->relation_index =
4311 
4312  return true;
4313 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:154
Relids ph_eval_at
Definition: relation.h:2063
StringInfo makeStringInfo(void)
Definition: stringinfo.c:29
ForeignServer * server
Definition: postgres_fdw.h:76
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:721
List * list_copy(const List *oldlist)
Definition: list.c:1160
Relids lower_subquery_rels
Definition: postgres_fdw.h:103
List * join_rel_list
Definition: relation.h:214
List * list_concat(List *list1, List *list2)
Definition: list.c:321
RelOptInfo * outerrel
Definition: postgres_fdw.h:89
static void merge_fdw_options(PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_o, const PgFdwRelationInfo *fpinfo_i)
bool make_outerrel_subquery
Definition: postgres_fdw.h:99
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
#define lfirst_node(type, lc)
Definition: pg_list.h:109
const char * get_jointype_name(JoinType jointype)
Definition: deparse.c:1311
Relids relids
Definition: relation.h:524
List * lappend(List *list, void *datum)
Definition: list.c:128
Expr * clause
Definition: relation.h:1746
UserMapping * user
Definition: postgres_fdw.h:77
List * restrictlist
Definition: relation.h:2179
bool is_pushed_down
Definition: relation.h:1748
StringInfo relation_name
Definition: postgres_fdw.h:86
void * fdw_private
Definition: relation.h:576
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:218
static int list_length(const List *l)
Definition: pg_list.h:89
RelOptInfo * innerrel
Definition: postgres_fdw.h:90
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition: deparse.c:226
List * placeholder_list
Definition: relation.h:257
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
static void get_remote_estimate ( const char *  sql,
PGconn conn,
double *  rows,
int *  width,
Cost startup_cost,
Cost total_cost 
)
static

Definition at line 2838 of file postgres_fdw.c.

References elog, ERROR, NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgfdw_exec_query(), pgfdw_report_error(), PGRES_TUPLES_OK, PQclear(), PQgetvalue(), and PQresultStatus().

Referenced by estimate_path_cost_size().

2841 {
2842  PGresult *volatile res = NULL;
2843 
2844  /* PGresult must be released before leaving this function. */
2845  PG_TRY();
2846  {
2847  char *line;
2848  char *p;
2849  int n;
2850 
2851  /*
2852  * Execute EXPLAIN remotely.
2853  */
2854  res = pgfdw_exec_query(conn, sql);
2855  if (PQresultStatus(res) != PGRES_TUPLES_OK)
2856  pgfdw_report_error(ERROR, res, conn, false, sql);
2857 
2858  /*
2859  * Extract cost numbers for topmost plan node. Note we search for a
2860  * left paren from the end of the line to avoid being confused by
2861  * other uses of parentheses.
2862  */
2863  line = PQgetvalue(res, 0, 0);
2864  p = strrchr(line, '(');
2865  if (p == NULL)
2866  elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
2867  n = sscanf(p, "(cost=%lf..%lf rows=%lf width=%d)",
2868  startup_cost, total_cost, rows, width);
2869  if (n != 4)
2870  elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
2871 
2872  PQclear(res);
2873  res = NULL;
2874  }
2875  PG_CATCH();
2876  {
2877  if (res)
2878  PQclear(res);
2879  PG_RE_THROW();
2880  }
2881  PG_END_TRY();
2882 }
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3067
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define PG_RE_THROW()
Definition: elog.h:314
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
#define PG_END_TRY()
Definition: elog.h:300
static TupleTableSlot * get_returning_data ( ForeignScanState node)
static

Definition at line 3328 of file postgres_fdw.c.

References Assert, PgFdwDirectModifyState::attinmeta, ExecClearTuple(), ExecStoreAllNullTuple(), ExecStoreTuple(), ForeignScanState::fdw_state, PgFdwDirectModifyState::has_returning, InvalidBuffer, make_tuple_from_result_row(), PgFdwDirectModifyState::next_tuple, NULL, PgFdwDirectModifyState::num_tuples, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PQclear(), ScanState::ps, PgFdwDirectModifyState::rel, PgFdwDirectModifyState::result, PgFdwDirectModifyState::retrieved_attrs, PgFdwDirectModifyState::set_processed, ForeignScanState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, and PgFdwDirectModifyState::temp_cxt.

Referenced by postgresIterateDirectModify().

3329 {
3331  EState *estate = node->ss.ps.state;
3332  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
3333  TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
3334 
3335  Assert(resultRelInfo->ri_projectReturning);
3336 
3337  /* If we didn't get any tuples, must be end of data. */
3338  if (dmstate->next_tuple >= dmstate->num_tuples)
3339  return ExecClearTuple(slot);
3340 
3341  /* Increment the command es_processed count if necessary. */
3342  if (dmstate->set_processed)
3343  estate->es_processed += 1;
3344 
3345  /*
3346  * Store a RETURNING tuple. If has_returning is false, just emit a dummy
3347  * tuple. (has_returning is false when the local query is of the form
3348  * "UPDATE/DELETE .. RETURNING 1" for example.)
3349  */
3350  if (!dmstate->has_returning)
3351  ExecStoreAllNullTuple(slot);
3352  else
3353  {
3354  /*
3355  * On error, be sure to release the PGresult on the way out. Callers
3356  * do not have PG_TRY blocks to ensure this happens.
3357  */
3358  PG_TRY();
3359  {
3360  HeapTuple newtup;
3361 
3362  newtup = make_tuple_from_result_row(dmstate->result,
3363  dmstate->next_tuple,
3364  dmstate->rel,
3365  dmstate->attinmeta,
3366  dmstate->retrieved_attrs,
3367  NULL,
3368  dmstate->temp_cxt);
3369  ExecStoreTuple(newtup, slot, InvalidBuffer, false);
3370  }
3371  PG_CATCH();
3372  {
3373  if (dmstate->result)
3374  PQclear(dmstate->result);
3375  PG_RE_THROW();
3376  }
3377  PG_END_TRY();
3378  }
3379  dmstate->next_tuple++;
3380 
3381  /* Make slot available for evaluation of the local query RETURNING list. */
3382  resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple = slot;
3383 
3384  return slot;
3385 }
ScanState ss
Definition: execnodes.h:1491
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
static HeapTuple make_tuple_from_result_row(PGresult *res, int row, Relation rel, AttInMetadata *attinmeta, List *retrieved_attrs, ForeignScanState *fsstate, MemoryContext temp_context)
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:512
AttInMetadata * attinmeta
Definition: postgres_fdw.c:194
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define InvalidBuffer
Definition: buf.h:25
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
EState * state
Definition: execnodes.h:805
PlanState ps
Definition: execnodes.h:1047
MemoryContext temp_cxt
Definition: postgres_fdw.c:215
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define PG_RE_THROW()
Definition: elog.h:314
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
static List * get_useful_ecs_for_relation ( PlannerInfo root,
RelOptInfo rel 
)
static

Definition at line 682 of file postgres_fdw.c.

References Assert, bms_is_empty(), bms_overlap(), EquivalenceClass::ec_relids, eclass_useful_for_merging(), PlannerInfo::eq_classes, RelOptInfo::has_eclass_joins, IS_OTHER_REL, RelOptInfo::joininfo, lappend(), RestrictInfo::left_ec, lfirst, list_append_unique_ptr(), RestrictInfo::mergeopfamilies, NIL, RelOptInfo::relids, RestrictInfo::right_ec, RelOptInfo::top_parent_relids, and update_mergeclause_eclasses().

Referenced by get_useful_pathkeys_for_relation().

683 {
684  List *useful_eclass_list = NIL;
685  ListCell *lc;
686  Relids relids;
687 
688  /*
689  * First, consider whether any active EC is potentially useful for a merge
690  * join against this relation.
691  */
692  if (rel->has_eclass_joins)
693  {
694  foreach(lc, root->eq_classes)
695  {
696  EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc);
697 
698  if (eclass_useful_for_merging(root, cur_ec, rel))
699  useful_eclass_list = lappend(useful_eclass_list, cur_ec);
700  }
701  }
702 
703  /*
704  * Next, consider whether there are any non-EC derivable join clauses that
705  * are merge-joinable. If the joininfo list is empty, we can exit
706  * quickly.
707  */
708  if (rel->joininfo == NIL)
709  return useful_eclass_list;
710 
711  /* If this is a child rel, we must use the topmost parent rel to search. */
712  if (IS_OTHER_REL(rel))
713  {
715  relids = rel->top_parent_relids;
716  }
717  else
718  relids = rel->relids;
719 
720  /* Check each join clause in turn. */
721  foreach(lc, rel->joininfo)
722  {
723  RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(lc);
724 
725  /* Consider only mergejoinable clauses */
726  if (restrictinfo->mergeopfamilies == NIL)
727  continue;
728 
729  /* Make sure we've got canonical ECs. */
730  update_mergeclause_eclasses(root, restrictinfo);
731 
732  /*
733  * restrictinfo->mergeopfamilies != NIL is sufficient to guarantee
734  * that left_ec and right_ec will be initialized, per comments in
735  * distribute_qual_to_rels.
736  *
737  * We want to identify which side of this merge-joinable clause
738  * contains columns from the relation produced by this RelOptInfo. We
739  * test for overlap, not containment, because there could be extra
740  * relations on either side. For example, suppose we've got something
741  * like ((A JOIN B ON A.x = B.x) JOIN C ON A.y = C.y) LEFT JOIN D ON
742  * A.y = D.y. The input rel might be the joinrel between A and B, and
743  * we'll consider the join clause A.y = D.y. relids contains a
744  * relation not involved in the join class (B) and the equivalence
745  * class for the left-hand side of the clause contains a relation not
746  * involved in the input rel (C). Despite the fact that we have only
747  * overlap and not containment in either direction, A.y is potentially
748  * useful as a sort column.
749  *
750  * Note that it's even possible that relids overlaps neither side of
751  * the join clause. For example, consider A LEFT JOIN B ON A.x = B.x
752  * AND A.x = 1. The clause A.x = 1 will appear in B's joininfo list,
753  * but overlaps neither side of B. In that case, we just skip this
754  * join clause, since it doesn't suggest a useful sort order for this
755  * relation.
756  */
757  if (bms_overlap(relids, restrictinfo->right_ec->ec_relids))
758  useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
759  restrictinfo->right_ec);
760  else if (bms_overlap(relids, restrictinfo->left_ec->ec_relids))
761  useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
762  restrictinfo->left_ec);
763  }
764 
765  return useful_eclass_list;
766 }
bool has_eclass_joins
Definition: relation.h:590
#define NIL
Definition: pg_list.h:69
bool eclass_useful_for_merging(PlannerInfo *root, EquivalenceClass *eclass, RelOptInfo *rel)
Definition: equivclass.c:2397
#define IS_OTHER_REL(rel)
Definition: relation.h:515
EquivalenceClass * right_ec
Definition: relation.h:1795
List * mergeopfamilies
Definition: relation.h:1791
List * list_append_unique_ptr(List *list, void *datum)
Definition: list.c:975
List * joininfo
Definition: relation.h:588
Relids ec_relids
Definition: relation.h:775
Relids relids
Definition: relation.h:524
List * lappend(List *list, void *datum)
Definition: list.c:128
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
List * eq_classes
Definition: relation.h:234
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
EquivalenceClass * left_ec
Definition: relation.h:1794
Definition: pg_list.h:45
void update_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:968
Relids top_parent_relids
Definition: relation.h:593
static List * get_useful_pathkeys_for_relation ( PlannerInfo root,
RelOptInfo rel 
)
static

Definition at line 778 of file postgres_fdw.c.

References BTLessStrategyNumber, EquivalenceClass::ec_has_volatile, EquivalenceClass::ec_opfamilies, RelOptInfo::fdw_private, find_em_expr_for_rel(), get_useful_ecs_for_relation(), is_foreign_expr(), lappend(), lfirst, linitial, linitial_oid, list_copy(), list_length(), list_make1, make_canonical_pathkey(), NIL, NULL, PathKey::pk_eclass, PlannerInfo::query_pathkeys, and PgFdwRelationInfo::use_remote_estimate.

Referenced by add_paths_with_pathkeys_for_rel().

779 {
780  List *useful_pathkeys_list = NIL;
781  List *useful_eclass_list;
783  EquivalenceClass *query_ec = NULL;
784  ListCell *lc;
785 
786  /*
787  * Pushing the query_pathkeys to the remote server is always worth
788  * considering, because it might let us avoid a local sort.
789  */
790  if (root->query_pathkeys)
791  {
792  bool query_pathkeys_ok = true;
793 
794  foreach(lc, root->query_pathkeys)
795  {
796  PathKey *pathkey = (PathKey *) lfirst(lc);
797  EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
798  Expr *em_expr;
799 
800  /*
801  * The planner and executor don't have any clever strategy for
802  * taking data sorted by a prefix of the query's pathkeys and
803  * getting it to be sorted by all of those pathkeys. We'll just
804  * end up resorting the entire data set. So, unless we can push
805  * down all of the query pathkeys, forget it.
806  *
807  * is_foreign_expr would detect volatile expressions as well, but
808  * checking ec_has_volatile here saves some cycles.
809  */
810  if (pathkey_ec->ec_has_volatile ||
811  !(em_expr = find_em_expr_for_rel(pathkey_ec, rel)) ||
812  !is_foreign_expr(root, rel, em_expr))
813  {
814  query_pathkeys_ok = false;
815  break;
816  }
817  }
818 
819  if (query_pathkeys_ok)
820  useful_pathkeys_list = list_make1(list_copy(root->query_pathkeys));
821  }
822 
823  /*
824  * Even if we're not using remote estimates, having the remote side do the
825  * sort generally won't be any worse than doing it locally, and it might
826  * be much better if the remote side can generate data in the right order
827  * without needing a sort at all. However, what we're going to do next is
828  * try to generate pathkeys that seem promising for possible merge joins,
829  * and that's more speculative. A wrong choice might hurt quite a bit, so
830  * bail out if we can't use remote estimates.
831  */
832  if (!fpinfo->use_remote_estimate)
833  return useful_pathkeys_list;
834 
835  /* Get the list of interesting EquivalenceClasses. */
836  useful_eclass_list = get_useful_ecs_for_relation(root, rel);
837 
838  /* Extract unique EC for query, if any, so we don't consider it again. */
839  if (list_length(root->query_pathkeys) == 1)
840  {
841  PathKey *query_pathkey = linitial(root->query_pathkeys);
842 
843  query_ec = query_pathkey->pk_eclass;
844  }
845 
846  /*
847  * As a heuristic, the only pathkeys we consider here are those of length
848  * one. It's surely possible to consider more, but since each one we
849  * choose to consider will generate a round-trip to the remote side, we
850  * need to be a bit cautious here. It would sure be nice to have a local
851  * cache of information about remote index definitions...
852  */
853  foreach(lc, useful_eclass_list)
854  {
855  EquivalenceClass *cur_ec = lfirst(lc);
856  Expr *em_expr;
857  PathKey *pathkey;
858 
859  /* If redundant with what we did above, skip it. */
860  if (cur_ec == query_ec)
861  continue;
862 
863  /* If no pushable expression for this rel, skip it. */
864  em_expr = find_em_expr_for_rel(cur_ec, rel);
865  if (em_expr == NULL || !is_foreign_expr(root, rel, em_expr))
866  continue;
867 
868  /* Looks like we can generate a pathkey, so let's do it. */
869  pathkey = make_canonical_pathkey(root, cur_ec,
870  linitial_oid(cur_ec->ec_opfamilies),
872  false);
873  useful_pathkeys_list = lappend(useful_pathkeys_list,
874  list_make1(pathkey));
875  }
876 
877  return useful_pathkeys_list;
878 }
#define NIL
Definition: pg_list.h:69
List * query_pathkeys
Definition: relation.h:261
static List * get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition: postgres_fdw.c:682
List * list_copy(const List *oldlist)
Definition: list.c:1160
PathKey * make_canonical_pathkey(PlannerInfo *root, EquivalenceClass *eclass, Oid opfamily, int strategy, bool nulls_first)
Definition: pathkeys.c:51
#define list_make1(x1)
Definition: pg_list.h:139
#define linitial(l)
Definition: pg_list.h:111
List * lappend(List *list, void *datum)
Definition: list.c:128
List * ec_opfamilies
Definition: relation.h:770
void * fdw_private
Definition: relation.h:576
#define NULL
Definition: c.h:229
Expr * find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel)
#define lfirst(lc)
Definition: pg_list.h:106
EquivalenceClass * pk_eclass
Definition: relation.h:849
#define linitial_oid(l)
Definition: pg_list.h:113
static int list_length(const List *l)
Definition: pg_list.h:89
bool ec_has_volatile
Definition: relation.h:778
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition: deparse.c:226
#define BTLessStrategyNumber
Definition: stratnum.h:29
Definition: pg_list.h:45
static HeapTuple make_tuple_from_result_row ( PGresult res,
int  row,
Relation  rel,
AttInMetadata attinmeta,
List retrieved_attrs,
ForeignScanState fsstate,
MemoryContext  temp_context 
)
static

Definition at line 4913 of file postgres_fdw.c.

References ErrorContextCallback::arg, Assert, AttInMetadata::attinfuncs, AttInMetadata::attioparams, AttInMetadata::atttypmods, ErrorContextCallback::callback, conversion_error_callback(), CStringGetDatum, ConversionLocation::cur_attno, DatumGetObjectId, DatumGetPointer, DirectFunctionCall1, elog, ERROR, error_context_stack, ForeignScanState::fdw_state, ConversionLocation::fsstate, heap_form_tuple(), HeapTupleHeaderSetCmin, HeapTupleHeaderSetXmax, HeapTupleHeaderSetXmin, HeapTupleSetOid, i, InputFunctionCall(), InvalidOid, InvalidTransactionId, lfirst_int, MemoryContextReset(), MemoryContextSwitchTo(), tupleDesc::natts, NULL, ObjectIdAttributeNumber, oidin(), OidIsValid, palloc(), palloc0(), PQgetisnull(), PQgetvalue(), PQnfields(), PQntuples(), ErrorContextCallback::previous, ConversionLocation::rel, RelationGetDescr, SelfItemPointerAttributeNumber, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleData::t_self, tidin(), PgFdwScanState::tupdesc, and values.

Referenced by analyze_row_processor(), fetch_more_data(), get_returning_data(), and store_returning_result().

4920 {
4921  HeapTuple tuple;
4922  TupleDesc tupdesc;
4923  Datum *values;
4924  bool *nulls;
4925  ItemPointer ctid = NULL;
4926  Oid oid = InvalidOid;
4927  ConversionLocation errpos;
4928  ErrorContextCallback errcallback;
4929  MemoryContext oldcontext;
4930  ListCell *lc;
4931  int j;
4932 
4933  Assert(row < PQntuples(res));
4934 
4935  /*
4936  * Do the following work in a temp context that we reset after each tuple.
4937  * This cleans up not only the data we have direct access to, but any
4938  * cruft the I/O functions might leak.
4939  */
4940  oldcontext = MemoryContextSwitchTo(temp_context);
4941 
4942  if (rel)
4943  tupdesc = RelationGetDescr(rel);
4944  else
4945  {
4946  PgFdwScanState *fdw_sstate;
4947 
4948  Assert(fsstate);
4949  fdw_sstate = (PgFdwScanState *) fsstate->fdw_state;
4950  tupdesc = fdw_sstate->tupdesc;
4951  }
4952 
4953  values = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
4954  nulls = (bool *) palloc(tupdesc->natts * sizeof(bool));
4955  /* Initialize to nulls for any columns not present in result */
4956  memset(nulls, true, tupdesc->natts * sizeof(bool));
4957 
4958  /*
4959  * Set up and install callback to report where conversion error occurs.
4960  */
4961  errpos.rel = rel;
4962  errpos.cur_attno = 0;
4963  errpos.fsstate = fsstate;
4964  errcallback.callback = conversion_error_callback;
4965  errcallback.arg = (void *) &errpos;
4966  errcallback.previous = error_context_stack;
4967  error_context_stack = &errcallback;
4968 
4969  /*
4970  * i indexes columns in the relation, j indexes columns in the PGresult.
4971  */
4972  j = 0;
4973  foreach(lc, retrieved_attrs)
4974  {
4975  int i = lfirst_int(lc);
4976  char *valstr;
4977 
4978  /* fetch next column's textual value */
4979  if (PQgetisnull(res, row, j))
4980  valstr = NULL;
4981  else
4982  valstr = PQgetvalue(res, row, j);
4983 
4984  /*
4985  * convert value to internal representation
4986  *
4987  * Note: we ignore system columns other than ctid and oid in result
4988  */
4989  errpos.cur_attno = i;
4990  if (i > 0)
4991  {
4992  /* ordinary column */
4993  Assert(i <= tupdesc->natts);
4994  nulls[i - 1] = (valstr == NULL);
4995  /* Apply the input function even to nulls, to support domains */
4996  values[i - 1] = InputFunctionCall(&attinmeta->attinfuncs[i - 1],
4997  valstr,
4998  attinmeta->attioparams[i - 1],
4999  attinmeta->atttypmods[i - 1]);
5000  }
5001  else if (i == SelfItemPointerAttributeNumber)
5002  {
5003  /* ctid */
5004  if (valstr != NULL)
5005  {
5006  Datum datum;
5007 
5008  datum = DirectFunctionCall1(tidin, CStringGetDatum(valstr));
5009  ctid = (ItemPointer) DatumGetPointer(datum);
5010  }
5011  }
5012  else if (i == ObjectIdAttributeNumber)
5013  {
5014  /* oid */
5015  if (valstr != NULL)
5016  {
5017  Datum datum;
5018 
5019  datum = DirectFunctionCall1(oidin, CStringGetDatum(valstr));
5020  oid = DatumGetObjectId(datum);
5021  }
5022  }
5023  errpos.cur_attno = 0;
5024 
5025  j++;
5026  }
5027 
5028  /* Uninstall error context callback. */
5029  error_context_stack = errcallback.previous;
5030 
5031  /*
5032  * Check we got the expected number of columns. Note: j == 0 and
5033  * PQnfields == 1 is expected, since deparse emits a NULL if no columns.
5034  */
5035  if (j > 0 && j != PQnfields(res))
5036  elog(ERROR, "remote query result does not match the foreign table");
5037 
5038  /*
5039  * Build the result tuple in caller's memory context.
5040  */
5041  MemoryContextSwitchTo(oldcontext);
5042 
5043  tuple = heap_form_tuple(tupdesc, values, nulls);
5044 
5045  /*
5046  * If we have a CTID to return, install it in both t_self and t_ctid.
5047  * t_self is the normal place, but if the tuple is converted to a
5048  * composite Datum, t_self will be lost; setting t_ctid allows CTID to be
5049  * preserved during EvalPlanQual re-evaluations (see ROW_MARK_COPY code).
5050  */
5051  if (ctid)
5052  tuple->t_self = tuple->t_data->t_ctid = *ctid;
5053 
5054  /*
5055  * Stomp on the xmin, xmax, and cmin fields from the tuple created by
5056  * heap_form_tuple. heap_form_tuple actually creates the tuple with
5057  * DatumTupleFields, not HeapTupleFields, but the executor expects
5058  * HeapTupleFields and will happily extract system columns on that
5059  * assumption. If we don't do this then, for example, the tuple length
5060  * ends up in the xmin field, which isn't what we want.
5061  */
5065 
5066  /*
5067  * If we have an OID to return, install it.
5068  */
5069  if (OidIsValid(oid))
5070  HeapTupleSetOid(tuple, oid);
5071 
5072  /* Clean up */
5073  MemoryContextReset(temp_context);
5074 
5075  return tuple;
5076 }
int PQnfields(const PGresult *res)
Definition: fe-exec.c:2681
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3067
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define DatumGetObjectId(X)
Definition: postgres.h:506
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int32 * atttypmods
Definition: funcapi.h:47
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
unsigned int Oid
Definition: postgres_ext.h:31
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
struct ErrorContextCallback * previous
Definition: elog.h:238
#define OidIsValid(objectId)
Definition: c.h:538
Oid * attioparams
Definition: funcapi.h:44
int natts
Definition: tupdesc.h:73
ItemPointerData * ItemPointer
Definition: itemptr.h:48
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
ErrorContextCallback * error_context_stack
Definition: elog.c:88
ForeignScanState * fsstate
Definition: postgres_fdw.c:256
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:107
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
#define CStringGetDatum(X)
Definition: postgres.h:584
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:374
#define InvalidTransactionId
Definition: transam.h:31
void * palloc0(Size size)
Definition: mcxt.c:878
static void conversion_error_callback(void *arg)
uintptr_t Datum
Definition: postgres.h:372
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1623
#define InvalidOid
Definition: postgres_ext.h:36
Datum tidin(PG_FUNCTION_ARGS)
Definition: tid.c:53
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
TupleDesc tupdesc
Definition: postgres_fdw.c:129
#define DatumGetPointer(X)
Definition: postgres.h:555
static Datum values[MAXATTR]
Definition: bootstrap.c:163
void(* callback)(void *arg)
Definition: elog.h:239
void * palloc(Size size)
Definition: mcxt.c:849
int i
Datum oidin(PG_FUNCTION_ARGS)
Definition: oid.c:117
FmgrInfo * attinfuncs
Definition: funcapi.h:41
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
#define elog
Definition: elog.h:219
AttrNumber cur_attno
Definition: postgres_fdw.c:248
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3092
#define HeapTupleHeaderSetCmin(tup, cid)
Definition: htup_details.h:391
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:313
static void merge_fdw_options ( PgFdwRelationInfo fpinfo,
const PgFdwRelationInfo fpinfo_o,
const PgFdwRelationInfo fpinfo_i 
)
static

Definition at line 4408 of file postgres_fdw.c.

References Assert, PgFdwRelationInfo::fdw_startup_cost, PgFdwRelationInfo::fdw_tuple_cost, PgFdwRelationInfo::fetch_size, Max, PgFdwRelationInfo::server, ForeignServer::serverid, PgFdwRelationInfo::shippable_extensions, and PgFdwRelationInfo::use_remote_estimate.

Referenced by add_foreign_grouping_paths(), and foreign_join_ok().

4411 {
4412  /* We must always have fpinfo_o. */
4413  Assert(fpinfo_o);
4414 
4415  /* fpinfo_i may be NULL, but if present the servers must both match. */
4416  Assert(!fpinfo_i ||
4417  fpinfo_i->server->serverid == fpinfo_o->server->serverid);
4418 
4419  /*
4420  * Copy the server specific FDW options. (For a join, both relations come
4421  * from the same server, so the server options should have the same value
4422  * for both relations.)
4423  */
4424  fpinfo->fdw_startup_cost = fpinfo_o->fdw_startup_cost;
4425  fpinfo->fdw_tuple_cost = fpinfo_o->fdw_tuple_cost;
4426  fpinfo->shippable_extensions = fpinfo_o->shippable_extensions;
4427  fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate;
4428  fpinfo->fetch_size = fpinfo_o->fetch_size;
4429 
4430  /* Merge the table level options from either side of the join. */
4431  if (fpinfo_i)
4432  {
4433  /*
4434  * We'll prefer to use remote estimates for this join if any table
4435  * from either side of the join is using remote estimates. This is
4436  * most likely going to be preferred since they're already willing to
4437  * pay the price of a round trip to get the remote EXPLAIN. In any
4438  * case it's not entirely clear how we might otherwise handle this
4439  * best.
4440  */
4441  fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate ||
4442  fpinfo_i->use_remote_estimate;
4443 
4444  /*
4445  * Set fetch size to maximum of the joining sides, since we are
4446  * expecting the rows returned by the join to be proportional to the
4447  * relation sizes.
4448  */
4449  fpinfo->fetch_size = Max(fpinfo_o->fetch_size, fpinfo_i->fetch_size);
4450  }
4451 }
ForeignServer * server
Definition: postgres_fdw.h:76
#define Max(x, y)
Definition: c.h:800
#define Assert(condition)
Definition: c.h:675
List * shippable_extensions
Definition: postgres_fdw.h:72
Oid serverid
Definition: foreign.h:47
PG_FUNCTION_INFO_V1 ( postgres_fdw_handler  )
Datum postgres_fdw_handler ( PG_FUNCTION_ARGS  )

Definition at line 429 of file postgres_fdw.c.

References FdwRoutine::AddForeignUpdateTargets, FdwRoutine::AnalyzeForeignTable, FdwRoutine::BeginDirectModify, FdwRoutine::BeginForeignModify, FdwRoutine::BeginForeignScan, FdwRoutine::EndDirectModify, FdwRoutine::EndForeignModify, FdwRoutine::EndForeignScan, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, FdwRoutine::ExplainDirectModify, FdwRoutine::ExplainForeignModify, FdwRoutine::ExplainForeignScan, FdwRoutine::GetForeignJoinPaths, FdwRoutine::GetForeignPaths, FdwRoutine::GetForeignPlan, FdwRoutine::GetForeignRelSize, FdwRoutine::GetForeignUpperPaths, FdwRoutine::ImportForeignSchema, FdwRoutine::IsForeignRelUpdatable, FdwRoutine::IterateDirectModify, FdwRoutine::IterateForeignScan, makeNode, PG_RETURN_POINTER, FdwRoutine::PlanDirectModify, FdwRoutine::PlanForeignModify, postgresAddForeignUpdateTargets(), postgresAnalyzeForeignTable(), postgresBeginDirectModify(), postgresBeginForeignModify(), postgresBeginForeignScan(), postgresEndDirectModify(), postgresEndForeignModify(), postgresEndForeignScan(), postgresExecForeignDelete(), postgresExecForeignInsert(), postgresExecForeignUpdate(), postgresExplainDirectModify(), postgresExplainForeignModify(), postgresExplainForeignScan(), postgresGetForeignJoinPaths(), postgresGetForeignPaths(), postgresGetForeignPlan(), postgresGetForeignRelSize(), postgresGetForeignUpperPaths(), postgresImportForeignSchema(), postgresIsForeignRelUpdatable(), postgresIterateDirectModify(), postgresIterateForeignScan(), postgresPlanDirectModify(), postgresPlanForeignModify(), postgresRecheckForeignScan(), postgresReScanForeignScan(), FdwRoutine::RecheckForeignScan, and FdwRoutine::ReScanForeignScan.

430 {
431  FdwRoutine *routine = makeNode(FdwRoutine);
432 
433  /* Functions for scanning foreign tables */
441 
442  /* Functions for updating foreign tables */
455 
456  /* Function for EvalPlanQual rechecks */
458  /* Support functions for EXPLAIN */
462 
463  /* Support functions for ANALYZE */
465 
466  /* Support functions for IMPORT FOREIGN SCHEMA */
468 
469  /* Support functions for join push-down */
471 
472  /* Support functions for upper relation push-down */
474 
475  PG_RETURN_POINTER(routine);
476 }
GetForeignPlan_function GetForeignPlan
Definition: fdwapi.h:176
BeginForeignScan_function BeginForeignScan
Definition: fdwapi.h:177
GetForeignUpperPaths_function GetForeignUpperPaths
Definition: fdwapi.h:191
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:199
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:321
EndDirectModify_function EndDirectModify
Definition: fdwapi.h:205
static ForeignScan * postgresGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan)
static void postgresExplainForeignModify(ModifyTableState *mtstate, ResultRelInfo *rinfo, List *fdw_private, int subplan_index, ExplainState *es)
static List * postgresPlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index)
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:213
static TupleTableSlot * postgresExecForeignUpdate(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
AnalyzeForeignTable_function AnalyzeForeignTable
Definition: fdwapi.h:218
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:197
static void postgresBeginForeignScan(ForeignScanState *node, int eflags)
static void postgresGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: postgres_fdw.c:486
static int postgresIsForeignRelUpdatable(Relation rel)
static bool postgresAnalyzeForeignTable(Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages)
static void postgresExplainDirectModify(ForeignScanState *node, ExplainState *es)
static TupleTableSlot * postgresExecForeignInsert(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
AddForeignUpdateTargets_function AddForeignUpdateTargets
Definition: fdwapi.h:194
static void postgresEndDirectModify(ForeignScanState *node)
RecheckForeignScan_function RecheckForeignScan
Definition: fdwapi.h:210
IterateDirectModify_function IterateDirectModify
Definition: fdwapi.h:204
static void postgresEndForeignScan(ForeignScanState *node)
GetForeignJoinPaths_function GetForeignJoinPaths
Definition: fdwapi.h:188
static List * postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
static void postgresBeginDirectModify(ForeignScanState *node, int eflags)
GetForeignRelSize_function GetForeignRelSize
Definition: fdwapi.h:174
EndForeignScan_function EndForeignScan
Definition: fdwapi.h:180
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:215
ImportForeignSchema_function ImportForeignSchema
Definition: fdwapi.h:221
PlanForeignModify_function PlanForeignModify
Definition: fdwapi.h:195
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:200
GetForeignPaths_function GetForeignPaths
Definition: fdwapi.h:175
static bool postgresPlanDirectModify(PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index)
static TupleTableSlot * postgresIterateForeignScan(ForeignScanState *node)
PlanDirectModify_function PlanDirectModify
Definition: fdwapi.h:202
static void postgresGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: postgres_fdw.c:885
static void postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel)
BeginDirectModify_function BeginDirectModify
Definition: fdwapi.h:203
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:198
static TupleTableSlot * postgresExecForeignDelete(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot)
#define makeNode(_type_)
Definition: nodes.h:557
ReScanForeignScan_function ReScanForeignScan
Definition: fdwapi.h:179
IterateForeignScan_function IterateForeignScan
Definition: fdwapi.h:178
static bool postgresRecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot)
static void postgresExplainForeignScan(ForeignScanState *node, ExplainState *es)
static void postgresBeginForeignModify(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, List *fdw_private, int subplan_index, int eflags)
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:214
static void postgresAddForeignUpdateTargets(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
static void postgresEndForeignModify(EState *estate, ResultRelInfo *resultRelInfo)
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:201
static TupleTableSlot * postgresIterateDirectModify(ForeignScanState *node)
static void postgresGetForeignJoinPaths(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:196
static void postgresReScanForeignScan(ForeignScanState *node)
static int postgresAcquireSampleRowsFunc ( Relation  relation,
int  elevel,
HeapTuple rows,
int  targrows,
double *  totalrows,
double *  totaldeadrows 
)
static

Definition at line 3555 of file postgres_fdw.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), analyze_row_processor(), PgFdwAnalyzeState::anl_cxt, appendStringInfo(), PgFdwAnalyzeState::attinmeta, CHECK_FOR_INTERRUPTS, close_cursor(), conn, CurrentMemoryContext, cursor_number, StringInfoData::data, defGetString(), DefElem::defname, deparseAnalyzeSql(), ereport, errmsg(), ERROR, fetch_size, GetConnection(), GetCursorNumber(), GetForeignServer(), GetForeignTable(), GetUserMapping(), i, initStringInfo(), lfirst, NULL, PgFdwAnalyzeState::numrows, ForeignServer::options, ForeignTable::options, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgfdw_exec_query(), pgfdw_report_error(), PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQntuples(), PQresultStatus(), RelationData::rd_rel, PgFdwAnalyzeState::rel, RelationGetDescr, RelationGetRelationName, RelationGetRelid, ReleaseConnection(), reservoir_init_selection_state(), PgFdwAnalyzeState::retrieved_attrs, PgFdwAnalyzeState::rows, PgFdwAnalyzeState::rowstoskip, PgFdwAnalyzeState::rstate, PgFdwAnalyzeState::samplerows, ForeignTable::serverid, snprintf(), PgFdwAnalyzeState::targrows, PgFdwAnalyzeState::temp_cxt, TupleDescGetAttInMetadata(), and user.

Referenced by postgresAnalyzeForeignTable().

3559 {
3560  PgFdwAnalyzeState astate;
3561  ForeignTable *table;
3562  ForeignServer *server;
3563  UserMapping *user;
3564  PGconn *conn;
3565  unsigned int cursor_number;
3566  StringInfoData sql;
3567  PGresult *volatile res = NULL;
3568 
3569  /* Initialize workspace state */
3570  astate.rel = relation;
3572 
3573  astate.rows = rows;
3574  astate.targrows = targrows;
3575  astate.numrows = 0;
3576  astate.samplerows = 0;
3577  astate.rowstoskip = -1; /* -1 means not set yet */
3578  reservoir_init_selection_state(&astate.rstate, targrows);
3579 
3580  /* Remember ANALYZE context, and create a per-tuple temp context */
3581  astate.anl_cxt = CurrentMemoryContext;
3583  "postgres_fdw temporary data",
3585 
3586  /*
3587  * Get the connection to use. We do the remote access as the table's
3588  * owner, even if the ANALYZE was started by some other user.
3589  */
3590  table = GetForeignTable(RelationGetRelid(relation));
3591  server = GetForeignServer(table->serverid);
3592  user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
3593  conn = GetConnection(user, false);
3594 
3595  /*
3596  * Construct cursor that retrieves whole rows from remote.
3597  */
3598  cursor_number = GetCursorNumber(conn);
3599  initStringInfo(&sql);
3600  appendStringInfo(&sql, "DECLARE c%u CURSOR FOR ", cursor_number);
3601  deparseAnalyzeSql(&sql, relation, &astate.retrieved_attrs);
3602 
3603  /* In what follows, do not risk leaking any PGresults. */
3604  PG_TRY();
3605  {
3606  res = pgfdw_exec_query(conn, sql.data);
3607  if (PQresultStatus(res) != PGRES_COMMAND_OK)
3608  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3609  PQclear(res);
3610  res = NULL;
3611 
3612  /* Retrieve and process rows a batch at a time. */
3613  for (;;)
3614  {
3615  char fetch_sql[64];
3616  int fetch_size;
3617  int numrows;
3618  int i;
3619  ListCell *lc;
3620 
3621  /* Allow users to cancel long query */
3623 
3624  /*
3625  * XXX possible future improvement: if rowstoskip is large, we
3626  * could issue a MOVE rather than physically fetching the rows,
3627  * then just adjust rowstoskip and samplerows appropriately.
3628  */
3629 
3630  /* The fetch size is arbitrary, but shouldn't be enormous. */
3631  fetch_size = 100;
3632  foreach(lc, server->options)
3633  {
3634  DefElem *def = (DefElem *) lfirst(lc);
3635 
3636  if (strcmp(def->defname, "fetch_size") == 0)
3637  {
3638  fetch_size = strtol(defGetString(def), NULL, 10);
3639  break;
3640  }
3641  }
3642  foreach(lc, table->options)
3643  {
3644  DefElem *def = (DefElem *) lfirst(lc);
3645 
3646  if (strcmp(def->defname, "fetch_size") == 0)
3647  {
3648  fetch_size = strtol(defGetString(def), NULL, 10);
3649  break;
3650  }
3651  }
3652 
3653  /* Fetch some rows */
3654  snprintf(fetch_sql, sizeof(fetch_sql), "FETCH %d FROM c%u",
3655  fetch_size, cursor_number);
3656 
3657  res = pgfdw_exec_query(conn, fetch_sql);
3658  /* On error, report the original query, not the FETCH. */
3659  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3660  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3661 
3662  /* Process whatever we got. */
3663  numrows = PQntuples(res);
3664  for (i = 0; i < numrows; i++)
3665  analyze_row_processor(res, i, &astate);
3666 
3667  PQclear(res);
3668  res = NULL;
3669 
3670  /* Must be EOF if we didn't get all the rows requested. */
3671  if (numrows < fetch_size)
3672  break;
3673  }
3674 
3675  /* Close the cursor, just to be tidy. */
3676  close_cursor(conn, cursor_number);
3677  }
3678  PG_CATCH();
3679  {
3680  if (res)
3681  PQclear(res);
3682  PG_RE_THROW();
3683  }
3684  PG_END_TRY();
3685 
3686  ReleaseConnection(conn);
3687 
3688  /* We assume that we have no dead tuple. */
3689  *totaldeadrows = 0.0;
3690 
3691  /* We've retrieved all living tuples from foreign server. */
3692  *totalrows = astate.samplerows;
3693 
3694  /*
3695  * Emit some interesting relation info
3696  */
3697  ereport(elevel,
3698  (errmsg("\"%s\": table contains %.0f rows, %d rows in sample",
3699  RelationGetRelationName(relation),
3700  astate.samplerows, astate.numrows)));
3701 
3702  return astate.numrows;
3703 }
HeapTuple * rows
Definition: postgres_fdw.c:228
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
uint64 fetch_size
Definition: logging.c:21
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void reservoir_init_selection_state(ReservoirState rs, int n)
Definition: sampling.c:129
Form_pg_class rd_rel
Definition: rel.h:114
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
static void close_cursor(PGconn *conn, unsigned int cursor_number)
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define ERROR
Definition: elog.h:43
PGconn * conn
Definition: streamutil.c:42
char * defGetString(DefElem *def)
Definition: define.c:49
#define RelationGetRelationName(relation)
Definition: rel.h:437
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
static unsigned int cursor_number
Definition: connection.c:60
#define ereport(elevel, rest)
Definition: elog.h:122
ReservoirStateData rstate
Definition: postgres_fdw.c:235
void deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
Definition: deparse.c:1838
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
AttInMetadata * attinmeta
Definition: postgres_fdw.c:224
static int elevel
Definition: vacuumlazy.c:137
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:93
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
void PQclear(PGresult *res)
Definition: fe-exec.c:650
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
#define PG_CATCH()
Definition: elog.h:293
MemoryContext temp_cxt
Definition: postgres_fdw.c:239
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Oid serverid
Definition: foreign.h:67
unsigned int GetCursorNumber(PGconn *conn)
Definition: connection.c:423
MemoryContext anl_cxt
Definition: postgres_fdw.c:238
#define PG_RE_THROW()
Definition: elog.h:314
List * options
Definition: foreign.h:68
static char * user
Definition: pg_regress.c:92
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
int i
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:166
char * defname
Definition: parsenodes.h:720
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define PG_TRY()
Definition: elog.h:284
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
List * options
Definition: foreign.h:53
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PG_END_TRY()
Definition: elog.h:300
static void postgresAddForeignUpdateTargets ( Query parsetree,
RangeTblEntry target_rte,
Relation  target_relation 
)
static

Definition at line 1505 of file postgres_fdw.c.

References InvalidOid, lappend(), list_length(), makeTargetEntry(), makeVar(), pstrdup(), Query::resultRelation, SelfItemPointerAttributeNumber, Query::targetList, and TIDOID.

Referenced by postgres_fdw_handler().

1508 {
1509  Var *var;
1510  const char *attrname;
1511  TargetEntry *tle;
1512 
1513  /*
1514  * In postgres_fdw, what we need is the ctid, same as for a regular table.
1515  */
1516 
1517  /* Make a Var representing the desired value */
1518  var = makeVar(parsetree->resultRelation,
1520  TIDOID,
1521  -1,
1522  InvalidOid,
1523  0);
1524 
1525  /* Wrap it in a resjunk TLE with the right name ... */
1526  attrname = "ctid";
1527 
1528  tle = makeTargetEntry((Expr *) var,
1529  list_length(parsetree->targetList) + 1,
1530  pstrdup(attrname),
1531  true);
1532 
1533  /* ... and add it to the query's targetlist */
1534  parsetree->targetList = lappend(parsetree->targetList, tle);
1535 }
char * pstrdup(const char *in)
Definition: mcxt.c:1077
int resultRelation
Definition: parsenodes.h:120
Definition: primnodes.h:163
List * targetList
Definition: parsenodes.h:138
#define TIDOID
Definition: pg_type.h:332
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:235
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
List * lappend(List *list, void *datum)
Definition: list.c:128
#define InvalidOid
Definition: postgres_ext.h:36
static int list_length(const List *l)
Definition: pg_list.h:89
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
static bool postgresAnalyzeForeignTable ( Relation  relation,
AcquireSampleRowsFunc func,
BlockNumber totalpages 
)
static

Definition at line 3477 of file postgres_fdw.c.

References conn, StringInfoData::data, deparseAnalyzeSizeSql(), elog, ERROR, GetConnection(), GetForeignTable(), GetUserMapping(), initStringInfo(), NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgfdw_exec_query(), pgfdw_report_error(), PGRES_TUPLES_OK, postgresAcquireSampleRowsFunc(), PQclear(), PQgetvalue(), PQnfields(), PQntuples(), PQresultStatus(), RelationData::rd_rel, RelationGetRelid, ReleaseConnection(), ForeignTable::serverid, and user.

Referenced by postgres_fdw_handler().

3480 {
3481  ForeignTable *table;
3482  UserMapping *user;
3483  PGconn *conn;
3484  StringInfoData sql;
3485  PGresult *volatile res = NULL;
3486 
3487  /* Return the row-analysis function pointer */
3489 
3490  /*
3491  * Now we have to get the number of pages. It's annoying that the ANALYZE
3492  * API requires us to return that now, because it forces some duplication
3493  * of effort between this routine and postgresAcquireSampleRowsFunc. But
3494  * it's probably not worth redefining that API at this point.
3495  */
3496 
3497  /*
3498  * Get the connection to use. We do the remote access as the table's
3499  * owner, even if the ANALYZE was started by some other user.
3500  */
3501  table = GetForeignTable(RelationGetRelid(relation));
3502  user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
3503  conn = GetConnection(user, false);
3504 
3505  /*
3506  * Construct command to get page count for relation.
3507  */
3508  initStringInfo(&sql);
3509  deparseAnalyzeSizeSql(&sql, relation);
3510 
3511  /* In what follows, do not risk leaking any PGresults. */
3512  PG_TRY();
3513  {
3514  res = pgfdw_exec_query(conn, sql.data);
3515  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3516  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3517 
3518  if (PQntuples(res) != 1 || PQnfields(res) != 1)
3519  elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
3520  *totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
3521 
3522  PQclear(res);
3523  res = NULL;
3524  }
3525  PG_CATCH();
3526  {
3527  if (res)
3528  PQclear(res);
3529  PG_RE_THROW();
3530  }
3531  PG_END_TRY();
3532 
3533  ReleaseConnection(conn);
3534 
3535  return true;
3536 }
int PQnfields(const PGresult *res)
Definition: fe-exec.c:2681
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3067
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
Form_pg_class rd_rel
Definition: rel.h:114
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
#define ERROR
Definition: elog.h:43
PGconn * conn
Definition: streamutil.c:42
static int postgresAcquireSampleRowsFunc(Relation relation, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
void PQclear(PGresult *res)
Definition: fe-exec.c:650
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
void deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
Definition: deparse.c:1818
Oid serverid
Definition: foreign.h:67
#define PG_RE_THROW()
Definition: elog.h:314
static char * user
Definition: pg_regress.c:92
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:166
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PG_END_TRY()
Definition: elog.h:300
static void postgresBeginDirectModify ( ForeignScanState node,
int  eflags 
)
static

Definition at line 2266 of file postgres_fdw.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), EXEC_FLAG_EXPLAIN_ONLY, ForeignScan::fdw_exprs, ForeignScan::fdw_private, ForeignScanState::fdw_state, FdwDirectModifyPrivateHasReturning, FdwDirectModifyPrivateRetrievedAttrs, FdwDirectModifyPrivateSetProcessed, FdwDirectModifyPrivateUpdateSql, GetConnection(), GetForeignTable(), GetUserId(), GetUserMapping(), intVal, list_length(), list_nth(), palloc0(), PlanState::plan, prepare_query_params(), ScanState::ps, RelationGetDescr, RelationGetRelid, rt_fetch, ForeignScan::scan, Scan::scanrelid, ForeignScanState::ss, ScanState::ss_currentRelation, PlanState::state, strVal, TupleDescGetAttInMetadata(), and user.

Referenced by postgres_fdw_handler().

2267 {
2268  ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
2269  EState *estate = node->ss.ps.state;
2270  PgFdwDirectModifyState *dmstate;
2271  RangeTblEntry *rte;
2272  Oid userid;
2273  ForeignTable *table;
2274  UserMapping *user;
2275  int numParams;
2276 
2277  /*
2278  * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
2279  */
2280  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
2281  return;
2282 
2283  /*
2284  * We'll save private state in node->fdw_state.
2285  */
2286  dmstate = (PgFdwDirectModifyState *) palloc0(sizeof(PgFdwDirectModifyState));
2287  node->fdw_state = (void *) dmstate;
2288 
2289  /*
2290  * Identify which user to do the remote access as. This should match what
2291  * ExecCheckRTEPerms() does.
2292  */
2293  rte = rt_fetch(fsplan->scan.scanrelid, estate->es_range_table);
2294  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
2295 
2296  /* Get info about foreign table. */
2297  dmstate->rel = node->ss.ss_currentRelation;
2298  table = GetForeignTable(RelationGetRelid(dmstate->rel));
2299  user = GetUserMapping(userid, table->serverid);
2300 
2301  /*
2302  * Get connection to the foreign server. Connection manager will
2303  * establish new connection if necessary.
2304  */
2305  dmstate->conn = GetConnection(user, false);
2306 
2307  /* Initialize state variable */
2308  dmstate->num_tuples = -1; /* -1 means not set yet */
2309 
2310  /* Get private info created by planner functions. */
2311  dmstate->query = strVal(list_nth(fsplan->fdw_private,
2313  dmstate->has_returning = intVal(list_nth(fsplan->fdw_private,
2315  dmstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
2317  dmstate->set_processed = intVal(list_nth(fsplan->fdw_private,
2319 
2320  /* Create context for per-tuple temp workspace. */
2321  dmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
2322  "postgres_fdw temporary data",
2324 
2325  /* Prepare for input conversion of RETURNING results. */
2326  if (dmstate->has_returning)
2327  dmstate->attinmeta = TupleDescGetAttInMetadata(RelationGetDescr(dmstate->rel));
2328 
2329  /*
2330  * Prepare for processing of parameters used in remote query, if any.
2331  */
2332  numParams = list_length(fsplan->fdw_exprs);
2333  dmstate->numParams = numParams;
2334  if (numParams > 0)
2336  fsplan->fdw_exprs,
2337  numParams,
2338  &dmstate->param_flinfo,
2339  &dmstate->param_exprs,
2340  &dmstate->param_values);
2341 }
ScanState ss
Definition: execnodes.h:1491
Index scanrelid
Definition: plannodes.h:318
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid GetUserId(void)
Definition: miscinit.c:283
static void prepare_query_params(PlanState *node, List *fdw_exprs, int numParams, FmgrInfo **param_flinfo, List **param_exprs, const char ***param_values)
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
List * fdw_exprs
Definition: plannodes.h:589
List * fdw_private
Definition: plannodes.h:590
#define strVal(v)
Definition: value.h:54
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
Relation ss_currentRelation
Definition: execnodes.h:1048
EState * state
Definition: execnodes.h:805
unsigned int Oid
Definition: postgres_ext.h:31
PlanState ps
Definition: execnodes.h:1047
void * list_nth(const List *list, int n)
Definition: list.c:410
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
Plan * plan
Definition: execnodes.h:803
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
static int list_length(const List *l)
Definition: pg_list.h:89
static char * user
Definition: pg_regress.c:92
#define intVal(v)
Definition: value.h:52
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:166
Definition: pg_list.h:45
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
#define RelationGetRelid(relation)
Definition: rel.h:417
static void postgresBeginForeignModify ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo,
List fdw_private,
int  subplan_index,
int  eflags 
)
static

Definition at line 1660 of file postgres_fdw.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), Assert, PgFdwModifyState::attinmeta, AttributeNumberIsValid, RangeTblEntry::checkAsUser, CMD_DELETE, CMD_INSERT, CMD_UPDATE, PgFdwModifyState::conn, PgFdwModifyState::ctidAttno, elog, ERROR, EState::es_query_cxt, EState::es_range_table, EXEC_FLAG_EXPLAIN_ONLY, ExecFindJunkAttributeInTlist(), FdwModifyPrivateHasReturning, FdwModifyPrivateRetrievedAttrs, FdwModifyPrivateTargetAttnums, FdwModifyPrivateUpdateSql, fmgr_info(), GetConnection(), GetForeignTable(), getTypeOutputInfo(), GetUserId(), GetUserMapping(), PgFdwModifyState::has_returning, intVal, lfirst_int, list_length(), list_nth(), ModifyTableState::mt_plans, NULL, ModifyTableState::operation, PgFdwModifyState::p_flinfo, PgFdwModifyState::p_name, PgFdwModifyState::p_nums, palloc0(), PlanState::plan, ModifyTableState::ps, PgFdwModifyState::query, PgFdwModifyState::rel, RelationGetDescr, RelationGetRelid, PgFdwModifyState::retrieved_attrs, ResultRelInfo::ri_FdwState, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, rt_fetch, ForeignTable::serverid, PlanState::state, strVal, PgFdwModifyState::target_attrs, Plan::targetlist, PgFdwModifyState::temp_cxt, TIDOID, TupleDescGetAttInMetadata(), and user.

Referenced by postgres_fdw_handler().

1665 {
1666  PgFdwModifyState *fmstate;
1667  EState *estate = mtstate->ps.state;
1668  CmdType operation = mtstate->operation;
1669  Relation rel = resultRelInfo->ri_RelationDesc;
1670  RangeTblEntry *rte;
1671  Oid userid;
1672  ForeignTable *table;
1673  UserMapping *user;
1674  AttrNumber n_params;
1675  Oid typefnoid;
1676  bool isvarlena;
1677  ListCell *lc;
1678 
1679  /*
1680  * Do nothing in EXPLAIN (no ANALYZE) case. resultRelInfo->ri_FdwState
1681  * stays NULL.
1682  */
1683  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
1684  return;
1685 
1686  /* Begin constructing PgFdwModifyState. */
1687  fmstate = (PgFdwModifyState *) palloc0(sizeof(PgFdwModifyState));
1688  fmstate->rel = rel;
1689 
1690  /*
1691  * Identify which user to do the remote access as. This should match what
1692  * ExecCheckRTEPerms() does.
1693  */
1694  rte = rt_fetch(resultRelInfo->ri_RangeTableIndex, estate->es_range_table);
1695  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1696 
1697  /* Get info about foreign table. */
1698  table = GetForeignTable(RelationGetRelid(rel));
1699  user = GetUserMapping(userid, table->serverid);
1700 
1701  /* Open connection; report that we'll create a prepared statement. */
1702  fmstate->conn = GetConnection(user, true);
1703  fmstate->p_name = NULL; /* prepared statement not made yet */
1704 
1705  /* Deconstruct fdw_private data. */
1706  fmstate->query = strVal(list_nth(fdw_private,
1708  fmstate->target_attrs = (List *) list_nth(fdw_private,
1710  fmstate->has_returning = intVal(list_nth(fdw_private,
1712  fmstate->retrieved_attrs = (List *) list_nth(fdw_private,
1714 
1715  /* Create context for per-tuple temp workspace. */
1716  fmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
1717  "postgres_fdw temporary data",
1719 
1720  /* Prepare for input conversion of RETURNING results. */
1721  if (fmstate->has_returning)
1723 
1724  /* Prepare for output conversion of parameters used in prepared stmt. */
1725  n_params = list_length(fmstate->target_attrs) + 1;
1726  fmstate->p_flinfo = (FmgrInfo *) palloc0(sizeof(FmgrInfo) * n_params);
1727  fmstate->p_nums = 0;
1728 
1729  if (operation == CMD_UPDATE || operation == CMD_DELETE)
1730  {
1731  /* Find the ctid resjunk column in the subplan's result */
1732  Plan *subplan = mtstate->mt_plans[subplan_index]->plan;
1733 
1735  "ctid");
1736  if (!AttributeNumberIsValid(fmstate->ctidAttno))
1737  elog(ERROR, "could not find junk ctid column");
1738 
1739  /* First transmittable parameter will be ctid */
1740  getTypeOutputInfo(TIDOID, &typefnoid, &isvarlena);
1741  fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
1742  fmstate->p_nums++;
1743  }
1744 
1745  if (operation == CMD_INSERT || operation == CMD_UPDATE)
1746  {
1747  /* Set up for remaining transmittable parameters */
1748  foreach(lc, fmstate->target_attrs)
1749  {
1750  int attnum = lfirst_int(lc);
1751  Form_pg_attribute attr = RelationGetDescr(rel)->attrs[attnum - 1];
1752 
1753  Assert(!attr->attisdropped);
1754 
1755  getTypeOutputInfo(attr->atttypid, &typefnoid, &isvarlena);
1756  fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
1757  fmstate->p_nums++;
1758  }
1759  }
1760 
1761  Assert(fmstate->p_nums <= n_params);
1762 
1763  resultRelInfo->ri_FdwState = fmstate;
1764 }
Definition: fmgr.h:56
Relation ri_RelationDesc
Definition: execnodes.h:374
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2632
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:221
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid GetUserId(void)
Definition: miscinit.c:283
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
#define strVal(v)
Definition: value.h:54
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
CmdType operation
Definition: execnodes.h:910
EState * state
Definition: execnodes.h:805
List * es_range_table
Definition: execnodes.h:411
unsigned int Oid
Definition: postgres_ext.h:31
List * retrieved_attrs
Definition: postgres_fdw.c:177
Index ri_RangeTableIndex
Definition: execnodes.h:373
#define TIDOID
Definition: pg_type.h:332
MemoryContext es_query_cxt
Definition: execnodes.h:438
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
#define lfirst_int(lc)
Definition: pg_list.h:107
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
void * list_nth(const List *list, int n)
Definition: list.c:410
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
AttrNumber ctidAttno
Definition: postgres_fdw.c:180
PlanState ** mt_plans
Definition: execnodes.h:913
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
FmgrInfo * p_flinfo
Definition: postgres_fdw.c:182
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
Plan * plan
Definition: execnodes.h:803
void * ri_FdwState
Definition: execnodes.h:383
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
MemoryContext temp_cxt
Definition: postgres_fdw.c:185
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Oid serverid
Definition: foreign.h:67
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:134
static char * user
Definition: pg_regress.c:92
#define intVal(v)
Definition: value.h:52
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:166
AttInMetadata * attinmeta
Definition: postgres_fdw.c:167
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:417
CmdType
Definition: nodes.h:648
static void postgresBeginForeignScan ( ForeignScanState node,
int  eflags 
)
static

Definition at line 1280 of file postgres_fdw.c.

References ALLOCSET_DEFAULT_SIZES, ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), bms_next_member(), EXEC_FLAG_EXPLAIN_ONLY, ForeignScan::fdw_exprs, ForeignScan::fdw_private, ForeignScanState::fdw_state, FdwScanPrivateFetchSize, FdwScanPrivateRetrievedAttrs, FdwScanPrivateSelectSql, ForeignScan::fs_relids, GetConnection(), GetCursorNumber(), GetForeignTable(), GetUserId(), GetUserMapping(), intVal, list_length(), list_nth(), NULL, palloc0(), PlanState::plan, prepare_query_params(), ScanState::ps, RelationGetDescr, rt_fetch, ForeignScan::scan, Scan::scanrelid, ForeignScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, strVal, TupleTableSlot::tts_tupleDescriptor, TupleDescGetAttInMetadata(), and user.

Referenced by postgres_fdw_handler().

1281 {
1282  ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
1283  EState *estate = node->ss.ps.state;
1284  PgFdwScanState *fsstate;
1285  RangeTblEntry *rte;
1286  Oid userid;
1287  ForeignTable *table;
1288  UserMapping *user;
1289  int rtindex;
1290  int numParams;
1291 
1292  /*
1293  * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
1294  */
1295  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
1296  return;
1297 
1298  /*
1299  * We'll save private state in node->fdw_state.
1300  */
1301  fsstate = (PgFdwScanState *) palloc0(sizeof(PgFdwScanState));
1302  node->fdw_state = (void *) fsstate;
1303 
1304  /*
1305  * Identify which user to do the remote access as. This should match what
1306  * ExecCheckRTEPerms() does. In case of a join or aggregate, use the
1307  * lowest-numbered member RTE as a representative; we would get the same
1308  * result from any.
1309  */
1310  if (fsplan->scan.scanrelid > 0)
1311  rtindex = fsplan->scan.scanrelid;
1312  else
1313  rtindex = bms_next_member(fsplan->fs_relids, -1);
1314  rte = rt_fetch(rtindex, estate->es_range_table);
1315  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1316 
1317  /* Get info about foreign table. */
1318  table = GetForeignTable(rte->relid);
1319  user = GetUserMapping(userid, table->serverid);
1320 
1321  /*
1322  * Get connection to the foreign server. Connection manager will
1323  * establish new connection if necessary.
1324  */
1325  fsstate->conn = GetConnection(user, false);
1326 
1327  /* Assign a unique ID for my cursor */
1328  fsstate->cursor_number = GetCursorNumber(fsstate->conn);
1329  fsstate->cursor_exists = false;
1330 
1331  /* Get private info created by planner functions. */
1332  fsstate->query = strVal(list_nth(fsplan->fdw_private,
1334  fsstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
1336  fsstate->fetch_size = intVal(list_nth(fsplan->fdw_private,
1338 
1339  /* Create contexts for batches of tuples and per-tuple temp workspace. */
1340  fsstate->batch_cxt = AllocSetContextCreate(estate->es_query_cxt,
1341  "postgres_fdw tuple data",
1343  fsstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
1344  "postgres_fdw temporary data",
1346 
1347  /*
1348  * Get info we'll need for converting data fetched from the foreign server
1349  * into local representation and error reporting during that process.
1350  */
1351  if (fsplan->scan.scanrelid > 0)
1352  {
1353  fsstate->rel = node->ss.ss_currentRelation;
1354  fsstate->tupdesc = RelationGetDescr(fsstate->rel);
1355  }
1356  else
1357  {
1358  fsstate->rel = NULL;
1359  fsstate->tupdesc = node->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
1360  }
1361 
1362  fsstate->attinmeta = TupleDescGetAttInMetadata(fsstate->tupdesc);
1363 
1364  /*
1365  * Prepare for processing of parameters used in remote query, if any.
1366  */
1367  numParams = list_length(fsplan->fdw_exprs);
1368  fsstate->numParams = numParams;
1369  if (numParams > 0)
1371  fsplan->fdw_exprs,
1372  numParams,
1373  &fsstate->param_flinfo,
1374  &fsstate->param_exprs,
1375  &fsstate->param_values);
1376 }
ScanState ss
Definition: execnodes.h:1491
Index scanrelid
Definition: plannodes.h:318
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid GetUserId(void)
Definition: miscinit.c:283
static void prepare_query_params(PlanState *node, List *fdw_exprs, int numParams, FmgrInfo **param_flinfo, List **param_exprs, const char ***param_values)
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
List * fdw_exprs
Definition: plannodes.h:589
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:937
List * fdw_private
Definition: plannodes.h:590
#define strVal(v)
Definition: value.h:54
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
Relation ss_currentRelation
Definition: execnodes.h:1048
EState * state
Definition: execnodes.h:805
unsigned int Oid
Definition: postgres_ext.h:31
PlanState ps
Definition: execnodes.h:1047
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void * list_nth(const List *list, int n)
Definition: list.c:410
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
Plan * plan
Definition: execnodes.h:803
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
#define NULL
Definition: c.h:229
unsigned int GetCursorNumber(PGconn *conn)
Definition: connection.c:423
static int list_length(const List *l)
Definition: pg_list.h:89
static char * user
Definition: pg_regress.c:92
#define intVal(v)
Definition: value.h:52
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:166
Definition: pg_list.h:45
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
Bitmapset * fs_relids
Definition: plannodes.h:594
static void postgresEndDirectModify ( ForeignScanState node)
static

Definition at line 2392 of file postgres_fdw.c.

References PgFdwDirectModifyState::conn, ForeignScanState::fdw_state, NULL, PQclear(), ReleaseConnection(), and PgFdwDirectModifyState::result.

Referenced by postgres_fdw_handler().

2393 {
2395 
2396  /* if dmstate is NULL, we are in EXPLAIN; nothing to do */
2397  if (dmstate == NULL)
2398  return;
2399 
2400  /* Release PGresult */
2401  if (dmstate->result)
2402  PQclear(dmstate->result);
2403 
2404  /* Release remote connection */
2405  ReleaseConnection(dmstate->conn);
2406  dmstate->conn = NULL;
2407 
2408  /* MemoryContext will be deleted automatically. */
2409 }
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define NULL
Definition: c.h:229
static void postgresEndForeignModify ( EState estate,
ResultRelInfo resultRelInfo 
)
static

Definition at line 1987 of file postgres_fdw.c.

References PgFdwModifyState::conn, ERROR, NULL, PgFdwModifyState::p_name, pgfdw_exec_query(), pgfdw_report_error(), PGRES_COMMAND_OK, PQclear(), PQresultStatus(), ReleaseConnection(), ResultRelInfo::ri_FdwState, and snprintf().

Referenced by postgres_fdw_handler().

1989 {
1990  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1991 
1992  /* If fmstate is NULL, we are in EXPLAIN; nothing to do */
1993  if (fmstate == NULL)
1994  return;
1995 
1996  /* If we created a prepared statement, destroy it */
1997  if (fmstate->p_name)
1998  {
1999  char sql[64];
2000  PGresult *res;
2001 
2002  snprintf(sql, sizeof(sql), "DEALLOCATE %s", fmstate->p_name);
2003 
2004  /*
2005  * We don't use a PG_TRY block here, so be careful not to throw error
2006  * without releasing the PGresult.
2007  */
2008  res = pgfdw_exec_query(fmstate->conn, sql);
2009  if (PQresultStatus(res) != PGRES_COMMAND_OK)
2010  pgfdw_report_error(ERROR, res, fmstate->conn, true, sql);
2011  PQclear(res);
2012  fmstate->p_name = NULL;
2013  }
2014 
2015  /* Release remote connection */
2016  ReleaseConnection(fmstate->conn);
2017  fmstate->conn = NULL;
2018 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
void * ri_FdwState
Definition: execnodes.h:383
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define NULL
Definition: c.h:229
PGresult * pgfdw_exec_query(PGconn *conn, const char *query)
Definition: connection.c:450
static void postgresEndForeignScan ( ForeignScanState node)
static

Definition at line 1481 of file postgres_fdw.c.

References close_cursor(), PgFdwScanState::conn, PgFdwScanState::cursor_exists, PgFdwScanState::cursor_number, ForeignScanState::fdw_state, NULL, and ReleaseConnection().

Referenced by postgres_fdw_handler().

1482 {
1483  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
1484 
1485  /* if fsstate is NULL, we are in EXPLAIN; nothing to do */
1486  if (fsstate == NULL)
1487  return;
1488 
1489  /* Close the cursor if open, to prevent accumulation of cursors */
1490  if (fsstate->cursor_exists)
1491  close_cursor(fsstate->conn, fsstate->cursor_number);
1492 
1493  /* Release remote connection */
1494  ReleaseConnection(fsstate->conn);
1495  fsstate->conn = NULL;
1496 
1497  /* MemoryContexts will be deleted automatically. */
1498 }
static void close_cursor(PGconn *conn, unsigned int cursor_number)
unsigned int cursor_number
Definition: postgres_fdw.c:138
void ReleaseConnection(PGconn *conn)
Definition: connection.c:402
#define NULL
Definition: c.h:229
static TupleTableSlot * postgresExecForeignDelete ( EState estate,
ResultRelInfo resultRelInfo,
TupleTableSlot slot,
TupleTableSlot planSlot 
)
static

Definition at line 1911 of file postgres_fdw.c.

References PgFdwModifyState::conn, convert_prep_stmt_params(), PgFdwModifyState::ctidAttno, DatumGetPointer, elog, ERROR, ExecGetJunkAttribute(), PgFdwModifyState::has_returning, MemoryContextReset(), NULL, PgFdwModifyState::p_name, PgFdwModifyState::p_nums, pgfdw_get_result(), pgfdw_report_error(), PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQcmdTuples(), PQntuples(), PQresultStatus(), PQsendQueryPrepared(), prepare_foreign_modify(), PgFdwModifyState::query, ResultRelInfo::ri_FdwState, store_returning_result(), and PgFdwModifyState::temp_cxt.

Referenced by postgres_fdw_handler().

1915 {
1916  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1917  Datum datum;
1918  bool isNull;
1919  const char **p_values;
1920  PGresult *res;
1921  int n_rows;
1922 
1923  /* Set up the prepared statement on the remote server, if we didn't yet */
1924  if (!fmstate->p_name)
1925  prepare_foreign_modify(fmstate);
1926 
1927  /* Get the ctid that was passed up as a resjunk column */
1928  datum = ExecGetJunkAttribute(planSlot,
1929  fmstate->ctidAttno,
1930  &isNull);
1931  /* shouldn't ever get a null result... */
1932  if (isNull)
1933  elog(ERROR, "ctid is NULL");
1934 
1935  /* Convert parameters needed by prepared statement to text form */
1936  p_values = convert_prep_stmt_params(fmstate,
1937  (ItemPointer) DatumGetPointer(datum),
1938  NULL);
1939 
1940  /*
1941  * Execute the prepared statement.
1942  */
1943  if (!PQsendQueryPrepared(fmstate->conn,
1944  fmstate->p_name,
1945  fmstate->p_nums,
1946  p_values,
1947  NULL,
1948  NULL,
1949  0))
1950  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1951 
1952  /*
1953  * Get the result, and check for success.
1954  *
1955  * We don't use a PG_TRY block here, so be careful not to throw error
1956  * without releasing the PGresult.
1957  */
1958  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1959  if (PQresultStatus(res) !=
1961  pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1962 
1963  /* Check number of rows affected, and fetch RETURNING tuple if any */
1964  if (fmstate->has_returning)
1965  {
1966  n_rows = PQntuples(res);
1967  if (n_rows > 0)
1968  store_returning_result(fmstate, slot, res);
1969  }
1970  else
1971  n_rows = atoi(PQcmdTuples(res));
1972 
1973  /* And clean up */
1974  PQclear(res);
1975 
1976  MemoryContextReset(fmstate->temp_cxt);
1977 
1978  /* Return NULL if nothing was deleted on the remote end */
1979  return (n_rows > 0) ? slot : NULL;
1980 }
char * PQcmdTuples(PGresult *res)
Definition: fe-exec.c:3014
static void store_returning_result(PgFdwModifyState *fmstate, TupleTableSlot *slot, PGresult *res)
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
AttrNumber ctidAttno
Definition: postgres_fdw.c:180
uintptr_t Datum
Definition: postgres.h:372
void * ri_FdwState
Definition: execnodes.h:383
void PQclear(PGresult *res)
Definition: fe-exec.c:650
MemoryContext temp_cxt
Definition: postgres_fdw.c:185
PGresult * pgfdw_get_result(PGconn *conn, const char *query)
Definition: connection.c:474
#define NULL
Definition: c.h:229
static const char ** convert_prep_stmt_params(PgFdwModifyState *fmstate, ItemPointer tupleid, TupleTableSlot *slot)
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1325
#define DatumGetPointer(X)
Definition: postgres.h:555
static void prepare_foreign_modify(PgFdwModifyState *fmstate)
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:248
#define elog
Definition: elog.h:219
static TupleTableSlot * postgresExecForeignInsert ( EState estate,
ResultRelInfo resultRelInfo,
TupleTableSlot slot,
TupleTableSlot planSlot 
)
static

Definition at line 1771 of file postgres_fdw.c.

References PgFdwModifyState::conn, convert_prep_stmt_params(), ERROR, PgFdwModifyState::has_returning, MemoryContextReset(), NULL, PgFdwModifyState::p_name, PgFdwModifyState::p_nums, pgfdw_get_result(), pgfdw_report_error(), PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQcmdTuples(), PQntuples(), PQresultStatus(), PQsendQueryPrepared(), prepare_foreign_modify(), PgFdwModifyState::query, ResultRelInfo::ri_FdwState, store_returning_result(), and PgFdwModifyState::temp_cxt.

Referenced by postgres_fdw_handler().

1775 {
1776  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1777  const char **p_values;
1778  PGresult *res;
1779  int n_rows;
1780 
1781  /* Set up the prepared statement on the remote server, if we didn't yet */
1782  if (!fmstate->p_name)
1783  prepare_foreign_modify(fmstate);
1784 
1785  /* Convert parameters needed by prepared statement to text form */
1786  p_values = convert_prep_stmt_params(fmstate, NULL, slot);
1787 
1788  /*
1789  * Execute the prepared statement.
1790  */
1791  if (!PQsendQueryPrepared(fmstate->conn,
1792  fmstate->p_name,
1793  fmstate->p_nums,
1794  p_values,
1795  NULL,
1796  NULL,
1797  0))
1798  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1799 
1800  /*
1801  * Get the result, and check for success.
1802  *
1803  * We don't use a PG_TRY block here, so be careful not to throw error
1804  * without releasing the PGresult.
1805  */
1806  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1807  if (PQresultStatus(res) !=
1809  pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1810 
1811  /* Check number of rows affected, and fetch RETURNING tuple if any */
1812  if (fmstate->has_returning)
1813  {
1814  n_rows = PQntuples(res);
1815  if (n_rows > 0)
1816  store_returning_result(fmstate, slot, res);
1817  }
1818  else
1819  n_rows = atoi(PQcmdTuples(res));
1820 
1821  /* And clean up */
1822  PQclear(res);
1823 
1824  MemoryContextReset(fmstate->temp_cxt);
1825 
1826  /* Return NULL if nothing was inserted on the remote end */
1827  return (n_rows > 0) ? slot : NULL;
1828 }
char * PQcmdTuples(PGresult *res)
Definition: fe-exec.c:3014
static void store_returning_result(PgFdwModifyState *fmstate, TupleTableSlot *slot, PGresult *res)
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
#define ERROR
Definition: elog.h:43
void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql)
Definition: connection.c:528
void * ri_FdwState
Definition: execnodes.h:383
void PQclear(PGresult *res)
Definition: fe-exec.c:650
MemoryContext temp_cxt
Definition: postgres_fdw.c:185
PGresult * pgfdw_get_result(PGconn *conn, const char *query)
Definition: connection.c:474
#define NULL
Definition: c.h:229
static const char ** convert_prep_stmt_params(PgFdwModifyState *fmstate, ItemPointer tupleid, TupleTableSlot *slot)
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1325
static void prepare_foreign_modify(PgFdwModifyState *fmstate)
static TupleTableSlot * postgresExecForeignUpdate ( EState estate,
ResultRelInfo resultRelInfo,
TupleTableSlot slot,
TupleTableSlot planSlot 
)
static

Definition at line 1835 of file postgres_fdw.c.

References PgFdwModifyState::conn, convert_prep_stmt_params(), PgFdwModifyState::ctidAttno, DatumGetPointer, elog, ERROR, ExecGetJunkAttribute(), PgFdwModifyState::has_returning, MemoryContextReset(), NULL, PgFdwModifyState::p_name, PgFdwModifyState::p_nums, pgfdw_get_result(), pgfdw_report_error(), PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQcmdTuples(), PQntuples(), PQresultStatus(), PQsendQueryPrepared(), prepare_foreign_modify(), PgFdwModifyState::query, ResultRelInfo::ri_FdwState, store_returning_result(), and PgFdwModifyState::temp_cxt.

Referenced by postgres_fdw_handler().

1839 {
1840  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1841  Datum datum;
1842  bool isNull;
1843  const char **p_values;
1844  PGresult *res;
1845  int n_rows;
1846 
1847  /* Set up the prepared statement on the remote server, if we didn't yet */
1848  if (!fmstate->p_name)
1849  prepare_foreign_modify(fmstate);
1850 
1851  /* Get the ctid that was passed up as a resjunk column */
1852  datum = ExecGetJunkAttribute(planSlot,
1853  fmstate->ctidAttno,
1854  &isNull);
1855  /* shouldn't ever get a null result... */
1856  if (isNull)
1857  elog(ERROR, "ctid is NULL");
1858 
1859  /* Convert parameters needed by prepared statement to text form */
1860  p_values = convert_prep_stmt_params(fmstate,
1861  (ItemPointer) DatumGetPointer(datum),
1862  slot);
1863 
1864  /*
1865  * Execute the prepared statement.
1866  */
1867  if (!PQsendQueryPrepared(fmstate->conn,
1868  fmstate->p_name,
1869  fmstate->p_nums,
1870  p_values,
1871  NULL,
1872  NULL,
1873  0))
1874  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1875 
1876  /*
1877  * Get the result, and check for success.
1878  *
1879  * We don't use a PG_TRY block here, so be careful not to throw error
1880  * without releasing the PGresult.
1881  */
1882  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1883  if (PQresultStatus(res) !=
1884  (fmstate->has_returning ?