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