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