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