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