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