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, FdwScanPrivateRemoteConds, 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)
 
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 112 of file postgres_fdw.c.

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

Definition at line 91 of file postgres_fdw.c.

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

Definition at line 63 of file postgres_fdw.c.

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

Function Documentation

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

Definition at line 4747 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, NIL, NULL, PgFdwRelationInfo::outerrel, parse(), PlannerInfo::parse, PgFdwRelationInfo::rows, PgFdwRelationInfo::server, PgFdwRelationInfo::shippable_extensions, PgFdwRelationInfo::startup_cost, PgFdwRelationInfo::table, PgFdwRelationInfo::total_cost, PlannerInfo::upper_targets, UPPERREL_GROUP_AGG, PgFdwRelationInfo::user, and PgFdwRelationInfo::width.

Referenced by postgresGetForeignUpperPaths().

4749 {
4750  Query *parse = root->parse;
4751  PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
4752  PgFdwRelationInfo *fpinfo = grouped_rel->fdw_private;
4753  ForeignPath *grouppath;
4754  PathTarget *grouping_target;
4755  double rows;
4756  int width;
4757  Cost startup_cost;
4758  Cost total_cost;
4759 
4760  /* Nothing to be done, if there is no grouping or aggregation required. */
4761  if (!parse->groupClause && !parse->groupingSets && !parse->hasAggs &&
4762  !root->hasHavingQual)
4763  return;
4764 
4765  grouping_target = root->upper_targets[UPPERREL_GROUP_AGG];
4766 
4767  /* save the input_rel as outerrel in fpinfo */
4768  fpinfo->outerrel = input_rel;
4769 
4770  /*
4771  * Copy foreign table, foreign server, user mapping, shippable extensions
4772  * etc. details from the input relation's fpinfo.
4773  */
4774  fpinfo->table = ifpinfo->table;
4775  fpinfo->server = ifpinfo->server;
4776  fpinfo->user = ifpinfo->user;
4777  fpinfo->shippable_extensions = ifpinfo->shippable_extensions;
4778 
4779  /* Assess if it is safe to push down aggregation and grouping. */
4780  if (!foreign_grouping_ok(root, grouped_rel))
4781  return;
4782 
4783  /* Estimate the cost of push down */
4784  estimate_path_cost_size(root, grouped_rel, NIL, NIL, &rows,
4785  &width, &startup_cost, &total_cost);
4786 
4787  /* Now update this information in the fpinfo */
4788  fpinfo->rows = rows;
4789  fpinfo->width = width;
4790  fpinfo->startup_cost = startup_cost;
4791  fpinfo->total_cost = total_cost;
4792 
4793  /* Create and add foreign path to the grouping relation. */
4794  grouppath = create_foreignscan_path(root,
4795  grouped_rel,
4796  grouping_target,
4797  rows,
4798  startup_cost,
4799  total_cost,
4800  NIL, /* no pathkeys */
4801  NULL, /* no required_outer */
4802  NULL,
4803  NIL); /* no fdw_private */
4804 
4805  /* Add generated path into grouped_rel by add_path(). */
4806  add_path(grouped_rel, (Path *) grouppath);
4807 }
#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:116
ForeignServer * server
Definition: postgres_fdw.h:78
List * groupingSets
Definition: parsenodes.h:139
RelOptInfo * outerrel
Definition: postgres_fdw.h:91
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:1934
UserMapping * user
Definition: postgres_fdw.h:79
static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel)
void * fdw_private
Definition: relation.h:546
#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:77
List * groupClause
Definition: parsenodes.h:137
bool hasHavingQual
Definition: relation.h:301
List * shippable_extensions
Definition: postgres_fdw.h:74
Definition: relation.h:911
double Cost
Definition: nodes.h:646
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 4332 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().

4334 {
4335  List *useful_pathkeys_list = NIL; /* List of all pathkeys */
4336  ListCell *lc;
4337 
4338  useful_pathkeys_list = get_useful_pathkeys_for_relation(root, rel);
4339 
4340  /* Create one path for each set of pathkeys we found above. */
4341  foreach(lc, useful_pathkeys_list)
4342  {
4343  double rows;
4344  int width;
4345  Cost startup_cost;
4346  Cost total_cost;
4347  List *useful_pathkeys = lfirst(lc);
4348 
4349  estimate_path_cost_size(root, rel, NIL, useful_pathkeys,
4350  &rows, &width, &startup_cost, &total_cost);
4351 
4352  add_path(rel, (Path *)
4353  create_foreignscan_path(root, rel,
4354  NULL,
4355  rows,
4356  startup_cost,
4357  total_cost,
4358  useful_pathkeys,
4359  NULL,
4360  epq_path,
4361  NIL));
4362  }
4363 }
#define NIL
Definition: pg_list.h:69
static List * get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition: postgres_fdw.c:795
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:1934
#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:911
double Cost
Definition: nodes.h:646
static void analyze_row_processor ( PGresult res,
int  row,
PgFdwAnalyzeState astate 
)
static

Definition at line 3709 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().

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

Definition at line 3113 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().

3114 {
3115  char sql[64];
3116  PGresult *res;
3117 
3118  snprintf(sql, sizeof(sql), "CLOSE c%u", cursor_number);
3119 
3120  /*
3121  * We don't use a PG_TRY block here, so be careful not to throw error
3122  * without releasing the PGresult.
3123  */
3124  res = pgfdw_exec_query(conn, sql);
3125  if (PQresultStatus(res) != PGRES_COMMAND_OK)
3126  pgfdw_report_error(ERROR, res, conn, true, sql);
3127  PQclear(res);
3128 }
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 4988 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(), 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().

4989 {
4990  const char *attname = NULL;
4991  const char *relname = NULL;
4992  bool is_wholerow = false;
4994 
4995  if (errpos->rel)
4996  {
4997  /* error occurred in a scan against a foreign table */
4998  TupleDesc tupdesc = RelationGetDescr(errpos->rel);
4999 
5000  if (errpos->cur_attno > 0 && errpos->cur_attno <= tupdesc->natts)
5001  attname = NameStr(tupdesc->attrs[errpos->cur_attno - 1]->attname);
5002  else if (errpos->cur_attno == SelfItemPointerAttributeNumber)
5003  attname = "ctid";
5004  else if (errpos->cur_attno == ObjectIdAttributeNumber)
5005  attname = "oid";
5006 
5007  relname = RelationGetRelationName(errpos->rel);
5008  }
5009  else
5010  {
5011  /* error occurred in a scan against a foreign join */
5012  ForeignScanState *fsstate = errpos->fsstate;
5013  ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
5014  EState *estate = fsstate->ss.ps.state;
5015  TargetEntry *tle;
5016 
5018  errpos->cur_attno - 1));
5019 
5020  /*
5021  * Target list can have Vars and expressions. For Vars, we can get
5022  * it's relation, however for expressions we can't. Thus for
5023  * expressions, just show generic context message.
5024  */
5025  if (IsA(tle->expr, Var))
5026  {
5027  RangeTblEntry *rte;
5028  Var *var = (Var *) tle->expr;
5029 
5030  rte = rt_fetch(var->varno, estate->es_range_table);
5031 
5032  if (var->varattno == 0)
5033  is_wholerow = true;
5034  else
5035  attname = get_relid_attribute_name(rte->relid, var->varattno);
5036 
5037  relname = get_rel_name(rte->relid);
5038  }
5039  else
5040  errcontext("processing expression at position %d in select list",
5041  errpos->cur_attno);
5042  }
5043 
5044  if (relname)
5045  {
5046  if (is_wholerow)
5047  errcontext("whole-row reference to foreign table \"%s\"", relname);
5048  else if (attname)
5049  errcontext("column \"%s\" of foreign table \"%s\"", attname, relname);
5050  }
5051 }
ScanState ss
Definition: execnodes.h:1714
#define IsA(nodeptr, _type_)
Definition: nodes.h:573
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
Form_pg_attribute * attrs
Definition: tupdesc.h:74
AttrNumber varattno
Definition: primnodes.h:168
List * fdw_scan_tlist
Definition: plannodes.h:579
EState * state
Definition: execnodes.h:1051
List * es_range_table
Definition: execnodes.h:374
Definition: primnodes.h:163
int natts
Definition: tupdesc.h:73
PlanState ps
Definition: execnodes.h:1290
ForeignScanState * fsstate
Definition: postgres_fdw.c:258
void * list_nth(const List *list, int n)
Definition: list.c:410
#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:1049
#define NULL
Definition: c.h:229
Expr * expr
Definition: primnodes.h:1352
#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:250
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
static const char ** convert_prep_stmt_params ( PgFdwModifyState fmstate,
ItemPointer  tupleid,
TupleTableSlot slot 
)
static

Definition at line 3185 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().

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

Definition at line 2917 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().

2918 {
2919  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
2920  ExprContext *econtext = node->ss.ps.ps_ExprContext;
2921  int numParams = fsstate->numParams;
2922  const char **values = fsstate->param_values;
2923  PGconn *conn = fsstate->conn;
2925  PGresult *res;
2926 
2927  /*
2928  * Construct array of query parameter values in text format. We do the
2929  * conversions in the short-lived per-tuple context, so as not to cause a
2930  * memory leak over repeated scans.
2931  */
2932  if (numParams > 0)
2933  {
2934  MemoryContext oldcontext;
2935 
2936  oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
2937 
2938  process_query_params(econtext,
2939  fsstate->param_flinfo,
2940  fsstate->param_exprs,
2941  values);
2942 
2943  MemoryContextSwitchTo(oldcontext);
2944  }
2945 
2946  /* Construct the DECLARE CURSOR command */
2947  initStringInfo(&buf);
2948  appendStringInfo(&buf, "DECLARE c%u CURSOR FOR\n%s",
2949  fsstate->cursor_number, fsstate->query);
2950 
2951  /*
2952  * Notice that we pass NULL for paramTypes, thus forcing the remote server
2953  * to infer types for all parameters. Since we explicitly cast every
2954  * parameter (see deparse.c), the "inference" is trivial and will produce
2955  * the desired result. This allows us to avoid assuming that the remote
2956  * server has the same OIDs we do for the parameters' types.
2957  */
2958  if (!PQsendQueryParams(conn, buf.data, numParams,
2959  NULL, values, NULL, NULL, 0))
2960  pgfdw_report_error(ERROR, NULL, conn, false, buf.data);
2961 
2962  /*
2963  * Get the result, and check for success.
2964  *
2965  * We don't use a PG_TRY block here, so be careful not to throw error
2966  * without releasing the PGresult.
2967  */
2968  res = pgfdw_get_result(conn, buf.data);
2969  if (PQresultStatus(res) != PGRES_COMMAND_OK)
2970  pgfdw_report_error(ERROR, res, conn, true, fsstate->query);
2971  PQclear(res);
2972 
2973  /* Mark the cursor as created, and show no tuples have been retrieved */
2974  fsstate->cursor_exists = true;
2975  fsstate->tuples = NULL;
2976  fsstate->num_tuples = 0;
2977  fsstate->next_tuple = 0;
2978  fsstate->fetch_ct_2 = 0;
2979  fsstate->eof_reached = false;
2980 
2981  /* Clean up */
2982  pfree(buf.data);
2983 }
ScanState ss
Definition: execnodes.h:1714
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:144
ExprContext * ps_ExprContext
Definition: execnodes.h:1080
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:140
PlanState ps
Definition: execnodes.h:1290
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:145
PGconn * conn
Definition: streamutil.c:42
static char * buf
Definition: pg_test_fsync.c:65
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:143
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:148
static Datum values[MAXATTR]
Definition: bootstrap.c:162
static bool ec_member_matches_foreign ( PlannerInfo root,
RelOptInfo rel,
EquivalenceClass ec,
EquivalenceMember em,
void *  arg 
)
static

Definition at line 2888 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().

2891 {
2893  Expr *expr = em->em_expr;
2894 
2895  /*
2896  * If we've identified what we're processing in the current scan, we only
2897  * want to match that expression.
2898  */
2899  if (state->current != NULL)
2900  return equal(expr, state->current);
2901 
2902  /*
2903  * Otherwise, ignore anything we've already processed.
2904  */
2905  if (list_member(state->already_used, expr))
2906  return false;
2907 
2908  /* This is the new target to process. */
2909  state->current = expr;
2910  return true;
2911 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2946
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 2494 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, 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, RELOPT_JOINREL, RELOPT_UPPER_REL, RelOptInfo::reloptkind, 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().

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

Definition at line 3276 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().

3277 {
3279  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3280  int numParams = dmstate->numParams;
3281  const char **values = dmstate->param_values;
3282 
3283  /*
3284  * Construct array of query parameter values in text format.
3285  */
3286  if (numParams > 0)
3287  process_query_params(econtext,
3288  dmstate->param_flinfo,
3289  dmstate->param_exprs,
3290  values);
3291 
3292  /*
3293  * Notice that we pass NULL for paramTypes, thus forcing the remote server
3294  * to infer types for all parameters. Since we explicitly cast every
3295  * parameter (see deparse.c), the "inference" is trivial and will produce
3296  * the desired result. This allows us to avoid assuming that the remote
3297  * server has the same OIDs we do for the parameters' types.
3298  */
3299  if (!PQsendQueryParams(dmstate->conn, dmstate->query, numParams,
3300  NULL, values, NULL, NULL, 0))
3301  pgfdw_report_error(ERROR, NULL, dmstate->conn, false, dmstate->query);
3302 
3303  /*
3304  * Get the result, and check for success.
3305  *
3306  * We don't use a PG_TRY block here, so be careful not to throw error
3307  * without releasing the PGresult.
3308  */
3309  dmstate->result = pgfdw_get_result(dmstate->conn, dmstate->query);
3310  if (PQresultStatus(dmstate->result) !=
3312  pgfdw_report_error(ERROR, dmstate->result, dmstate->conn, true,
3313  dmstate->query);
3314 
3315  /* Get the number of rows affected. */
3316  if (dmstate->has_returning)
3317  dmstate->num_tuples = PQntuples(dmstate->result);
3318  else
3319  dmstate->num_tuples = atoi(PQcmdTuples(dmstate->result));
3320 }
ScanState ss
Definition: execnodes.h:1714
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:209
char * PQcmdTuples(PGresult *res)
Definition: fe-exec.c:3014
ExprContext * ps_ExprContext
Definition: execnodes.h:1080
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:1290
#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:162
static void fetch_more_data ( ForeignScanState node)
static

Definition at line 2989 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().

2990 {
2991  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
2992  PGresult *volatile res = NULL;
2993  MemoryContext oldcontext;
2994 
2995  /*
2996  * We'll store the tuples in the batch_cxt. First, flush the previous
2997  * batch.
2998  */
2999  fsstate->tuples = NULL;
3000  MemoryContextReset(fsstate->batch_cxt);
3001  oldcontext = MemoryContextSwitchTo(fsstate->batch_cxt);
3002 
3003  /* PGresult must be released before leaving this function. */
3004  PG_TRY();
3005  {
3006  PGconn *conn = fsstate->conn;
3007  char sql[64];
3008  int numrows;
3009  int i;
3010 
3011  snprintf(sql, sizeof(sql), "FETCH %d FROM c%u",
3012  fsstate->fetch_size, fsstate->cursor_number);
3013 
3014  res = pgfdw_exec_query(conn, sql);
3015  /* On error, report the original query, not the FETCH. */
3016  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3017  pgfdw_report_error(ERROR, res, conn, false, fsstate->query);
3018 
3019  /* Convert the data into HeapTuples */
3020  numrows = PQntuples(res);
3021  fsstate->tuples = (HeapTuple *) palloc0(numrows * sizeof(HeapTuple));
3022  fsstate->num_tuples = numrows;
3023  fsstate->next_tuple = 0;
3024 
3025  for (i = 0; i < numrows; i++)
3026  {
3027  Assert(IsA(node->ss.ps.plan, ForeignScan));
3028 
3029  fsstate->tuples[i] =
3031  fsstate->rel,
3032  fsstate->attinmeta,
3033  fsstate->retrieved_attrs,
3034  node,
3035  fsstate->temp_cxt);
3036  }
3037 
3038  /* Update fetch_ct_2 */
3039  if (fsstate->fetch_ct_2 < 2)
3040  fsstate->fetch_ct_2++;
3041 
3042  /* Must be EOF if we didn't get as many tuples as we asked for. */
3043  fsstate->eof_reached = (numrows < fsstate->fetch_size);
3044 
3045  PQclear(res);
3046  res = NULL;
3047  }
3048  PG_CATCH();
3049  {
3050  if (res)
3051  PQclear(res);
3052  PG_RE_THROW();
3053  }
3054  PG_END_TRY();
3055 
3056  MemoryContextSwitchTo(oldcontext);
3057 }
ScanState ss
Definition: execnodes.h:1714
#define IsA(nodeptr, _type_)
Definition: nodes.h:573
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:136
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:140
PlanState ps
Definition: execnodes.h:1290
#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:132
void * palloc0(Size size)
Definition: mcxt.c:878
MemoryContext temp_cxt
Definition: postgres_fdw.c:158
Plan * plan
Definition: execnodes.h:1049
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:148
#define PG_RE_THROW()
Definition: elog.h:314
int i
#define PG_TRY()
Definition: elog.h:284
MemoryContext batch_cxt
Definition: postgres_fdw.c:157
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 5058 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().

5059 {
5060  ListCell *lc_em;
5061 
5062  foreach(lc_em, ec->ec_members)
5063  {
5064  EquivalenceMember *em = lfirst(lc_em);
5065 
5066  if (bms_is_subset(em->em_relids, rel->relids))
5067  {
5068  /*
5069  * If there is more than one equivalence member whose Vars are
5070  * taken entirely from this relation, we'll be content to choose
5071  * any one of those.
5072  */
5073  return em->em_expr;
5074  }
5075  }
5076 
5077  /* We didn't find any suitable equivalence class expression */
5078  return NULL;
5079 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:307
Relids relids
Definition: relation.h:494
Relids em_relids
Definition: relation.h:786
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
List * ec_members
Definition: relation.h:737
static bool foreign_grouping_ok ( PlannerInfo root,
RelOptInfo grouped_rel 
)
static

Definition at line 4503 of file postgres_fdw.c.

References add_to_flat_tlist(), appendStringInfo(), apply_pathtarget_labeling_to_tlist(), copy_pathtarget(), StringInfoData::data, PathTarget::exprs, RelOptInfo::fdw_private, PgFdwRelationInfo::fdw_startup_cost, PgFdwRelationInfo::fdw_tuple_cost, PgFdwRelationInfo::fetch_size, 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, list_make1, PgFdwRelationInfo::local_conds, makeStringInfo(), NIL, PgFdwRelationInfo::outerrel, PlannerInfo::parse, pull_var_clause(), PgFdwRelationInfo::pushdown_safe, PVC_INCLUDE_AGGREGATES, PgFdwRelationInfo::rel_startup_cost, PgFdwRelationInfo::rel_total_cost, PgFdwRelationInfo::relation_name, PgFdwRelationInfo::remote_conds, PathTarget::sortgrouprefs, PlannerInfo::upper_targets, UPPERREL_GROUP_AGG, and PgFdwRelationInfo::use_remote_estimate.

Referenced by add_foreign_grouping_paths().

4504 {
4505  Query *query = root->parse;
4506  PathTarget *grouping_target;
4507  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
4508  PgFdwRelationInfo *ofpinfo;
4509  List *aggvars;
4510  ListCell *lc;
4511  int i;
4512  List *tlist = NIL;
4513 
4514  /* Grouping Sets are not pushable */
4515  if (query->groupingSets)
4516  return false;
4517 
4518  /* Get the fpinfo of the underlying scan relation. */
4519  ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
4520 
4521  /*
4522  * If underneath input relation has any local conditions, those conditions
4523  * are required to be applied before performing aggregation. Hence the
4524  * aggregate cannot be pushed down.
4525  */
4526  if (ofpinfo->local_conds)
4527  return false;
4528 
4529  /*
4530  * The targetlist expected from this node and the targetlist pushed down
4531  * to the foreign server may be different. The latter requires
4532  * sortgrouprefs to be set to push down GROUP BY clause, but should not
4533  * have those arising from ORDER BY clause. These sortgrouprefs may be
4534  * different from those in the plan's targetlist. Use a copy of path
4535  * target to record the new sortgrouprefs.
4536  */
4537  grouping_target = copy_pathtarget(root->upper_targets[UPPERREL_GROUP_AGG]);
4538 
4539  /*
4540  * Evaluate grouping targets and check whether they are safe to push down
4541  * to the foreign side. All GROUP BY expressions will be part of the
4542  * grouping target and thus there is no need to evaluate it separately.
4543  * While doing so, add required expressions into target list which can
4544  * then be used to pass to foreign server.
4545  */
4546  i = 0;
4547  foreach(lc, grouping_target->exprs)
4548  {
4549  Expr *expr = (Expr *) lfirst(lc);
4550  Index sgref = get_pathtarget_sortgroupref(grouping_target, i);
4551  ListCell *l;
4552 
4553  /* Check whether this expression is part of GROUP BY clause */
4554  if (sgref && get_sortgroupref_clause_noerr(sgref, query->groupClause))
4555  {
4556  /*
4557  * If any of the GROUP BY expression is not shippable we can not
4558  * push down aggregation to the foreign server.
4559  */
4560  if (!is_foreign_expr(root, grouped_rel, expr))
4561  return false;
4562 
4563  /* Pushable, add to tlist */
4564  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4565  }
4566  else
4567  {
4568  /* Check entire expression whether it is pushable or not */
4569  if (is_foreign_expr(root, grouped_rel, expr))
4570  {
4571  /* Pushable, add to tlist */
4572  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4573  }
4574  else
4575  {
4576  /*
4577  * If we have sortgroupref set, then it means that we have an
4578  * ORDER BY entry pointing to this expression. Since we are
4579  * not pushing ORDER BY with GROUP BY, clear it.
4580  */
4581  if (sgref)
4582  grouping_target->sortgrouprefs[i] = 0;
4583 
4584  /* Not matched exactly, pull the var with aggregates then */
4585  aggvars = pull_var_clause((Node *) expr,
4587 
4588  if (!is_foreign_expr(root, grouped_rel, (Expr *) aggvars))
4589  return false;
4590 
4591  /*
4592  * Add aggregates, if any, into the targetlist. Plain var
4593  * nodes should be either same as some GROUP BY expression or
4594  * part of some GROUP BY expression. In later case, the query
4595  * cannot refer plain var nodes without the surrounding
4596  * expression. In both the cases, they are already part of
4597  * the targetlist and thus no need to add them again. In fact
4598  * adding pulled plain var nodes in SELECT clause will cause
4599  * an error on the foreign server if they are not same as some
4600  * GROUP BY expression.
4601  */
4602  foreach(l, aggvars)
4603  {
4604  Expr *expr = (Expr *) lfirst(l);
4605 
4606  if (IsA(expr, Aggref))
4607  tlist = add_to_flat_tlist(tlist, list_make1(expr));
4608  }
4609  }
4610  }
4611 
4612  i++;
4613  }
4614 
4615  /*
4616  * Classify the pushable and non-pushable having clauses and save them in
4617  * remote_conds and local_conds of the grouped rel's fpinfo.
4618  */
4619  if (root->hasHavingQual && query->havingQual)
4620  {
4621  ListCell *lc;
4622 
4623  foreach(lc, (List *) query->havingQual)
4624  {
4625  Expr *expr = (Expr *) lfirst(lc);
4626 
4627  if (!is_foreign_expr(root, grouped_rel, expr))
4628  fpinfo->local_conds = lappend(fpinfo->local_conds, expr);
4629  else
4630  fpinfo->remote_conds = lappend(fpinfo->remote_conds, expr);
4631  }
4632  }
4633 
4634  /*
4635  * If there are any local conditions, pull Vars and aggregates from it and
4636  * check whether they are safe to pushdown or not.
4637  */
4638  if (fpinfo->local_conds)
4639  {
4640  ListCell *lc;
4641  List *aggvars = pull_var_clause((Node *) fpinfo->local_conds,
4643 
4644  foreach(lc, aggvars)
4645  {
4646  Expr *expr = (Expr *) lfirst(lc);
4647 
4648  /*
4649  * If aggregates within local conditions are not safe to push
4650  * down, then we cannot push down the query. Vars are already
4651  * part of GROUP BY clause which are checked above, so no need to
4652  * access them again here.
4653  */
4654  if (IsA(expr, Aggref))
4655  {
4656  if (!is_foreign_expr(root, grouped_rel, expr))
4657  return false;
4658 
4659  tlist = add_to_flat_tlist(tlist, aggvars);
4660  }
4661  }
4662  }
4663 
4664  /* Transfer any sortgroupref data to the replacement tlist */
4665  apply_pathtarget_labeling_to_tlist(tlist, grouping_target);
4666 
4667  /* Store generated targetlist */
4668  fpinfo->grouped_tlist = tlist;
4669 
4670  /* Safe to pushdown */
4671  fpinfo->pushdown_safe = true;
4672 
4673  /*
4674  * If user is willing to estimate cost for a scan using EXPLAIN, he
4675  * intends to estimate scans on that relation more accurately. Then, it
4676  * makes sense to estimate the cost of the grouping on that relation more
4677  * accurately using EXPLAIN.
4678  */
4679  fpinfo->use_remote_estimate = ofpinfo->use_remote_estimate;
4680 
4681  /* Copy startup and tuple cost as is from underneath input rel's fpinfo */
4682  fpinfo->fdw_startup_cost = ofpinfo->fdw_startup_cost;
4683  fpinfo->fdw_tuple_cost = ofpinfo->fdw_tuple_cost;
4684 
4685  /*
4686  * Set cached relation costs to some negative value, so that we can detect
4687  * when they are set to some sensible costs, during one (usually the
4688  * first) of the calls to estimate_path_cost_size().
4689  */
4690  fpinfo->rel_startup_cost = -1;
4691  fpinfo->rel_total_cost = -1;
4692 
4693  /* Set fetch size same as that of underneath input rel's fpinfo */
4694  fpinfo->fetch_size = ofpinfo->fetch_size;
4695 
4696  /*
4697  * Set the string describing this grouped relation to be used in EXPLAIN
4698  * output of corresponding ForeignScan.
4699  */
4700  fpinfo->relation_name = makeStringInfo();
4701  appendStringInfo(fpinfo->relation_name, "Aggregate on (%s)",
4702  ofpinfo->relation_name->data);
4703 
4704  return true;
4705 }
#define NIL
Definition: pg_list.h:69
PathTarget * copy_pathtarget(PathTarget *src)
Definition: tlist.c:629
#define IsA(nodeptr, _type_)
Definition: nodes.h:573
Query * parse
Definition: relation.h:154
StringInfo makeStringInfo(void)
Definition: stringinfo.c:29
List * groupingSets
Definition: parsenodes.h:139
Definition: nodes.h:522
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
RelOptInfo * outerrel
Definition: postgres_fdw.h:91
#define PVC_INCLUDE_AGGREGATES
Definition: var.h:20
#define list_make1(x1)
Definition: pg_list.h:133
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
Index * sortgrouprefs
Definition: relation.h:848
#define get_pathtarget_sortgroupref(target, colno)
Definition: relation.h:854
List * lappend(List *list, void *datum)
Definition: list.c:128
List * exprs
Definition: relation.h:847
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:88
void * fdw_private
Definition: relation.h:546
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition: tlist.c:135
#define lfirst(lc)
Definition: pg_list.h:106
List * groupClause
Definition: parsenodes.h:137
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:141
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 4050 of file postgres_fdw.c.

References appendStringInfo(), Assert, bms_add_members(), bms_is_subset(), bms_nonempty_difference(), bms_union(), StringInfoData::data, elog, ERROR, extract_actual_clauses(), extract_actual_join_clauses(), RelOptInfo::fdw_private, PgFdwRelationInfo::fdw_startup_cost, PgFdwRelationInfo::fdw_tuple_cost, PgFdwRelationInfo::fetch_size, get_jointype_name(), PgFdwRelationInfo::innerrel, is_foreign_expr(), IS_OUTER_JOIN, JOIN_FULL, JOIN_INNER, JOIN_LEFT, PlannerInfo::join_rel_list, JOIN_RIGHT, PgFdwRelationInfo::joinclauses, PgFdwRelationInfo::jointype, lappend(), lfirst, list_concat(), list_copy(), list_length(), PgFdwRelationInfo::local_conds, PgFdwRelationInfo::lower_subquery_rels, PgFdwRelationInfo::make_innerrel_subquery, PgFdwRelationInfo::make_outerrel_subquery, makeStringInfo(), 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().

4053 {
4054  PgFdwRelationInfo *fpinfo;
4055  PgFdwRelationInfo *fpinfo_o;
4056  PgFdwRelationInfo *fpinfo_i;
4057  ListCell *lc;
4058  List *joinclauses;
4059  List *otherclauses;
4060 
4061  /*
4062  * We support pushing down INNER, LEFT, RIGHT and FULL OUTER joins.
4063  * Constructing queries representing SEMI and ANTI joins is hard, hence
4064  * not considered right now.
4065  */
4066  if (jointype != JOIN_INNER && jointype != JOIN_LEFT &&
4067  jointype != JOIN_RIGHT && jointype != JOIN_FULL)
4068  return false;
4069 
4070  /*
4071  * If either of the joining relations is marked as unsafe to pushdown, the
4072  * join can not be pushed down.
4073  */
4074  fpinfo = (PgFdwRelationInfo *) joinrel->fdw_private;
4075  fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private;
4076  fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private;
4077  if (!fpinfo_o || !fpinfo_o->pushdown_safe ||
4078  !fpinfo_i || !fpinfo_i->pushdown_safe)
4079  return false;
4080 
4081  /*
4082  * If joining relations have local conditions, those conditions are
4083  * required to be applied before joining the relations. Hence the join can
4084  * not be pushed down.
4085  */
4086  if (fpinfo_o->local_conds || fpinfo_i->local_conds)
4087  return false;
4088 
4089  /* Separate restrict list into join quals and quals on join relation */
4090  if (IS_OUTER_JOIN(jointype))
4091  extract_actual_join_clauses(extra->restrictlist, &joinclauses, &otherclauses);
4092  else
4093  {
4094  /*
4095  * Unlike an outer join, for inner join, the join result contains only
4096  * the rows which satisfy join clauses, similar to the other clause.
4097  * Hence all clauses can be treated as other quals. This helps to push
4098  * a join down to the foreign server even if some of its join quals
4099  * are not safe to pushdown.
4100  */
4101  otherclauses = extract_actual_clauses(extra->restrictlist, false);
4102  joinclauses = NIL;
4103  }
4104 
4105  /* Join quals must be safe to push down. */
4106  foreach(lc, joinclauses)
4107  {
4108  Expr *expr = (Expr *) lfirst(lc);
4109 
4110  if (!is_foreign_expr(root, joinrel, expr))
4111  return false;
4112  }
4113 
4114  /*
4115  * deparseExplicitTargetList() isn't smart enough to handle anything other
4116  * than a Var. In particular, if there's some PlaceHolderVar that would
4117  * need to be evaluated within this join tree (because there's an upper
4118  * reference to a quantity that may go to NULL as a result of an outer
4119  * join), then we can't try to push the join down because we'll fail when
4120  * we get to deparseExplicitTargetList(). However, a PlaceHolderVar that
4121  * needs to be evaluated *at the top* of this join tree is OK, because we
4122  * can do that locally after fetching the results from the remote side.
4123  */
4124  foreach(lc, root->placeholder_list)
4125  {
4126  PlaceHolderInfo *phinfo = lfirst(lc);
4127  Relids relids = joinrel->relids;
4128 
4129  if (bms_is_subset(phinfo->ph_eval_at, relids) &&
4130  bms_nonempty_difference(relids, phinfo->ph_eval_at))
4131  return false;
4132  }
4133 
4134  /* Save the join clauses, for later use. */
4135  fpinfo->joinclauses = joinclauses;
4136 
4137  /*
4138  * Other clauses are applied after the join has been performed and thus
4139  * need not be all pushable. We will push those which can be pushed to
4140  * reduce the number of rows fetched from the foreign server. Rest of them
4141  * will be applied locally after fetching join result. Add them to fpinfo
4142  * so that other joins involving this joinrel will know that this joinrel
4143  * has local clauses.
4144  */
4145  foreach(lc, otherclauses)
4146  {
4147  Expr *expr = (Expr *) lfirst(lc);
4148 
4149  if (!is_foreign_expr(root, joinrel, expr))
4150  fpinfo->local_conds = lappend(fpinfo->local_conds, expr);
4151  else
4152  fpinfo->remote_conds = lappend(fpinfo->remote_conds, expr);
4153  }
4154 
4155  fpinfo->outerrel = outerrel;
4156  fpinfo->innerrel = innerrel;
4157  fpinfo->jointype = jointype;
4158 
4159  /*
4160  * By default, both the input relations are not required to be deparsed
4161  * as subqueries, but there might be some relations covered by the input
4162  * relations that are required to be deparsed as subqueries, so save the
4163  * relids of those relations for later use by the deparser.
4164  */
4165  fpinfo->make_outerrel_subquery = false;
4166  fpinfo->make_innerrel_subquery = false;
4167  Assert(bms_is_subset(fpinfo_o->lower_subquery_rels, outerrel->relids));
4168  Assert(bms_is_subset(fpinfo_i->lower_subquery_rels, innerrel->relids));
4170  fpinfo_i->lower_subquery_rels);
4171 
4172  /*
4173  * Pull the other remote conditions from the joining relations into join
4174  * clauses or other remote clauses (remote_conds) of this relation
4175  * wherever possible. This avoids building subqueries at every join step.
4176  *
4177  * For an inner join, clauses from both the relations are added to the
4178  * other remote clauses. For LEFT and RIGHT OUTER join, the clauses from
4179  * the outer side are added to remote_conds since those can be evaluated
4180  * after the join is evaluated. The clauses from inner side are added to
4181  * the joinclauses, since they need to be evaluated while constructing the
4182  * join.
4183  *
4184  * For a FULL OUTER JOIN, the other clauses from either relation can not
4185  * be added to the joinclauses or remote_conds, since each relation acts
4186  * as an outer relation for the other.
4187  *
4188  * The joining sides can not have local conditions, thus no need to test
4189  * shippability of the clauses being pulled up.
4190  */
4191  switch (jointype)
4192  {
4193  case JOIN_INNER:
4194  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4195  list_copy(fpinfo_i->remote_conds));
4196  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4197  list_copy(fpinfo_o->remote_conds));
4198  break;
4199 
4200  case JOIN_LEFT:
4201  fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
4202  list_copy(fpinfo_i->remote_conds));
4203  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4204  list_copy(fpinfo_o->remote_conds));
4205  break;
4206 
4207  case JOIN_RIGHT:
4208  fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
4209  list_copy(fpinfo_o->remote_conds));
4210  fpinfo->remote_conds = list_concat(fpinfo->remote_conds,
4211  list_copy(fpinfo_i->remote_conds));
4212  break;
4213 
4214  case JOIN_FULL:
4215 
4216  /*
4217  * In this case, if any of the input relations has conditions,
4218  * we need to deparse that relation as a subquery so that the
4219  * conditions can be evaluated before the join. Remember it in
4220  * the fpinfo of this relation so that the deparser can take
4221  * appropriate action. Also, save the relids of base relations
4222  * covered by that relation for later use by the deparser.
4223  */
4224  if (fpinfo_o->remote_conds)
4225  {
4226  fpinfo->make_outerrel_subquery = true;
4227  fpinfo->lower_subquery_rels =
4229  outerrel->relids);
4230  }
4231  if (fpinfo_i->remote_conds)
4232  {
4233  fpinfo->make_innerrel_subquery = true;
4234  fpinfo->lower_subquery_rels =
4236  innerrel->relids);
4237  }
4238  break;
4239 
4240  default:
4241  /* Should not happen, we have just check this above */
4242  elog(ERROR, "unsupported join type %d", jointype);
4243  }
4244 
4245  /*
4246  * For an inner join, all restrictions can be treated alike. Treating the
4247  * pushed down conditions as join conditions allows a top level full outer
4248  * join to be deparsed without requiring subqueries.
4249  */
4250  if (jointype == JOIN_INNER)
4251  {
4252  Assert(!fpinfo->joinclauses);
4253  fpinfo->joinclauses = fpinfo->remote_conds;
4254  fpinfo->remote_conds = NIL;
4255  }
4256 
4257  /* Mark that this join can be pushed down safely */
4258  fpinfo->pushdown_safe = true;
4259 
4260  /*
4261  * If user is willing to estimate cost for a scan of either of the joining
4262  * relations using EXPLAIN, he intends to estimate scans on that relation
4263  * more accurately. Then, it makes sense to estimate the cost of the join
4264  * with that relation more accurately using EXPLAIN.
4265  */
4266  fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate ||
4267  fpinfo_i->use_remote_estimate;
4268 
4269  /* Get user mapping */
4270  if (fpinfo->use_remote_estimate)
4271  {
4272  if (fpinfo_o->use_remote_estimate)
4273  fpinfo->user = fpinfo_o->user;
4274  else
4275  fpinfo->user = fpinfo_i->user;
4276  }
4277  else
4278  fpinfo->user = NULL;
4279 
4280  /* Get foreign server */
4281  fpinfo->server = fpinfo_o->server;
4282 
4283  /*
4284  * Since both the joining relations come from the same server, the server
4285  * level options should have same value for both the relations. Pick from
4286  * any side.
4287  */
4288  fpinfo->fdw_startup_cost = fpinfo_o->fdw_startup_cost;
4289  fpinfo->fdw_tuple_cost = fpinfo_o->fdw_tuple_cost;
4290 
4291  /*
4292  * Set cached relation costs to some negative value, so that we can detect
4293  * when they are set to some sensible costs, during one (usually the
4294  * first) of the calls to estimate_path_cost_size().
4295  */
4296  fpinfo->rel_startup_cost = -1;
4297  fpinfo->rel_total_cost = -1;
4298 
4299  /*
4300  * Set fetch size to maximum of the joining sides, since we are expecting
4301  * the rows returned by the join to be proportional to the relation sizes.
4302  */
4303  if (fpinfo_o->fetch_size > fpinfo_i->fetch_size)
4304  fpinfo->fetch_size = fpinfo_o->fetch_size;
4305  else
4306  fpinfo->fetch_size = fpinfo_i->fetch_size;
4307 
4308  /*
4309  * Set the string describing this join relation to be used in EXPLAIN
4310  * output of corresponding ForeignScan.
4311  */
4312  fpinfo->relation_name = makeStringInfo();
4313  appendStringInfo(fpinfo->relation_name, "(%s) %s JOIN (%s)",
4314  fpinfo_o->relation_name->data,
4315  get_jointype_name(fpinfo->jointype),
4316  fpinfo_i->relation_name->data);
4317 
4318  /*
4319  * Set the relation index. This is defined as the position of this
4320  * joinrel in the join_rel_list list plus the length of the rtable list.
4321  * Note that since this joinrel is at the end of the join_rel_list list
4322  * when we are called, we can get the position by list_length.
4323  */
4324  Assert(fpinfo->relation_index == 0); /* shouldn't be set yet */
4325  fpinfo->relation_index =
4327 
4328  return true;
4329 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:154
Relids ph_eval_at
Definition: relation.h:1996
void extract_actual_join_clauses(List *restrictinfo_list, List **joinquals, List **otherquals)
Definition: restrictinfo.c:381
StringInfo makeStringInfo(void)
Definition: stringinfo.c:29
ForeignServer * server
Definition: postgres_fdw.h:78
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:728
List * list_copy(const List *oldlist)
Definition: list.c:1160
Relids lower_subquery_rels
Definition: postgres_fdw.h:104
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:91
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
List * rtable
Definition: parsenodes.h:128
#define ERROR
Definition: elog.h:43
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:307
const char * get_jointype_name(JoinType jointype)
Definition: deparse.c:1314
Relids relids
Definition: relation.h:494
List * lappend(List *list, void *datum)
Definition: list.c:128
UserMapping * user
Definition: postgres_fdw.h:79
List * restrictlist
Definition: relation.h:2110
StringInfo relation_name
Definition: postgres_fdw.h:88
void * fdw_private
Definition: relation.h:546
#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:217
static int list_length(const List *l)
Definition: pg_list.h:89
List * extract_actual_clauses(List *restrictinfo_list, bool pseudoconstant)
Definition: restrictinfo.c:354
RelOptInfo * innerrel
Definition: postgres_fdw.h:92
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:725
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:464
static void get_remote_estimate ( const char *  sql,
PGconn conn,
double *  rows,
int *  width,
Cost startup_cost,
Cost total_cost 
)
static

Definition at line 2836 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().

2839 {
2840  PGresult *volatile res = NULL;
2841 
2842  /* PGresult must be released before leaving this function. */
2843  PG_TRY();
2844  {
2845  char *line;
2846  char *p;
2847  int n;
2848 
2849  /*
2850  * Execute EXPLAIN remotely.
2851  */
2852  res = pgfdw_exec_query(conn, sql);
2853  if (PQresultStatus(res) != PGRES_TUPLES_OK)
2854  pgfdw_report_error(ERROR, res, conn, false, sql);
2855 
2856  /*
2857  * Extract cost numbers for topmost plan node. Note we search for a
2858  * left paren from the end of the line to avoid being confused by
2859  * other uses of parentheses.
2860  */
2861  line = PQgetvalue(res, 0, 0);
2862  p = strrchr(line, '(');
2863  if (p == NULL)
2864  elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
2865  n = sscanf(p, "(cost=%lf..%lf rows=%lf width=%d)",
2866  startup_cost, total_cost, rows, width);
2867  if (n != 4)
2868  elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
2869 
2870  PQclear(res);
2871  res = NULL;
2872  }
2873  PG_CATCH();
2874  {
2875  if (res)
2876  PQclear(res);
2877  PG_RE_THROW();
2878  }
2879  PG_END_TRY();
2880 }
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 3326 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().

3327 {
3329  EState *estate = node->ss.ps.state;
3330  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
3331  TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
3332 
3333  Assert(resultRelInfo->ri_projectReturning);
3334 
3335  /* If we didn't get any tuples, must be end of data. */
3336  if (dmstate->next_tuple >= dmstate->num_tuples)
3337  return ExecClearTuple(slot);
3338 
3339  /* Increment the command es_processed count if necessary. */
3340  if (dmstate->set_processed)
3341  estate->es_processed += 1;
3342 
3343  /*
3344  * Store a RETURNING tuple. If has_returning is false, just emit a dummy
3345  * tuple. (has_returning is false when the local query is of the form
3346  * "UPDATE/DELETE .. RETURNING 1" for example.)
3347  */
3348  if (!dmstate->has_returning)
3349  ExecStoreAllNullTuple(slot);
3350  else
3351  {
3352  /*
3353  * On error, be sure to release the PGresult on the way out. Callers
3354  * do not have PG_TRY blocks to ensure this happens.
3355  */
3356  PG_TRY();
3357  {
3358  HeapTuple newtup;
3359 
3360  newtup = make_tuple_from_result_row(dmstate->result,
3361  dmstate->next_tuple,
3362  dmstate->rel,
3363  dmstate->attinmeta,
3364  dmstate->retrieved_attrs,
3365  NULL,
3366  dmstate->temp_cxt);
3367  ExecStoreTuple(newtup, slot, InvalidBuffer, false);
3368  }
3369  PG_CATCH();
3370  {
3371  if (dmstate->result)
3372  PQclear(dmstate->result);
3373  PG_RE_THROW();
3374  }
3375  PG_END_TRY();
3376  }
3377  dmstate->next_tuple++;
3378 
3379  /* Make slot available for evaluation of the local query RETURNING list. */
3380  resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple = slot;
3381 
3382  return slot;
3383 }
ScanState ss
Definition: execnodes.h:1714
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:196
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define InvalidBuffer
Definition: buf.h:25
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1293
EState * state
Definition: execnodes.h:1051
PlanState ps
Definition: execnodes.h:1290
MemoryContext temp_cxt
Definition: postgres_fdw.c:217
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 702 of file postgres_fdw.c.

References bms_overlap(), EquivalenceClass::ec_relids, eclass_useful_for_merging(), PlannerInfo::eq_classes, find_childrel_top_parent(), RelOptInfo::has_eclass_joins, RelOptInfo::joininfo, lappend(), RestrictInfo::left_ec, lfirst, list_append_unique_ptr(), RestrictInfo::mergeopfamilies, NIL, RelOptInfo::relids, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, RestrictInfo::right_ec, and update_mergeclause_eclasses().

Referenced by get_useful_pathkeys_for_relation().

703 {
704  List *useful_eclass_list = NIL;
705  ListCell *lc;
706  Relids relids;
707 
708  /*
709  * First, consider whether any active EC is potentially useful for a merge
710  * join against this relation.
711  */
712  if (rel->has_eclass_joins)
713  {
714  foreach(lc, root->eq_classes)
715  {
716  EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc);
717 
718  if (eclass_useful_for_merging(root, cur_ec, rel))
719  useful_eclass_list = lappend(useful_eclass_list, cur_ec);
720  }
721  }
722 
723  /*
724  * Next, consider whether there are any non-EC derivable join clauses that
725  * are merge-joinable. If the joininfo list is empty, we can exit
726  * quickly.
727  */
728  if (rel->joininfo == NIL)
729  return useful_eclass_list;
730 
731  /* If this is a child rel, we must use the topmost parent rel to search. */
733  relids = find_childrel_top_parent(root, rel)->relids;
734  else
735  relids = rel->relids;
736 
737  /* Check each join clause in turn. */
738  foreach(lc, rel->joininfo)
739  {
740  RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(lc);
741 
742  /* Consider only mergejoinable clauses */
743  if (restrictinfo->mergeopfamilies == NIL)
744  continue;
745 
746  /* Make sure we've got canonical ECs. */
747  update_mergeclause_eclasses(root, restrictinfo);
748 
749  /*
750  * restrictinfo->mergeopfamilies != NIL is sufficient to guarantee
751  * that left_ec and right_ec will be initialized, per comments in
752  * distribute_qual_to_rels.
753  *
754  * We want to identify which side of this merge-joinable clause
755  * contains columns from the relation produced by this RelOptInfo. We
756  * test for overlap, not containment, because there could be extra
757  * relations on either side. For example, suppose we've got something
758  * like ((A JOIN B ON A.x = B.x) JOIN C ON A.y = C.y) LEFT JOIN D ON
759  * A.y = D.y. The input rel might be the joinrel between A and B, and
760  * we'll consider the join clause A.y = D.y. relids contains a
761  * relation not involved in the join class (B) and the equivalence
762  * class for the left-hand side of the clause contains a relation not
763  * involved in the input rel (C). Despite the fact that we have only
764  * overlap and not containment in either direction, A.y is potentially
765  * useful as a sort column.
766  *
767  * Note that it's even possible that relids overlaps neither side of
768  * the join clause. For example, consider A LEFT JOIN B ON A.x = B.x
769  * AND A.x = 1. The clause A.x = 1 will appear in B's joininfo list,
770  * but overlaps neither side of B. In that case, we just skip this
771  * join clause, since it doesn't suggest a useful sort order for this
772  * relation.
773  */
774  if (bms_overlap(relids, restrictinfo->right_ec->ec_relids))
775  useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
776  restrictinfo->right_ec);
777  else if (bms_overlap(relids, restrictinfo->left_ec->ec_relids))
778  useful_eclass_list = list_append_unique_ptr(useful_eclass_list,
779  restrictinfo->left_ec);
780  }
781 
782  return useful_eclass_list;
783 }
bool has_eclass_joins
Definition: relation.h:556
RelOptInfo * find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel)
Definition: relnode.c:976
#define NIL
Definition: pg_list.h:69
RelOptKind reloptkind
Definition: relation.h:491
bool eclass_useful_for_merging(PlannerInfo *root, EquivalenceClass *eclass, RelOptInfo *rel)
Definition: equivclass.c:2393
EquivalenceClass * right_ec
Definition: relation.h:1728
List * mergeopfamilies
Definition: relation.h:1724
List * list_append_unique_ptr(List *list, void *datum)
Definition: list.c:975
List * joininfo
Definition: relation.h:554
Relids ec_relids
Definition: relation.h:740
Relids relids
Definition: relation.h:494
List * lappend(List *list, void *datum)
Definition: list.c:128
#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:442
EquivalenceClass * left_ec
Definition: relation.h:1727
Definition: pg_list.h:45
void update_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:968
static List * get_useful_pathkeys_for_relation ( PlannerInfo root,
RelOptInfo rel 
)
static

Definition at line 795 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().

796 {
797  List *useful_pathkeys_list = NIL;
798  List *useful_eclass_list;
800  EquivalenceClass *query_ec = NULL;
801  ListCell *lc;
802 
803  /*
804  * Pushing the query_pathkeys to the remote server is always worth
805  * considering, because it might let us avoid a local sort.
806  */
807  if (root->query_pathkeys)
808  {
809  bool query_pathkeys_ok = true;
810 
811  foreach(lc, root->query_pathkeys)
812  {
813  PathKey *pathkey = (PathKey *) lfirst(lc);
814  EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
815  Expr *em_expr;
816 
817  /*
818  * The planner and executor don't have any clever strategy for
819  * taking data sorted by a prefix of the query's pathkeys and
820  * getting it to be sorted by all of those pathkeys. We'll just
821  * end up resorting the entire data set. So, unless we can push
822  * down all of the query pathkeys, forget it.
823  *
824  * is_foreign_expr would detect volatile expressions as well, but
825  * checking ec_has_volatile here saves some cycles.
826  */
827  if (pathkey_ec->ec_has_volatile ||
828  !(em_expr = find_em_expr_for_rel(pathkey_ec, rel)) ||
829  !is_foreign_expr(root, rel, em_expr))
830  {
831  query_pathkeys_ok = false;
832  break;
833  }
834  }
835 
836  if (query_pathkeys_ok)
837  useful_pathkeys_list = list_make1(list_copy(root->query_pathkeys));
838  }
839 
840  /*
841  * Even if we're not using remote estimates, having the remote side do the
842  * sort generally won't be any worse than doing it locally, and it might
843  * be much better if the remote side can generate data in the right order
844  * without needing a sort at all. However, what we're going to do next is
845  * try to generate pathkeys that seem promising for possible merge joins,
846  * and that's more speculative. A wrong choice might hurt quite a bit, so
847  * bail out if we can't use remote estimates.
848  */
849  if (!fpinfo->use_remote_estimate)
850  return useful_pathkeys_list;
851 
852  /* Get the list of interesting EquivalenceClasses. */
853  useful_eclass_list = get_useful_ecs_for_relation(root, rel);
854 
855  /* Extract unique EC for query, if any, so we don't consider it again. */
856  if (list_length(root->query_pathkeys) == 1)
857  {
858  PathKey *query_pathkey = linitial(root->query_pathkeys);
859 
860  query_ec = query_pathkey->pk_eclass;
861  }
862 
863  /*
864  * As a heuristic, the only pathkeys we consider here are those of length
865  * one. It's surely possible to consider more, but since each one we
866  * choose to consider will generate a round-trip to the remote side, we
867  * need to be a bit cautious here. It would sure be nice to have a local
868  * cache of information about remote index definitions...
869  */
870  foreach(lc, useful_eclass_list)
871  {
872  EquivalenceClass *cur_ec = lfirst(lc);
873  Expr *em_expr;
874  PathKey *pathkey;
875 
876  /* If redundant with what we did above, skip it. */
877  if (cur_ec == query_ec)
878  continue;
879 
880  /* If no pushable expression for this rel, skip it. */
881  em_expr = find_em_expr_for_rel(cur_ec, rel);
882  if (em_expr == NULL || !is_foreign_expr(root, rel, em_expr))
883  continue;
884 
885  /* Looks like we can generate a pathkey, so let's do it. */
886  pathkey = make_canonical_pathkey(root, cur_ec,
887  linitial_oid(cur_ec->ec_opfamilies),
889  false);
890  useful_pathkeys_list = lappend(useful_pathkeys_list,
891  list_make1(pathkey));
892  }
893 
894  return useful_pathkeys_list;
895 }
#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:702
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:133
#define linitial(l)
Definition: pg_list.h:110
List * lappend(List *list, void *datum)
Definition: list.c:128
List * ec_opfamilies
Definition: relation.h:735
void * fdw_private
Definition: relation.h:546
#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:814
#define linitial_oid(l)
Definition: pg_list.h:112
static int list_length(const List *l)
Definition: pg_list.h:89
bool ec_has_volatile
Definition: relation.h:743
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 4818 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().

4825 {
4826  HeapTuple tuple;
4827  TupleDesc tupdesc;
4828  Datum *values;
4829  bool *nulls;
4830  ItemPointer ctid = NULL;
4831  Oid oid = InvalidOid;
4832  ConversionLocation errpos;
4833  ErrorContextCallback errcallback;
4834  MemoryContext oldcontext;
4835  ListCell *lc;
4836  int j;
4837 
4838  Assert(row < PQntuples(res));
4839 
4840  /*
4841  * Do the following work in a temp context that we reset after each tuple.
4842  * This cleans up not only the data we have direct access to, but any
4843  * cruft the I/O functions might leak.
4844  */
4845  oldcontext = MemoryContextSwitchTo(temp_context);
4846 
4847  if (rel)
4848  tupdesc = RelationGetDescr(rel);
4849  else
4850  {
4851  PgFdwScanState *fdw_sstate;
4852 
4853  Assert(fsstate);
4854  fdw_sstate = (PgFdwScanState *) fsstate->fdw_state;
4855  tupdesc = fdw_sstate->tupdesc;
4856  }
4857 
4858  values = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
4859  nulls = (bool *) palloc(tupdesc->natts * sizeof(bool));
4860  /* Initialize to nulls for any columns not present in result */
4861  memset(nulls, true, tupdesc->natts * sizeof(bool));
4862 
4863  /*
4864  * Set up and install callback to report where conversion error occurs.
4865  */
4866  errpos.rel = rel;
4867  errpos.cur_attno = 0;
4868  errpos.fsstate = fsstate;
4869  errcallback.callback = conversion_error_callback;
4870  errcallback.arg = (void *) &errpos;
4871  errcallback.previous = error_context_stack;
4872  error_context_stack = &errcallback;
4873 
4874  /*
4875  * i indexes columns in the relation, j indexes columns in the PGresult.
4876  */
4877  j = 0;
4878  foreach(lc, retrieved_attrs)
4879  {
4880  int i = lfirst_int(lc);
4881  char *valstr;
4882 
4883  /* fetch next column's textual value */
4884  if (PQgetisnull(res, row, j))
4885  valstr = NULL;
4886  else
4887  valstr = PQgetvalue(res, row, j);
4888 
4889  /*
4890  * convert value to internal representation
4891  *
4892  * Note: we ignore system columns other than ctid and oid in result
4893  */
4894  errpos.cur_attno = i;
4895  if (i > 0)
4896  {
4897  /* ordinary column */
4898  Assert(i <= tupdesc->natts);
4899  nulls[i - 1] = (valstr == NULL);
4900  /* Apply the input function even to nulls, to support domains */
4901  values[i - 1] = InputFunctionCall(&attinmeta->attinfuncs[i - 1],
4902  valstr,
4903  attinmeta->attioparams[i - 1],
4904  attinmeta->atttypmods[i - 1]);
4905  }
4906  else if (i == SelfItemPointerAttributeNumber)
4907  {
4908  /* ctid */
4909  if (valstr != NULL)
4910  {
4911  Datum datum;
4912 
4913  datum = DirectFunctionCall1(tidin, CStringGetDatum(valstr));
4914  ctid = (ItemPointer) DatumGetPointer(datum);
4915  }
4916  }
4917  else if (i == ObjectIdAttributeNumber)
4918  {
4919  /* oid */
4920  if (valstr != NULL)
4921  {
4922  Datum datum;
4923 
4924  datum = DirectFunctionCall1(oidin, CStringGetDatum(valstr));
4925  oid = DatumGetObjectId(datum);
4926  }
4927  }
4928  errpos.cur_attno = 0;
4929 
4930  j++;
4931  }
4932 
4933  /* Uninstall error context callback. */
4934  error_context_stack = errcallback.previous;
4935 
4936  /*
4937  * Check we got the expected number of columns. Note: j == 0 and
4938  * PQnfields == 1 is expected, since deparse emits a NULL if no columns.
4939  */
4940  if (j > 0 && j != PQnfields(res))
4941  elog(ERROR, "remote query result does not match the foreign table");
4942 
4943  /*
4944  * Build the result tuple in caller's memory context.
4945  */
4946  MemoryContextSwitchTo(oldcontext);
4947 
4948  tuple = heap_form_tuple(tupdesc, values, nulls);
4949 
4950  /*
4951  * If we have a CTID to return, install it in both t_self and t_ctid.
4952  * t_self is the normal place, but if the tuple is converted to a
4953  * composite Datum, t_self will be lost; setting t_ctid allows CTID to be
4954  * preserved during EvalPlanQual re-evaluations (see ROW_MARK_COPY code).
4955  */
4956  if (ctid)
4957  tuple->t_self = tuple->t_data->t_ctid = *ctid;
4958 
4959  /*
4960  * Stomp on the xmin, xmax, and cmin fields from the tuple created by
4961  * heap_form_tuple. heap_form_tuple actually creates the tuple with
4962  * DatumTupleFields, not HeapTupleFields, but the executor expects
4963  * HeapTupleFields and will happily extract system columns on that
4964  * assumption. If we don't do this then, for example, the tuple length
4965  * ends up in the xmin field, which isn't what we want.
4966  */
4970 
4971  /*
4972  * If we have an OID to return, install it.
4973  */
4974  if (OidIsValid(oid))
4975  HeapTupleSetOid(tuple, oid);
4976 
4977  /* Clean up */
4978  MemoryContextReset(temp_context);
4979 
4980  return tuple;
4981 }
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:576
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:258
#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:1932
#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:131
#define DatumGetPointer(X)
Definition: postgres.h:555
static Datum values[MAXATTR]
Definition: bootstrap.c:162
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:250
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
PG_FUNCTION_INFO_V1 ( postgres_fdw_handler  )
Datum postgres_fdw_handler ( PG_FUNCTION_ARGS  )

Definition at line 426 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.

427 {
428  FdwRoutine *routine = makeNode(FdwRoutine);
429 
430  /* Functions for scanning foreign tables */
438 
439  /* Functions for updating foreign tables */
452 
453  /* Function for EvalPlanQual rechecks */
455  /* Support functions for EXPLAIN */
459 
460  /* Support functions for ANALYZE */
462 
463  /* Support functions for IMPORT FOREIGN SCHEMA */
465 
466  /* Support functions for join push-down */
468 
469  /* Support functions for upper relation push-down */
471 
472  PG_RETURN_POINTER(routine);
473 }
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:313
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:483
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:902
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:570
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 3553 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().

3557 {
3558  PgFdwAnalyzeState astate;
3559  ForeignTable *table;
3560  ForeignServer *server;
3561  UserMapping *user;
3562  PGconn *conn;
3563  unsigned int cursor_number;
3564  StringInfoData sql;
3565  PGresult *volatile res = NULL;
3566 
3567  /* Initialize workspace state */
3568  astate.rel = relation;
3570 
3571  astate.rows = rows;
3572  astate.targrows = targrows;
3573  astate.numrows = 0;
3574  astate.samplerows = 0;
3575  astate.rowstoskip = -1; /* -1 means not set yet */
3576  reservoir_init_selection_state(&astate.rstate, targrows);
3577 
3578  /* Remember ANALYZE context, and create a per-tuple temp context */
3579  astate.anl_cxt = CurrentMemoryContext;
3581  "postgres_fdw temporary data",
3583 
3584  /*
3585  * Get the connection to use. We do the remote access as the table's
3586  * owner, even if the ANALYZE was started by some other user.
3587  */
3588  table = GetForeignTable(RelationGetRelid(relation));
3589  server = GetForeignServer(table->serverid);
3590  user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
3591  conn = GetConnection(user, false);
3592 
3593  /*
3594  * Construct cursor that retrieves whole rows from remote.
3595  */
3596  cursor_number = GetCursorNumber(conn);
3597  initStringInfo(&sql);
3598  appendStringInfo(&sql, "DECLARE c%u CURSOR FOR ", cursor_number);
3599  deparseAnalyzeSql(&sql, relation, &astate.retrieved_attrs);
3600 
3601  /* In what follows, do not risk leaking any PGresults. */
3602  PG_TRY();
3603  {
3604  res = pgfdw_exec_query(conn, sql.data);
3605  if (PQresultStatus(res) != PGRES_COMMAND_OK)
3606  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3607  PQclear(res);
3608  res = NULL;
3609 
3610  /* Retrieve and process rows a batch at a time. */
3611  for (;;)
3612  {
3613  char fetch_sql[64];
3614  int fetch_size;
3615  int numrows;
3616  int i;
3617  ListCell *lc;
3618 
3619  /* Allow users to cancel long query */
3621 
3622  /*
3623  * XXX possible future improvement: if rowstoskip is large, we
3624  * could issue a MOVE rather than physically fetching the rows,
3625  * then just adjust rowstoskip and samplerows appropriately.
3626  */
3627 
3628  /* The fetch size is arbitrary, but shouldn't be enormous. */
3629  fetch_size = 100;
3630  foreach(lc, server->options)
3631  {
3632  DefElem *def = (DefElem *) lfirst(lc);
3633 
3634  if (strcmp(def->defname, "fetch_size") == 0)
3635  {
3636  fetch_size = strtol(defGetString(def), NULL, 10);
3637  break;
3638  }
3639  }
3640  foreach(lc, table->options)
3641  {
3642  DefElem *def = (DefElem *) lfirst(lc);
3643 
3644  if (strcmp(def->defname, "fetch_size") == 0)
3645  {
3646  fetch_size = strtol(defGetString(def), NULL, 10);
3647  break;
3648  }
3649  }
3650 
3651  /* Fetch some rows */
3652  snprintf(fetch_sql, sizeof(fetch_sql), "FETCH %d FROM c%u",
3653  fetch_size, cursor_number);
3654 
3655  res = pgfdw_exec_query(conn, fetch_sql);
3656  /* On error, report the original query, not the FETCH. */
3657  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3658  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3659 
3660  /* Process whatever we got. */
3661  numrows = PQntuples(res);
3662  for (i = 0; i < numrows; i++)
3663  analyze_row_processor(res, i, &astate);
3664 
3665  PQclear(res);
3666  res = NULL;
3667 
3668  /* Must be EOF if we didn't get all the rows requested. */
3669  if (numrows < fetch_size)
3670  break;
3671  }
3672 
3673  /* Close the cursor, just to be tidy. */
3674  close_cursor(conn, cursor_number);
3675  }
3676  PG_CATCH();
3677  {
3678  if (res)
3679  PQclear(res);
3680  PG_RE_THROW();
3681  }
3682  PG_END_TRY();
3683 
3684  ReleaseConnection(conn);
3685 
3686  /* We assume that we have no dead tuple. */
3687  *totaldeadrows = 0.0;
3688 
3689  /* We've retrieved all living tuples from foreign server. */
3690  *totalrows = astate.samplerows;
3691 
3692  /*
3693  * Emit some interesting relation info
3694  */
3695  ereport(elevel,
3696  (errmsg("\"%s\": table contains %.0f rows, %d rows in sample",
3697  RelationGetRelationName(relation),
3698  astate.samplerows, astate.numrows)));
3699 
3700  return astate.numrows;
3701 }
HeapTuple * rows
Definition: postgres_fdw.c:230
#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:237
void deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
Definition: deparse.c:1843
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
AttInMetadata * attinmeta
Definition: postgres_fdw.c:226
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:241
#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:240
#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:708
#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 1510 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().

1513 {
1514  Var *var;
1515  const char *attrname;
1516  TargetEntry *tle;
1517 
1518  /*
1519  * In postgres_fdw, what we need is the ctid, same as for a regular table.
1520  */
1521 
1522  /* Make a Var representing the desired value */
1523  var = makeVar(parsetree->resultRelation,
1525  TIDOID,
1526  -1,
1527  InvalidOid,
1528  0);
1529 
1530  /* Wrap it in a resjunk TLE with the right name ... */
1531  attrname = "ctid";
1532 
1533  tle = makeTargetEntry((Expr *) var,
1534  list_length(parsetree->targetList) + 1,
1535  pstrdup(attrname),
1536  true);
1537 
1538  /* ... and add it to the query's targetlist */
1539  parsetree->targetList = lappend(parsetree->targetList, tle);
1540 }
char * pstrdup(const char *in)
Definition: mcxt.c:1077
int resultRelation
Definition: parsenodes.h:113
Definition: primnodes.h:163
List * targetList
Definition: parsenodes.h:131
#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 3475 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().

3478 {
3479  ForeignTable *table;
3480  UserMapping *user;
3481  PGconn *conn;
3482  StringInfoData sql;
3483  PGresult *volatile res = NULL;
3484 
3485  /* Return the row-analysis function pointer */
3487 
3488  /*
3489  * Now we have to get the number of pages. It's annoying that the ANALYZE
3490  * API requires us to return that now, because it forces some duplication
3491  * of effort between this routine and postgresAcquireSampleRowsFunc. But
3492  * it's probably not worth redefining that API at this point.
3493  */
3494 
3495  /*
3496  * Get the connection to use. We do the remote access as the table's
3497  * owner, even if the ANALYZE was started by some other user.
3498  */
3499  table = GetForeignTable(RelationGetRelid(relation));
3500  user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
3501  conn = GetConnection(user, false);
3502 
3503  /*
3504  * Construct command to get page count for relation.
3505  */
3506  initStringInfo(&sql);
3507  deparseAnalyzeSizeSql(&sql, relation);
3508 
3509  /* In what follows, do not risk leaking any PGresults. */
3510  PG_TRY();
3511  {
3512  res = pgfdw_exec_query(conn, sql.data);
3513  if (PQresultStatus(res) != PGRES_TUPLES_OK)
3514  pgfdw_report_error(ERROR, res, conn, false, sql.data);
3515 
3516  if (PQntuples(res) != 1 || PQnfields(res) != 1)
3517  elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
3518  *totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
3519 
3520  PQclear(res);
3521  res = NULL;
3522  }
3523  PG_CATCH();
3524  {
3525  if (res)
3526  PQclear(res);
3527  PG_RE_THROW();
3528  }
3529  PG_END_TRY();
3530 
3531  ReleaseConnection(conn);
3532 
3533  return true;
3534 }
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:1823
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 2263 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().

2264 {
2265  ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
2266  EState *estate = node->ss.ps.state;
2267  PgFdwDirectModifyState *dmstate;
2268  RangeTblEntry *rte;
2269  Oid userid;
2270  ForeignTable *table;
2271  UserMapping *user;
2272  int numParams;
2273 
2274  /*
2275  * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
2276  */
2277  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
2278  return;
2279 
2280  /*
2281  * We'll save private state in node->fdw_state.
2282  */
2283  dmstate = (PgFdwDirectModifyState *) palloc0(sizeof(PgFdwDirectModifyState));
2284  node->fdw_state = (void *) dmstate;
2285 
2286  /*
2287  * Identify which user to do the remote access as. This should match what
2288  * ExecCheckRTEPerms() does.
2289  */
2290  rte = rt_fetch(fsplan->scan.scanrelid, estate->es_range_table);
2291  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
2292 
2293  /* Get info about foreign table. */
2294  dmstate->rel = node->ss.ss_currentRelation;
2295  table = GetForeignTable(RelationGetRelid(dmstate->rel));
2296  user = GetUserMapping(userid, table->serverid);
2297 
2298  /*
2299  * Get connection to the foreign server. Connection manager will
2300  * establish new connection if necessary.
2301  */
2302  dmstate->conn = GetConnection(user, false);
2303 
2304  /* Initialize state variable */
2305  dmstate->num_tuples = -1; /* -1 means not set yet */
2306 
2307  /* Get private info created by planner functions. */
2308  dmstate->query = strVal(list_nth(fsplan->fdw_private,
2310  dmstate->has_returning = intVal(list_nth(fsplan->fdw_private,
2312  dmstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
2314  dmstate->set_processed = intVal(list_nth(fsplan->fdw_private,
2316 
2317  /* Create context for per-tuple temp workspace. */
2318  dmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
2319  "postgres_fdw temporary data",
2321 
2322  /* Prepare for input conversion of RETURNING results. */
2323  if (dmstate->has_returning)
2324  dmstate->attinmeta = TupleDescGetAttInMetadata(RelationGetDescr(dmstate->rel));
2325 
2326  /*
2327  * Prepare for processing of parameters used in remote query, if any.
2328  */
2329  numParams = list_length(fsplan->fdw_exprs);
2330  dmstate->numParams = numParams;
2331  if (numParams > 0)
2333  fsplan->fdw_exprs,
2334  numParams,
2335  &dmstate->param_flinfo,
2336  &dmstate->param_exprs,
2337  &dmstate->param_values);
2338 }
ScanState ss
Definition: execnodes.h:1714
Index scanrelid
Definition: plannodes.h:316
#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:577
List * fdw_private
Definition: plannodes.h:578
#define strVal(v)
Definition: value.h:54
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
Relation ss_currentRelation
Definition: execnodes.h:1291
EState * state
Definition: execnodes.h:1051
unsigned int Oid
Definition: postgres_ext.h:31
PlanState ps
Definition: execnodes.h:1290
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:1049
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 1665 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().

1670 {
1671  PgFdwModifyState *fmstate;
1672  EState *estate = mtstate->ps.state;
1673  CmdType operation = mtstate->operation;
1674  Relation rel = resultRelInfo->ri_RelationDesc;
1675  RangeTblEntry *rte;
1676  Oid userid;
1677  ForeignTable *table;
1678  UserMapping *user;
1679  AttrNumber n_params;
1680  Oid typefnoid;
1681  bool isvarlena;
1682  ListCell *lc;
1683 
1684  /*
1685  * Do nothing in EXPLAIN (no ANALYZE) case. resultRelInfo->ri_FdwState
1686  * stays NULL.
1687  */
1688  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
1689  return;
1690 
1691  /* Begin constructing PgFdwModifyState. */
1692  fmstate = (PgFdwModifyState *) palloc0(sizeof(PgFdwModifyState));
1693  fmstate->rel = rel;
1694 
1695  /*
1696  * Identify which user to do the remote access as. This should match what
1697  * ExecCheckRTEPerms() does.
1698  */
1699  rte = rt_fetch(resultRelInfo->ri_RangeTableIndex, estate->es_range_table);
1700  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1701 
1702  /* Get info about foreign table. */
1703  table = GetForeignTable(RelationGetRelid(rel));
1704  user = GetUserMapping(userid, table->serverid);
1705 
1706  /* Open connection; report that we'll create a prepared statement. */
1707  fmstate->conn = GetConnection(user, true);
1708  fmstate->p_name = NULL; /* prepared statement not made yet */
1709 
1710  /* Deconstruct fdw_private data. */
1711  fmstate->query = strVal(list_nth(fdw_private,
1713  fmstate->target_attrs = (List *) list_nth(fdw_private,
1715  fmstate->has_returning = intVal(list_nth(fdw_private,
1717  fmstate->retrieved_attrs = (List *) list_nth(fdw_private,
1719 
1720  /* Create context for per-tuple temp workspace. */
1721  fmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
1722  "postgres_fdw temporary data",
1724 
1725  /* Prepare for input conversion of RETURNING results. */
1726  if (fmstate->has_returning)
1728 
1729  /* Prepare for output conversion of parameters used in prepared stmt. */
1730  n_params = list_length(fmstate->target_attrs) + 1;
1731  fmstate->p_flinfo = (FmgrInfo *) palloc0(sizeof(FmgrInfo) * n_params);
1732  fmstate->p_nums = 0;
1733 
1734  if (operation == CMD_UPDATE || operation == CMD_DELETE)
1735  {
1736  /* Find the ctid resjunk column in the subplan's result */
1737  Plan *subplan = mtstate->mt_plans[subplan_index]->plan;
1738 
1740  "ctid");
1741  if (!AttributeNumberIsValid(fmstate->ctidAttno))
1742  elog(ERROR, "could not find junk ctid column");
1743 
1744  /* First transmittable parameter will be ctid */
1745  getTypeOutputInfo(TIDOID, &typefnoid, &isvarlena);
1746  fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
1747  fmstate->p_nums++;
1748  }
1749 
1750  if (operation == CMD_INSERT || operation == CMD_UPDATE)
1751  {
1752  /* Set up for remaining transmittable parameters */
1753  foreach(lc, fmstate->target_attrs)
1754  {
1755  int attnum = lfirst_int(lc);
1756  Form_pg_attribute attr = RelationGetDescr(rel)->attrs[attnum - 1];
1757 
1758  Assert(!attr->attisdropped);
1759 
1760  getTypeOutputInfo(attr->atttypid, &typefnoid, &isvarlena);
1761  fmgr_info(typefnoid, &fmstate->p_flinfo[fmstate->p_nums]);
1762  fmstate->p_nums++;
1763  }
1764  }
1765 
1766  Assert(fmstate->p_nums <= n_params);
1767 
1768  resultRelInfo->ri_FdwState = fmstate;
1769 }
Definition: fmgr.h:53
Relation ri_RelationDesc
Definition: execnodes.h:337
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2600
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:1153
EState * state
Definition: execnodes.h:1051
List * es_range_table
Definition: execnodes.h:374
unsigned int Oid
Definition: postgres_ext.h:31
List * retrieved_attrs
Definition: postgres_fdw.c:179
Index ri_RangeTableIndex
Definition: execnodes.h:336
#define TIDOID
Definition: pg_type.h:332
MemoryContext es_query_cxt
Definition: execnodes.h:399
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1152
#define lfirst_int(lc)
Definition: pg_list.h:107
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:159
void * list_nth(const List *list, int n)
Definition: list.c:410
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
AttrNumber ctidAttno
Definition: postgres_fdw.c:182
PlanState ** mt_plans
Definition: execnodes.h:1156
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
FmgrInfo * p_flinfo
Definition: postgres_fdw.c:184
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:1049
void * ri_FdwState
Definition: execnodes.h:346
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:97
MemoryContext temp_cxt
Definition: postgres_fdw.c:187
#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:132
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:169
#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:655
static void postgresBeginForeignScan ( ForeignScanState node,
int  eflags 
)
static

Definition at line 1285 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().

1286 {
1287  ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
1288  EState *estate = node->ss.ps.state;
1289  PgFdwScanState *fsstate;
1290  RangeTblEntry *rte;
1291  Oid userid;
1292  ForeignTable *table;
1293  UserMapping *user;
1294  int rtindex;
1295  int numParams;
1296 
1297  /*
1298  * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
1299  */
1300  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
1301  return;
1302 
1303  /*
1304  * We'll save private state in node->fdw_state.
1305  */
1306  fsstate = (PgFdwScanState *) palloc0(sizeof(PgFdwScanState));
1307  node->fdw_state = (void *) fsstate;
1308 
1309  /*
1310  * Identify which user to do the remote access as. This should match what
1311  * ExecCheckRTEPerms() does. In case of a join or aggregate, use the
1312  * lowest-numbered member RTE as a representative; we would get the same
1313  * result from any.
1314  */
1315  if (fsplan->scan.scanrelid > 0)
1316  rtindex = fsplan->scan.scanrelid;
1317  else
1318  rtindex = bms_next_member(fsplan->fs_relids, -1);
1319  rte = rt_fetch(rtindex, estate->es_range_table);
1320  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1321 
1322  /* Get info about foreign table. */
1323  table = GetForeignTable(rte->relid);
1324  user = GetUserMapping(userid, table->serverid);
1325 
1326  /*
1327  * Get connection to the foreign server. Connection manager will
1328  * establish new connection if necessary.
1329  */
1330  fsstate->conn = GetConnection(user, false);
1331 
1332  /* Assign a unique ID for my cursor */
1333  fsstate->cursor_number = GetCursorNumber(fsstate->conn);
1334  fsstate->cursor_exists = false;
1335 
1336  /* Get private info created by planner functions. */
1337  fsstate->query = strVal(list_nth(fsplan->fdw_private,
1339  fsstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
1341  fsstate->fetch_size = intVal(list_nth(fsplan->fdw_private,
1343 
1344  /* Create contexts for batches of tuples and per-tuple temp workspace. */
1345  fsstate->batch_cxt = AllocSetContextCreate(estate->es_query_cxt,
1346  "postgres_fdw tuple data",
1348  fsstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt,
1349  "postgres_fdw temporary data",
1351 
1352  /*
1353  * Get info we'll need for converting data fetched from the foreign server
1354  * into local representation and error reporting during that process.
1355  */
1356  if (fsplan->scan.scanrelid > 0)
1357  {
1358  fsstate->rel = node->ss.ss_currentRelation;
1359  fsstate->tupdesc = RelationGetDescr(fsstate->rel);
1360  }
1361  else
1362  {
1363  fsstate->rel = NULL;
1364  fsstate->tupdesc = node->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
1365  }
1366 
1367  fsstate->attinmeta = TupleDescGetAttInMetadata(fsstate->tupdesc);
1368 
1369  /*
1370  * Prepare for processing of parameters used in remote query, if any.
1371  */
1372  numParams = list_length(fsplan->fdw_exprs);
1373  fsstate->numParams = numParams;
1374  if (numParams > 0)
1376  fsplan->fdw_exprs,
1377  numParams,
1378  &fsstate->param_flinfo,
1379  &fsstate->param_exprs,
1380  &fsstate->param_values);
1381 }
ScanState ss
Definition: execnodes.h:1714
Index scanrelid
Definition: plannodes.h:316
#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:577
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:907
List * fdw_private
Definition: plannodes.h:578
#define strVal(v)
Definition: value.h:54
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:216
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1293
Relation ss_currentRelation
Definition: execnodes.h:1291
EState * state
Definition: execnodes.h:1051
unsigned int Oid
Definition: postgres_ext.h:31
PlanState ps
Definition: execnodes.h:1290
#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:1049
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:582
static void postgresEndDirectModify ( ForeignScanState node)
static

Definition at line 2389 of file postgres_fdw.c.

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

Referenced by postgres_fdw_handler().

2390 {
2392 
2393  /* if dmstate is NULL, we are in EXPLAIN; nothing to do */
2394  if (dmstate == NULL)
2395  return;
2396 
2397  /* Release PGresult */
2398  if (dmstate->result)
2399  PQclear(dmstate->result);
2400 
2401  /* Release remote connection */
2402  ReleaseConnection(dmstate->conn);
2403  dmstate->conn = NULL;
2404 
2405  /* MemoryContext will be deleted automatically. */
2406 }
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 1992 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().

1994 {
1995  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1996 
1997  /* If fmstate is NULL, we are in EXPLAIN; nothing to do */
1998  if (fmstate == NULL)
1999  return;
2000 
2001  /* If we created a prepared statement, destroy it */
2002  if (fmstate->p_name)
2003  {
2004  char sql[64];
2005  PGresult *res;
2006 
2007  snprintf(sql, sizeof(sql), "DEALLOCATE %s", fmstate->p_name);
2008 
2009  /*
2010  * We don't use a PG_TRY block here, so be careful not to throw error
2011  * without releasing the PGresult.
2012  */
2013  res = pgfdw_exec_query(fmstate->conn, sql);
2014  if (PQresultStatus(res) != PGRES_COMMAND_OK)
2015  pgfdw_report_error(ERROR, res, fmstate->conn, true, sql);
2016  PQclear(res);
2017  fmstate->p_name = NULL;
2018  }
2019 
2020  /* Release remote connection */
2021  ReleaseConnection(fmstate->conn);
2022  fmstate->conn = NULL;
2023 }
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:346
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 1486 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().

1487 {
1488  PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
1489 
1490  /* if fsstate is NULL, we are in EXPLAIN; nothing to do */
1491  if (fsstate == NULL)
1492  return;
1493 
1494  /* Close the cursor if open, to prevent accumulation of cursors */
1495  if (fsstate->cursor_exists)
1496  close_cursor(fsstate->conn, fsstate->cursor_number);
1497 
1498  /* Release remote connection */
1499  ReleaseConnection(fsstate->conn);
1500  fsstate->conn = NULL;
1501 
1502  /* MemoryContexts will be deleted automatically. */
1503 }
static void close_cursor(PGconn *conn, unsigned int cursor_number)
unsigned int cursor_number
Definition: postgres_fdw.c:140
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 1916 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().

1920 {
1921  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1922  Datum datum;
1923  bool isNull;
1924  const char **p_values;
1925  PGresult *res;
1926  int n_rows;
1927 
1928  /* Set up the prepared statement on the remote server, if we didn't yet */
1929  if (!fmstate->p_name)
1930  prepare_foreign_modify(fmstate);
1931 
1932  /* Get the ctid that was passed up as a resjunk column */
1933  datum = ExecGetJunkAttribute(planSlot,
1934  fmstate->ctidAttno,
1935  &isNull);
1936  /* shouldn't ever get a null result... */
1937  if (isNull)
1938  elog(ERROR, "ctid is NULL");
1939 
1940  /* Convert parameters needed by prepared statement to text form */
1941  p_values = convert_prep_stmt_params(fmstate,
1942  (ItemPointer) DatumGetPointer(datum),
1943  NULL);
1944 
1945  /*
1946  * Execute the prepared statement.
1947  */
1948  if (!PQsendQueryPrepared(fmstate->conn,
1949  fmstate->p_name,
1950  fmstate->p_nums,
1951  p_values,
1952  NULL,
1953  NULL,
1954  0))
1955  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1956 
1957  /*
1958  * Get the result, and check for success.
1959  *
1960  * We don't use a PG_TRY block here, so be careful not to throw error
1961  * without releasing the PGresult.
1962  */
1963  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1964  if (PQresultStatus(res) !=
1966  pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1967 
1968  /* Check number of rows affected, and fetch RETURNING tuple if any */
1969  if (fmstate->has_returning)
1970  {
1971  n_rows = PQntuples(res);
1972  if (n_rows > 0)
1973  store_returning_result(fmstate, slot, res);
1974  }
1975  else
1976  n_rows = atoi(PQcmdTuples(res));
1977 
1978  /* And clean up */
1979  PQclear(res);
1980 
1981  MemoryContextReset(fmstate->temp_cxt);
1982 
1983  /* Return NULL if nothing was deleted on the remote end */
1984  return (n_rows > 0) ? slot : NULL;
1985 }
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:182
uintptr_t Datum
Definition: postgres.h:372
void * ri_FdwState
Definition: execnodes.h:346
void PQclear(PGresult *res)
Definition: fe-exec.c:650
MemoryContext temp_cxt
Definition: postgres_fdw.c:187
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 1776 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().

1780 {
1781  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1782  const char **p_values;
1783  PGresult *res;
1784  int n_rows;
1785 
1786  /* Set up the prepared statement on the remote server, if we didn't yet */
1787  if (!fmstate->p_name)
1788  prepare_foreign_modify(fmstate);
1789 
1790  /* Convert parameters needed by prepared statement to text form */
1791  p_values = convert_prep_stmt_params(fmstate, NULL, slot);
1792 
1793  /*
1794  * Execute the prepared statement.
1795  */
1796  if (!PQsendQueryPrepared(fmstate->conn,
1797  fmstate->p_name,
1798  fmstate->p_nums,
1799  p_values,
1800  NULL,
1801  NULL,
1802  0))
1803  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1804 
1805  /*
1806  * Get the result, and check for success.
1807  *
1808  * We don't use a PG_TRY block here, so be careful not to throw error
1809  * without releasing the PGresult.
1810  */
1811  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1812  if (PQresultStatus(res) !=
1814  pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1815 
1816  /* Check number of rows affected, and fetch RETURNING tuple if any */
1817  if (fmstate->has_returning)
1818  {
1819  n_rows = PQntuples(res);
1820  if (n_rows > 0)
1821  store_returning_result(fmstate, slot, res);
1822  }
1823  else
1824  n_rows = atoi(PQcmdTuples(res));
1825 
1826  /* And clean up */
1827  PQclear(res);
1828 
1829  MemoryContextReset(fmstate->temp_cxt);
1830 
1831  /* Return NULL if nothing was inserted on the remote end */
1832  return (n_rows > 0) ? slot : NULL;
1833 }
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:346
void PQclear(PGresult *res)
Definition: fe-exec.c:650
MemoryContext temp_cxt
Definition: postgres_fdw.c:187
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 1840 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().

1844 {
1845  PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1846  Datum datum;
1847  bool isNull;
1848  const char **p_values;
1849  PGresult *res;
1850  int n_rows;
1851 
1852  /* Set up the prepared statement on the remote server, if we didn't yet */
1853  if (!fmstate->p_name)
1854  prepare_foreign_modify(fmstate);
1855 
1856  /* Get the ctid that was passed up as a resjunk column */
1857  datum = ExecGetJunkAttribute(planSlot,
1858  fmstate->ctidAttno,
1859  &isNull);
1860  /* shouldn't ever get a null result... */
1861  if (isNull)
1862  elog(ERROR, "ctid is NULL");
1863 
1864  /* Convert parameters needed by prepared statement to text form */
1865  p_values = convert_prep_stmt_params(fmstate,
1866  (ItemPointer) DatumGetPointer(datum),
1867  slot);
1868 
1869  /*
1870  * Execute the prepared statement.
1871  */
1872  if (!PQsendQueryPrepared(fmstate->conn,
1873  fmstate->p_name,
1874  fmstate->p_nums,
1875  p_values,
1876  NULL,
1877  NULL,
1878  0))
1879  pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1880 
1881  /*
1882  * Get the result, and check for success.
1883  *
1884  * We don't use a PG_TRY block here, so be careful not to throw error
1885  * without releasing the PGresult.
1886  */
1887  res = pgfdw_get_result(fmstate->conn, fmstate->query);
1888  if (PQresultStatus(res) !=
1890  pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1891 
1892  /* Check number of rows affected, and fetch RETURNING tuple if any */
1893  if (fmstate->has_returning)
1894  {
1895  n_rows = PQntuples(res);
1896  if (n_rows > 0)
1897  store_returning_result(fmstate, slot, res);
1898  }
1899  else
1900  n_rows = atoi(PQcmdTuples(res));
1901 
1902  /* And clean up */
1903  PQclear(res);
1904 
1905  MemoryContextReset(fmstate->temp_cxt);
1906 
1907  /* Return NULL if nothing was updated on the remote end */
1908  return (n_rows > 0) ? slot : NULL;
1909 }
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:182
uintptr_t Datum
Definition: postgres.h:372
void * ri_FdwState
Definition: execnodes.h:346
void PQclear(PGresult *res)
Definition: fe-exec.c:650
MemoryContext temp_cxt
Definition: postgres_fdw.c:187
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 void postgresExplainDirectModify ( ForeignScanState node,
ExplainState es 
)
static

Definition at line 2467 of file postgres_fdw.c.

References ExplainPropertyText(), FdwDirectModifyPrivateUpdateSql, list_nth(), PlanState::plan, ScanState::ps, ForeignScanState::ss, strVal, and ExplainState::verbose.

Referenced by postgres_fdw_handler().

2468 {
2469  List *fdw_private;
2470  char *sql;
2471 
2472  if (es->verbose)
2473  {
2474  fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private;
2475  sql = strVal(list_nth(fdw_private, FdwDirectModifyPrivateUpdateSql));
2476  ExplainPropertyText("Remote SQL", sql, es);
2477  }
2478 }
ScanState ss
Definition: execnodes.h:1714
#define strVal(v)
Definition: value.h:54
PlanState ps
Definition: execnodes.h:1290
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
void * list_nth(const List *list, int n)
Definition: list.c:410
bool verbose
Definition: explain.h:32
Plan * plan
Definition: execnodes.h:1049
Definition: pg_list.h:45
static void postgresExplainForeignModify ( ModifyTableState mtstate,
ResultRelInfo rinfo,
List fdw_private,
int  subplan_index,
ExplainState es 
)
static

Definition at line 2446 of file postgres_fdw.c.

References ExplainPropertyText(), FdwModifyPrivateUpdateSql, list_nth(), strVal, and ExplainState::verbose.

Referenced by postgres_fdw_handler().

2451 {
2452  if (es->verbose)
2453  {
2454  char *sql = strVal(list_nth(fdw_private,
2456 
2457  ExplainPropertyText("Remote SQL", sql, es);
2458  }
2459 }
#define strVal(v)
Definition: value.h:54
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
void * list_nth(const List *list, int n)
Definition: list.c:410
bool verbose
Definition: explain.h:32
static void postgresExplainForeignScan ( ForeignScanState node,
ExplainState es 
)
static

Definition at line 2413 of file postgres_fdw.c.

References ExplainPropertyText(), FdwScanPrivateRelations, FdwScanPrivateSelectSql, list_length(), list_nth(), PlanState::plan, ScanState::ps, ForeignScanState::ss, strVal, and ExplainState::verbose.

Referenced by postgres_fdw_handler().

2414 {
2415  List *fdw_private;
2416  char *sql;
2417  char *relations;
2418 
2419  fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private;
2420 
2421  /*
2422  * Add names of relation handled by the foreign scan when the scan is a
2423  * join
2424  */
2425  if (list_length(fdw_private) > FdwScanPrivateRelations)
2426  {
2427  relations = strVal(list_nth(fdw_private, FdwScanPrivateRelations));