1/*-------------------------------------------------------------------------
4 * support for foreign-data wrappers, servers and user mappings.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 * src/backend/foreign/foreign.c
11 *-------------------------------------------------------------------------
35 * GetForeignDataWrapper - look up the foreign-data wrapper by OID.
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.
63 elog(
ERROR,
"cache lookup failed for foreign-data wrapper %u", fdwid);
71 fdw->
owner = fdwform->fdwowner;
76 /* Extract the fdwoptions */
79 Anum_pg_foreign_data_wrapper_fdwoptions,
93 * GetForeignDataWrapperByName - look up the foreign-data wrapper
109 * GetForeignServer - look up the foreign server definition.
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.
137 elog(
ERROR,
"cache lookup failed for foreign server %u", serverid);
146 server->
owner = serverform->srvowner;
147 server->
fdwid = serverform->srvfdw;
149 /* Extract server type */
152 Anum_pg_foreign_server_srvtype,
156 /* Extract server version */
159 Anum_pg_foreign_server_srvversion,
163 /* Extract the srvoptions */
166 Anum_pg_foreign_server_srvoptions,
180 * GetForeignServerByName - look up the foreign server definition by name.
195 * GetUserMapping - look up the user mapping.
197 * If no mapping is found for the supplied user, we also look for
198 * PUBLIC mappings (userid == InvalidOid).
214 /* Not found for the specific user -- try PUBLIC */
225 (
errcode(ERRCODE_UNDEFINED_OBJECT),
226 errmsg(
"user mapping not found for user \"%s\", server \"%s\"",
235 /* Extract the umoptions */
238 Anum_pg_user_mapping_umoptions,
252 * GetForeignTable - look up the foreign table definition by relation oid.
265 elog(
ERROR,
"cache lookup failed for foreign table %u", relid);
272 /* Extract the ftoptions */
275 Anum_pg_foreign_table_ftoptions,
289 * GetForeignColumnOptions - Get attfdwoptions of given relation/attnum
290 * as list of DefElem.
304 elog(
ERROR,
"cache lookup failed for attribute %d of relation %u",
308 Anum_pg_attribute_attfdwoptions,
322 * GetFdwRoutine - call the specified foreign-data wrapper handler routine
323 * to get its FdwRoutine struct.
331 /* Check if the access to foreign tables is restricted */
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")));
344 elog(
ERROR,
"foreign-data wrapper handler function %u did not return an FdwRoutine struct",
352 * GetForeignServerIdByRelId - look up the foreign server
353 * for the given foreign table, and return its OID.
364 elog(
ERROR,
"cache lookup failed for foreign table %u", relid);
366 serverid = tableform->ftserver;
374 * GetFdwRoutineByServerId - look up the handler of the foreign-data wrapper
375 * for the given foreign server, and retrieve its FdwRoutine struct.
386 /* Get foreign-data wrapper OID for the server. */
389 elog(
ERROR,
"cache lookup failed for foreign server %u", serverid);
391 fdwid = serverform->srvfdw;
394 /* Get handler function OID for the FDW. */
397 elog(
ERROR,
"cache lookup failed for foreign-data wrapper %u", fdwid);
399 fdwhandler = fdwform->fdwhandler;
401 /* Complain if FDW has been set to NO HANDLER. */
404 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
405 errmsg(
"foreign-data wrapper \"%s\" has no handler",
410 /* And finally, call the handler function. */
416 * GetFdwRoutineByRelId - look up the handler of the foreign-data wrapper
417 * for the given foreign table, and retrieve its FdwRoutine struct.
424 /* Get server OID for the foreign table. */
427 /* Now retrieve server's FdwRoutine struct. */
432 * GetFdwRoutineForRelation - look up the handler of the foreign-data wrapper
433 * for the given foreign table, and retrieve its FdwRoutine struct.
435 * This function is preferred over GetFdwRoutineByRelId because it caches
436 * the data in the relcache entry, saving a number of catalog lookups.
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.
450 /* Get the info by consulting the catalogs and the FDW code */
453 /* Save the data for later reuse in CacheMemoryContext */
456 memcpy(cfdwroutine, fdwroutine,
sizeof(
FdwRoutine));
459 /* Give back the locally palloc'd copy regardless of makecopy */
463 /* We have valid cached data --- does the caller want a copy? */
471 /* Only a short-lived reference is needed, so just hand back cached copy */
477 * IsImportableForeignTable - filter table names for IMPORT FOREIGN SCHEMA
479 * Returns true if given table name should be imported according to the
480 * statement's import filter options.
488 switch (
stmt->list_type)
494 foreach(lc,
stmt->table_list)
498 if (strcmp(tablename, rv->
relname) == 0)
504 foreach(lc,
stmt->table_list)
508 if (strcmp(tablename, rv->
relname) == 0)
513 return false;
/* shouldn't get here */
518 * pg_options_to_table - Convert options array to name/value table
520 * This is useful to provide details for information_schema and pg_dump.
533 /* prepare the result set */
563 * Describes the valid options for postgresql FDW, server, and user mapping.
572 * Copied from fe-connect.c PQconninfoOptions.
574 * The list is small - don't bother with bsearch if it stays so.
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},
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
614 * Validate the generic option given to SERVER or USER MAPPING.
615 * Raise an ERROR if the option or its value is considered invalid.
617 * Valid server options are all libpq conninfo options except
618 * user and password -- these may only appear in USER MAPPING options.
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.
633 foreach(cell, options_list)
640 const char *closest_match;
642 bool has_valid_options =
false;
645 * Unknown option specified, complain about it. Provide a hint
646 * with a valid option that looks similar, if there is one.
653 has_valid_options =
true;
660 (
errcode(ERRCODE_SYNTAX_ERROR),
662 has_valid_options ? closest_match ?
663 errhint(
"Perhaps you meant the option \"%s\".",
665 errhint(
"There are no valid options in this context.")));
676 * get_foreign_data_wrapper_oid - given a FDW name, look up the OID
678 * If missing_ok is false, throw an error if name not found. If true, just
687 Anum_pg_foreign_data_wrapper_oid,
691 (
errcode(ERRCODE_UNDEFINED_OBJECT),
692 errmsg(
"foreign-data wrapper \"%s\" does not exist",
699 * get_foreign_server_oid - given a server name, look up the OID
701 * If missing_ok is false, throw an error if name not found. If true, just
713 (
errcode(ERRCODE_UNDEFINED_OBJECT),
714 errmsg(
"server \"%s\" does not exist", servername)));
719 * Get a copy of an existing local path for a given join relation.
721 * This function is usually helpful to obtain an alternate local path for EPQ
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
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.
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.
753 /* Skip parameterized paths. */
754 if (path->param_info != NULL)
763 memcpy(hash_path, path,
sizeof(
HashPath));
772 memcpy(nest_path, path,
sizeof(
NestPath));
781 memcpy(merge_path, path,
sizeof(
MergePath));
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.
796 /* This path isn't good for us, check next. */
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
815 if (joinpath->path.pathtype == T_MergeJoin)
820 * If the new outer path is already well enough ordered
821 * for the mergejoin, we can skip doing an explicit sort.
841 if (joinpath->path.pathtype == T_MergeJoin)
846 * If the new inner path is already well enough ordered
847 * for the mergejoin, we can skip doing an explicit sort.
857 return (
Path *) joinpath;
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define TextDatumGetCString(d)
#define OidIsValid(objectId)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define OidFunctionCall0(functionId)
#define PG_GETARG_DATUM(n)
#define PG_RETURN_BOOL(x)
static bool is_conninfo_option(const char *option, Oid context)
static const struct ConnectionOption libpq_conninfo_options[]
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
ForeignTable * GetForeignTable(Oid relid)
Path * GetExistingLocalJoinPath(RelOptInfo *joinrel)
UserMapping * GetUserMapping(Oid userid, Oid serverid)
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
ForeignServer * GetForeignServer(Oid serverid)
Datum pg_options_to_table(PG_FUNCTION_ARGS)
ForeignDataWrapper * GetForeignDataWrapperExtended(Oid fdwid, bits16 flags)
Datum postgresql_fdw_validator(PG_FUNCTION_ARGS)
FdwRoutine * GetFdwRoutineByRelId(Oid relid)
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Oid GetForeignServerIdByRelId(Oid relid)
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
ForeignServer * GetForeignServerExtended(Oid serverid, bits16 flags)
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
#define MappingUserName(userid)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
#define MAT_SRF_USE_EXPECTED_DESC
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
struct parser_state match_state[5]
if(TABLE==NULL||TABLE_index==NULL)
void * MemoryContextAlloc(MemoryContext context, Size size)
char * pstrdup(const char *in)
MemoryContext CacheMemoryContext
#define IsA(nodeptr, _type_)
@ FDW_IMPORT_SCHEMA_LIMIT_TO
@ FDW_IMPORT_SCHEMA_EXCEPT
bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common)
bool pathkeys_contained_in(List *keys1, List *keys2)
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
FormData_pg_user_mapping * Form_pg_user_mapping
int restrict_nonsystem_relation_kind
static Datum Int16GetDatum(int16 X)
static Datum ObjectIdGetDatum(Oid X)
static Pointer DatumGetPointer(Datum X)
static Datum CStringGetDatum(const char *X)
#define RelationGetRelid(relation)
List * untransformRelOptions(Datum options)
struct FdwRoutine * rd_fdwroutine
Tuplestorestate * setResult
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
#define GetSysCacheOid1(cacheId, oidcol, key1)
#define RESTRICT_RELKIND_FOREIGN_TABLE
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
const char * getClosestMatch(ClosestMatchState *state)
void initClosestMatch(ClosestMatchState *state, const char *source, int max_d)
void updateClosestMatch(ClosestMatchState *state, const char *candidate)