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