PostgreSQL Source Code  git master
foreign.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * foreign.c
4  * support for foreign-data wrappers, servers and user mappings.
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/foreign/foreign.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "access/htup_details.h"
16 #include "access/reloptions.h"
21 #include "foreign/fdwapi.h"
22 #include "foreign/foreign.h"
23 #include "lib/stringinfo.h"
24 #include "miscadmin.h"
25 #include "utils/builtins.h"
26 #include "utils/memutils.h"
27 #include "utils/rel.h"
28 #include "utils/syscache.h"
29 
30 
31 /*
32  * GetForeignDataWrapper - look up the foreign-data wrapper by OID.
33  */
36 {
37  return GetForeignDataWrapperExtended(fdwid, 0);
38 }
39 
40 
41 /*
42  * GetForeignDataWrapperExtended - look up the foreign-data wrapper
43  * by OID. If flags uses FDW_MISSING_OK, return NULL if the object cannot
44  * be found instead of raising an error.
45  */
48 {
50  ForeignDataWrapper *fdw;
51  Datum datum;
52  HeapTuple tp;
53  bool isnull;
54 
56 
57  if (!HeapTupleIsValid(tp))
58  {
59  if ((flags & FDW_MISSING_OK) == 0)
60  elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
61  return NULL;
62  }
63 
65 
66  fdw = (ForeignDataWrapper *) palloc(sizeof(ForeignDataWrapper));
67  fdw->fdwid = fdwid;
68  fdw->owner = fdwform->fdwowner;
69  fdw->fdwname = pstrdup(NameStr(fdwform->fdwname));
70  fdw->fdwhandler = fdwform->fdwhandler;
71  fdw->fdwvalidator = fdwform->fdwvalidator;
72 
73  /* Extract the fdwoptions */
75  tp,
76  Anum_pg_foreign_data_wrapper_fdwoptions,
77  &isnull);
78  if (isnull)
79  fdw->options = NIL;
80  else
81  fdw->options = untransformRelOptions(datum);
82 
83  ReleaseSysCache(tp);
84 
85  return fdw;
86 }
87 
88 
89 /*
90  * GetForeignDataWrapperByName - look up the foreign-data wrapper
91  * definition by name.
92  */
94 GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
95 {
96  Oid fdwId = get_foreign_data_wrapper_oid(fdwname, missing_ok);
97 
98  if (!OidIsValid(fdwId))
99  return NULL;
100 
101  return GetForeignDataWrapper(fdwId);
102 }
103 
104 
105 /*
106  * GetForeignServer - look up the foreign server definition.
107  */
110 {
111  return GetForeignServerExtended(serverid, 0);
112 }
113 
114 
115 /*
116  * GetForeignServerExtended - look up the foreign server definition. If
117  * flags uses FSV_MISSING_OK, return NULL if the object cannot be found
118  * instead of raising an error.
119  */
122 {
123  Form_pg_foreign_server serverform;
124  ForeignServer *server;
125  HeapTuple tp;
126  Datum datum;
127  bool isnull;
128 
130 
131  if (!HeapTupleIsValid(tp))
132  {
133  if ((flags & FSV_MISSING_OK) == 0)
134  elog(ERROR, "cache lookup failed for foreign server %u", serverid);
135  return NULL;
136  }
137 
138  serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
139 
140  server = (ForeignServer *) palloc(sizeof(ForeignServer));
141  server->serverid = serverid;
142  server->servername = pstrdup(NameStr(serverform->srvname));
143  server->owner = serverform->srvowner;
144  server->fdwid = serverform->srvfdw;
145 
146  /* Extract server type */
148  tp,
149  Anum_pg_foreign_server_srvtype,
150  &isnull);
151  server->servertype = isnull ? NULL : TextDatumGetCString(datum);
152 
153  /* Extract server version */
155  tp,
156  Anum_pg_foreign_server_srvversion,
157  &isnull);
158  server->serverversion = isnull ? NULL : TextDatumGetCString(datum);
159 
160  /* Extract the srvoptions */
162  tp,
163  Anum_pg_foreign_server_srvoptions,
164  &isnull);
165  if (isnull)
166  server->options = NIL;
167  else
168  server->options = untransformRelOptions(datum);
169 
170  ReleaseSysCache(tp);
171 
172  return server;
173 }
174 
175 
176 /*
177  * GetForeignServerByName - look up the foreign server definition by name.
178  */
180 GetForeignServerByName(const char *srvname, bool missing_ok)
181 {
182  Oid serverid = get_foreign_server_oid(srvname, missing_ok);
183 
184  if (!OidIsValid(serverid))
185  return NULL;
186 
187  return GetForeignServer(serverid);
188 }
189 
190 
191 /*
192  * GetUserMapping - look up the user mapping.
193  *
194  * If no mapping is found for the supplied user, we also look for
195  * PUBLIC mappings (userid == InvalidOid).
196  */
197 UserMapping *
198 GetUserMapping(Oid userid, Oid serverid)
199 {
200  Datum datum;
201  HeapTuple tp;
202  bool isnull;
203  UserMapping *um;
204 
205  tp = SearchSysCache2(USERMAPPINGUSERSERVER,
206  ObjectIdGetDatum(userid),
207  ObjectIdGetDatum(serverid));
208 
209  if (!HeapTupleIsValid(tp))
210  {
211  /* Not found for the specific user -- try PUBLIC */
212  tp = SearchSysCache2(USERMAPPINGUSERSERVER,
214  ObjectIdGetDatum(serverid));
215  }
216 
217  if (!HeapTupleIsValid(tp))
218  ereport(ERROR,
219  (errcode(ERRCODE_UNDEFINED_OBJECT),
220  errmsg("user mapping not found for \"%s\"",
221  MappingUserName(userid))));
222 
223  um = (UserMapping *) palloc(sizeof(UserMapping));
224  um->umid = ((Form_pg_user_mapping) GETSTRUCT(tp))->oid;
225  um->userid = userid;
226  um->serverid = serverid;
227 
228  /* Extract the umoptions */
229  datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
230  tp,
231  Anum_pg_user_mapping_umoptions,
232  &isnull);
233  if (isnull)
234  um->options = NIL;
235  else
236  um->options = untransformRelOptions(datum);
237 
238  ReleaseSysCache(tp);
239 
240  return um;
241 }
242 
243 
244 /*
245  * GetForeignTable - look up the foreign table definition by relation oid.
246  */
247 ForeignTable *
249 {
250  Form_pg_foreign_table tableform;
251  ForeignTable *ft;
252  HeapTuple tp;
253  Datum datum;
254  bool isnull;
255 
257  if (!HeapTupleIsValid(tp))
258  elog(ERROR, "cache lookup failed for foreign table %u", relid);
259  tableform = (Form_pg_foreign_table) GETSTRUCT(tp);
260 
261  ft = (ForeignTable *) palloc(sizeof(ForeignTable));
262  ft->relid = relid;
263  ft->serverid = tableform->ftserver;
264 
265  /* Extract the ftoptions */
267  tp,
268  Anum_pg_foreign_table_ftoptions,
269  &isnull);
270  if (isnull)
271  ft->options = NIL;
272  else
273  ft->options = untransformRelOptions(datum);
274 
275  ReleaseSysCache(tp);
276 
277  return ft;
278 }
279 
280 
281 /*
282  * GetForeignColumnOptions - Get attfdwoptions of given relation/attnum
283  * as list of DefElem.
284  */
285 List *
287 {
288  List *options;
289  HeapTuple tp;
290  Datum datum;
291  bool isnull;
292 
293  tp = SearchSysCache2(ATTNUM,
294  ObjectIdGetDatum(relid),
295  Int16GetDatum(attnum));
296  if (!HeapTupleIsValid(tp))
297  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
298  attnum, relid);
299  datum = SysCacheGetAttr(ATTNUM,
300  tp,
301  Anum_pg_attribute_attfdwoptions,
302  &isnull);
303  if (isnull)
304  options = NIL;
305  else
306  options = untransformRelOptions(datum);
307 
308  ReleaseSysCache(tp);
309 
310  return options;
311 }
312 
313 
314 /*
315  * GetFdwRoutine - call the specified foreign-data wrapper handler routine
316  * to get its FdwRoutine struct.
317  */
318 FdwRoutine *
319 GetFdwRoutine(Oid fdwhandler)
320 {
321  Datum datum;
322  FdwRoutine *routine;
323 
324  datum = OidFunctionCall0(fdwhandler);
325  routine = (FdwRoutine *) DatumGetPointer(datum);
326 
327  if (routine == NULL || !IsA(routine, FdwRoutine))
328  elog(ERROR, "foreign-data wrapper handler function %u did not return an FdwRoutine struct",
329  fdwhandler);
330 
331  return routine;
332 }
333 
334 
335 /*
336  * GetForeignServerIdByRelId - look up the foreign server
337  * for the given foreign table, and return its OID.
338  */
339 Oid
341 {
342  HeapTuple tp;
343  Form_pg_foreign_table tableform;
344  Oid serverid;
345 
347  if (!HeapTupleIsValid(tp))
348  elog(ERROR, "cache lookup failed for foreign table %u", relid);
349  tableform = (Form_pg_foreign_table) GETSTRUCT(tp);
350  serverid = tableform->ftserver;
351  ReleaseSysCache(tp);
352 
353  return serverid;
354 }
355 
356 
357 /*
358  * GetFdwRoutineByServerId - look up the handler of the foreign-data wrapper
359  * for the given foreign server, and retrieve its FdwRoutine struct.
360  */
361 FdwRoutine *
363 {
364  HeapTuple tp;
366  Form_pg_foreign_server serverform;
367  Oid fdwid;
368  Oid fdwhandler;
369 
370  /* Get foreign-data wrapper OID for the server. */
372  if (!HeapTupleIsValid(tp))
373  elog(ERROR, "cache lookup failed for foreign server %u", serverid);
374  serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
375  fdwid = serverform->srvfdw;
376  ReleaseSysCache(tp);
377 
378  /* Get handler function OID for the FDW. */
380  if (!HeapTupleIsValid(tp))
381  elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
382  fdwform = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
383  fdwhandler = fdwform->fdwhandler;
384 
385  /* Complain if FDW has been set to NO HANDLER. */
386  if (!OidIsValid(fdwhandler))
387  ereport(ERROR,
388  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
389  errmsg("foreign-data wrapper \"%s\" has no handler",
390  NameStr(fdwform->fdwname))));
391 
392  ReleaseSysCache(tp);
393 
394  /* And finally, call the handler function. */
395  return GetFdwRoutine(fdwhandler);
396 }
397 
398 
399 /*
400  * GetFdwRoutineByRelId - look up the handler of the foreign-data wrapper
401  * for the given foreign table, and retrieve its FdwRoutine struct.
402  */
403 FdwRoutine *
405 {
406  Oid serverid;
407 
408  /* Get server OID for the foreign table. */
409  serverid = GetForeignServerIdByRelId(relid);
410 
411  /* Now retrieve server's FdwRoutine struct. */
412  return GetFdwRoutineByServerId(serverid);
413 }
414 
415 /*
416  * GetFdwRoutineForRelation - look up the handler of the foreign-data wrapper
417  * for the given foreign table, and retrieve its FdwRoutine struct.
418  *
419  * This function is preferred over GetFdwRoutineByRelId because it caches
420  * the data in the relcache entry, saving a number of catalog lookups.
421  *
422  * If makecopy is true then the returned data is freshly palloc'd in the
423  * caller's memory context. Otherwise, it's a pointer to the relcache data,
424  * which will be lost in any relcache reset --- so don't rely on it long.
425  */
426 FdwRoutine *
427 GetFdwRoutineForRelation(Relation relation, bool makecopy)
428 {
429  FdwRoutine *fdwroutine;
430  FdwRoutine *cfdwroutine;
431 
432  if (relation->rd_fdwroutine == NULL)
433  {
434  /* Get the info by consulting the catalogs and the FDW code */
435  fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(relation));
436 
437  /* Save the data for later reuse in CacheMemoryContext */
439  sizeof(FdwRoutine));
440  memcpy(cfdwroutine, fdwroutine, sizeof(FdwRoutine));
441  relation->rd_fdwroutine = cfdwroutine;
442 
443  /* Give back the locally palloc'd copy regardless of makecopy */
444  return fdwroutine;
445  }
446 
447  /* We have valid cached data --- does the caller want a copy? */
448  if (makecopy)
449  {
450  fdwroutine = (FdwRoutine *) palloc(sizeof(FdwRoutine));
451  memcpy(fdwroutine, relation->rd_fdwroutine, sizeof(FdwRoutine));
452  return fdwroutine;
453  }
454 
455  /* Only a short-lived reference is needed, so just hand back cached copy */
456  return relation->rd_fdwroutine;
457 }
458 
459 
460 /*
461  * IsImportableForeignTable - filter table names for IMPORT FOREIGN SCHEMA
462  *
463  * Returns true if given table name should be imported according to the
464  * statement's import filter options.
465  */
466 bool
467 IsImportableForeignTable(const char *tablename,
469 {
470  ListCell *lc;
471 
472  switch (stmt->list_type)
473  {
475  return true;
476 
478  foreach(lc, stmt->table_list)
479  {
480  RangeVar *rv = (RangeVar *) lfirst(lc);
481 
482  if (strcmp(tablename, rv->relname) == 0)
483  return true;
484  }
485  return false;
486 
488  foreach(lc, stmt->table_list)
489  {
490  RangeVar *rv = (RangeVar *) lfirst(lc);
491 
492  if (strcmp(tablename, rv->relname) == 0)
493  return false;
494  }
495  return true;
496  }
497  return false; /* shouldn't get here */
498 }
499 
500 
501 /*
502  * deflist_to_tuplestore - Helper function to convert DefElem list to
503  * tuplestore usable in SRF.
504  */
505 static void
507 {
508  ListCell *cell;
509  TupleDesc tupdesc;
510  Tuplestorestate *tupstore;
511  Datum values[2];
512  bool nulls[2];
513  MemoryContext per_query_ctx;
514  MemoryContext oldcontext;
515 
516  /* check to see if caller supports us returning a tuplestore */
517  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
518  ereport(ERROR,
519  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
520  errmsg("set-valued function called in context that cannot accept a set")));
521  if (!(rsinfo->allowedModes & SFRM_Materialize) ||
522  rsinfo->expectedDesc == NULL)
523  ereport(ERROR,
524  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
525  errmsg("materialize mode required, but it is not allowed in this context")));
526 
527  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
528  oldcontext = MemoryContextSwitchTo(per_query_ctx);
529 
530  /*
531  * Now prepare the result set.
532  */
533  tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
534  tupstore = tuplestore_begin_heap(true, false, work_mem);
535  rsinfo->returnMode = SFRM_Materialize;
536  rsinfo->setResult = tupstore;
537  rsinfo->setDesc = tupdesc;
538 
539  foreach(cell, options)
540  {
541  DefElem *def = lfirst(cell);
542 
543  values[0] = CStringGetTextDatum(def->defname);
544  nulls[0] = false;
545  if (def->arg)
546  {
547  values[1] = CStringGetTextDatum(((Value *) (def->arg))->val.str);
548  nulls[1] = false;
549  }
550  else
551  {
552  values[1] = (Datum) 0;
553  nulls[1] = true;
554  }
555  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
556  }
557 
558  /* clean up and return the tuplestore */
559  tuplestore_donestoring(tupstore);
560 
561  MemoryContextSwitchTo(oldcontext);
562 }
563 
564 
565 /*
566  * Convert options array to name/value table. Useful for information
567  * schema and pg_dump.
568  */
569 Datum
571 {
572  Datum array = PG_GETARG_DATUM(0);
573 
574  deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo,
575  untransformRelOptions(array));
576 
577  return (Datum) 0;
578 }
579 
580 
581 /*
582  * Describes the valid options for postgresql FDW, server, and user mapping.
583  */
585 {
586  const char *optname;
587  Oid optcontext; /* Oid of catalog in which option may appear */
588 };
589 
590 /*
591  * Copied from fe-connect.c PQconninfoOptions.
592  *
593  * The list is small - don't bother with bsearch if it stays so.
594  */
595 static const struct ConnectionOption libpq_conninfo_options[] = {
596  {"authtype", ForeignServerRelationId},
597  {"service", ForeignServerRelationId},
598  {"user", UserMappingRelationId},
599  {"password", UserMappingRelationId},
600  {"connect_timeout", ForeignServerRelationId},
601  {"dbname", ForeignServerRelationId},
602  {"host", ForeignServerRelationId},
603  {"hostaddr", ForeignServerRelationId},
604  {"port", ForeignServerRelationId},
605  {"tty", ForeignServerRelationId},
606  {"options", ForeignServerRelationId},
607  {"requiressl", ForeignServerRelationId},
608  {"sslmode", ForeignServerRelationId},
609  {"gsslib", ForeignServerRelationId},
610  {NULL, InvalidOid}
611 };
612 
613 
614 /*
615  * Check if the provided option is one of libpq conninfo options.
616  * context is the Oid of the catalog the option came from, or 0 if we
617  * don't care.
618  */
619 static bool
620 is_conninfo_option(const char *option, Oid context)
621 {
622  const struct ConnectionOption *opt;
623 
624  for (opt = libpq_conninfo_options; opt->optname; opt++)
625  if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
626  return true;
627  return false;
628 }
629 
630 
631 /*
632  * Validate the generic option given to SERVER or USER MAPPING.
633  * Raise an ERROR if the option or its value is considered invalid.
634  *
635  * Valid server options are all libpq conninfo options except
636  * user and password -- these may only appear in USER MAPPING options.
637  *
638  * Caution: this function is deprecated, and is now meant only for testing
639  * purposes, because the list of options it knows about doesn't necessarily
640  * square with those known to whichever libpq instance you might be using.
641  * Inquire of libpq itself, instead.
642  */
643 Datum
645 {
646  List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
647  Oid catalog = PG_GETARG_OID(1);
648 
649  ListCell *cell;
650 
651  foreach(cell, options_list)
652  {
653  DefElem *def = lfirst(cell);
654 
655  if (!is_conninfo_option(def->defname, catalog))
656  {
657  const struct ConnectionOption *opt;
659 
660  /*
661  * Unknown option specified, complain about it. Provide a hint
662  * with list of valid options for the object.
663  */
664  initStringInfo(&buf);
665  for (opt = libpq_conninfo_options; opt->optname; opt++)
666  if (catalog == opt->optcontext)
667  appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
668  opt->optname);
669 
670  ereport(ERROR,
671  (errcode(ERRCODE_SYNTAX_ERROR),
672  errmsg("invalid option \"%s\"", def->defname),
673  errhint("Valid options in this context are: %s",
674  buf.data)));
675 
676  PG_RETURN_BOOL(false);
677  }
678  }
679 
680  PG_RETURN_BOOL(true);
681 }
682 
683 
684 /*
685  * get_foreign_data_wrapper_oid - given a FDW name, look up the OID
686  *
687  * If missing_ok is false, throw an error if name not found. If true, just
688  * return InvalidOid.
689  */
690 Oid
691 get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
692 {
693  Oid oid;
694 
696  Anum_pg_foreign_data_wrapper_oid,
697  CStringGetDatum(fdwname));
698  if (!OidIsValid(oid) && !missing_ok)
699  ereport(ERROR,
700  (errcode(ERRCODE_UNDEFINED_OBJECT),
701  errmsg("foreign-data wrapper \"%s\" does not exist",
702  fdwname)));
703  return oid;
704 }
705 
706 
707 /*
708  * get_foreign_server_oid - given a server name, look up the OID
709  *
710  * If missing_ok is false, throw an error if name not found. If true, just
711  * return InvalidOid.
712  */
713 Oid
714 get_foreign_server_oid(const char *servername, bool missing_ok)
715 {
716  Oid oid;
717 
718  oid = GetSysCacheOid1(FOREIGNSERVERNAME, Anum_pg_foreign_server_oid,
719  CStringGetDatum(servername));
720  if (!OidIsValid(oid) && !missing_ok)
721  ereport(ERROR,
722  (errcode(ERRCODE_UNDEFINED_OBJECT),
723  errmsg("server \"%s\" does not exist", servername)));
724  return oid;
725 }
726 
727 /*
728  * Get a copy of an existing local path for a given join relation.
729  *
730  * This function is usually helpful to obtain an alternate local path for EPQ
731  * checks.
732  *
733  * Right now, this function only supports unparameterized foreign joins, so we
734  * only search for unparameterized path in the given list of paths. Since we
735  * are searching for a path which can be used to construct an alternative local
736  * plan for a foreign join, we look for only MergeJoin, HashJoin or NestLoop
737  * paths.
738  *
739  * If the inner or outer subpath of the chosen path is a ForeignScan, we
740  * replace it with its outer subpath. For this reason, and also because the
741  * planner might free the original path later, the path returned by this
742  * function is a shallow copy of the original. There's no need to copy
743  * the substructure, so we don't.
744  *
745  * Since the plan created using this path will presumably only be used to
746  * execute EPQ checks, efficiency of the path is not a concern. But since the
747  * path list in RelOptInfo is anyway sorted by total cost we are likely to
748  * choose the most efficient path, which is all for the best.
749  */
750 Path *
752 {
753  ListCell *lc;
754 
755  Assert(IS_JOIN_REL(joinrel));
756 
757  foreach(lc, joinrel->pathlist)
758  {
759  Path *path = (Path *) lfirst(lc);
760  JoinPath *joinpath = NULL;
761 
762  /* Skip parameterized paths. */
763  if (path->param_info != NULL)
764  continue;
765 
766  switch (path->pathtype)
767  {
768  case T_HashJoin:
769  {
770  HashPath *hash_path = makeNode(HashPath);
771 
772  memcpy(hash_path, path, sizeof(HashPath));
773  joinpath = (JoinPath *) hash_path;
774  }
775  break;
776 
777  case T_NestLoop:
778  {
779  NestPath *nest_path = makeNode(NestPath);
780 
781  memcpy(nest_path, path, sizeof(NestPath));
782  joinpath = (JoinPath *) nest_path;
783  }
784  break;
785 
786  case T_MergeJoin:
787  {
788  MergePath *merge_path = makeNode(MergePath);
789 
790  memcpy(merge_path, path, sizeof(MergePath));
791  joinpath = (JoinPath *) merge_path;
792  }
793  break;
794 
795  default:
796 
797  /*
798  * Just skip anything else. We don't know if corresponding
799  * plan would build the output row from whole-row references
800  * of base relations and execute the EPQ checks.
801  */
802  break;
803  }
804 
805  /* This path isn't good for us, check next. */
806  if (!joinpath)
807  continue;
808 
809  /*
810  * If either inner or outer path is a ForeignPath corresponding to a
811  * pushed down join, replace it with the fdw_outerpath, so that we
812  * maintain path for EPQ checks built entirely of local join
813  * strategies.
814  */
815  if (IsA(joinpath->outerjoinpath, ForeignPath))
816  {
817  ForeignPath *foreign_path;
818 
819  foreign_path = (ForeignPath *) joinpath->outerjoinpath;
820  if (IS_JOIN_REL(foreign_path->path.parent))
821  joinpath->outerjoinpath = foreign_path->fdw_outerpath;
822  }
823 
824  if (IsA(joinpath->innerjoinpath, ForeignPath))
825  {
826  ForeignPath *foreign_path;
827 
828  foreign_path = (ForeignPath *) joinpath->innerjoinpath;
829  if (IS_JOIN_REL(foreign_path->path.parent))
830  joinpath->innerjoinpath = foreign_path->fdw_outerpath;
831  }
832 
833  return (Path *) joinpath;
834  }
835  return NULL;
836 }
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:190
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
Oid umid
Definition: foreign.h:47
#define NIL
Definition: pg_list.h:65
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
int errhint(const char *fmt,...)
Definition: elog.c:974
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Path * fdw_outerpath
Definition: pathnodes.h:1319
static bool is_conninfo_option(const char *option, Oid context)
Definition: foreign.c:620
uint16 bits16
Definition: c.h:366
char * fdwname
Definition: foreign.h:28
Path * innerjoinpath
Definition: pathnodes.h:1496
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:192
#define FDW_MISSING_OK
Definition: foreign.h:64
char * pstrdup(const char *in)
Definition: mcxt.c:1186
char * serverversion
Definition: foreign.h:41
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:451
ParamPathInfo * param_info
Definition: pathnodes.h:1117
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:362
#define IS_JOIN_REL(rel)
Definition: pathnodes.h:619
int errcode(int sqlerrcode)
Definition: elog.c:570
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:248
unsigned int Oid
Definition: postgres_ext.h:31
Datum pg_options_to_table(PG_FUNCTION_ARGS)
Definition: foreign.c:570
#define OidIsValid(objectId)
Definition: c.h:638
Oid userid
Definition: foreign.h:48
static void deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
Definition: foreign.c:506
NodeTag pathtype
Definition: pathnodes.h:1112
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition: foreign.c:319
char * relname
Definition: primnodes.h:68
char * servertype
Definition: foreign.h:40
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
Definition: foreign.c:691
TupleDesc expectedDesc
Definition: execnodes.h:302
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:35
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:286
FormData_pg_foreign_table * Form_pg_foreign_table
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
RelOptInfo * parent
Definition: pathnodes.h:1114
FormData_pg_user_mapping * Form_pg_user_mapping
Oid relid
Definition: foreign.h:55
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition: foreign.c:467
static char * buf
Definition: pg_test_fsync.c:68
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
#define CStringGetDatum(X)
Definition: postgres.h:578
List * options
Definition: foreign.h:50
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition: foreign.c:180
#define ereport(elevel, rest)
Definition: elog.h:141
#define FSV_MISSING_OK
Definition: foreign.h:61
Node * arg
Definition: parsenodes.h:731
static char ** options
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
List * options
Definition: foreign.h:31
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
Path * outerjoinpath
Definition: pathnodes.h:1495
#define TextDatumGetCString(d)
Definition: builtins.h:84
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:109
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
uintptr_t Datum
Definition: postgres.h:367
FdwRoutine * GetFdwRoutineByRelId(Oid relid)
Definition: foreign.c:404
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1385
int work_mem
Definition: globals.c:121
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1030
FormData_pg_foreign_server * Form_pg_foreign_server
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
int allowedModes
Definition: execnodes.h:303
ForeignServer * GetForeignServerExtended(Oid serverid, bits16 flags)
Definition: foreign.c:121
SetFunctionReturnMode returnMode
Definition: execnodes.h:305
#define OidFunctionCall0(functionId)
Definition: fmgr.h:653
#define makeNode(_type_)
Definition: nodes.h:573
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
Definition: value.h:42
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition: foreign.c:94
Path * GetExistingLocalJoinPath(RelOptInfo *joinrel)
Definition: foreign.c:751
const char * optname
Definition: foreign.c:586
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:340
Oid serverid
Definition: foreign.h:56
Oid serverid
Definition: foreign.h:49
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1135
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
Tuplestorestate * setResult
Definition: execnodes.h:308
#define DatumGetPointer(X)
Definition: postgres.h:549
static Datum values[MAXATTR]
Definition: bootstrap.c:167
List * options
Definition: foreign.h:57
ExprContext * econtext
Definition: execnodes.h:301
TupleDesc setDesc
Definition: execnodes.h:309
ForeignDataWrapper * GetForeignDataWrapperExtended(Oid fdwid, bits16 flags)
Definition: foreign.c:47
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:784
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
char * servername
Definition: foreign.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define NameStr(name)
Definition: c.h:609
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Definition: foreign.c:198
#define CStringGetTextDatum(s)
Definition: builtins.h:83
Datum postgresql_fdw_validator(PG_FUNCTION_ARGS)
Definition: foreign.c:644
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
char * defname
Definition: parsenodes.h:730
List * pathlist
Definition: pathnodes.h:655
Definition: pg_list.h:50
List * options
Definition: foreign.h:42
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:419
Oid serverid
Definition: foreign.h:36
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:714
static const struct ConnectionOption libpq_conninfo_options[]
Definition: foreign.c:595
#define MappingUserName(userid)
Definition: foreign.h:20
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
ImportForeignSchemaType list_type
Definition: parsenodes.h:2353