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