aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/foreign/foreign.c164
1 files changed, 162 insertions, 2 deletions
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index 47c00af74f9..213217966cf 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -160,6 +160,54 @@ GetForeignServerByName(const char *srvname, bool missing_ok)
return GetForeignServer(serverid);
}
+/*
+ * GetUserMappingById - look up the user mapping by its OID.
+ */
+UserMapping *
+GetUserMappingById(Oid umid)
+{
+ Datum datum;
+ HeapTuple tp;
+ bool isnull;
+ UserMapping *um;
+
+ tp = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for user mapping %u", umid);
+
+ um = (UserMapping *) palloc(sizeof(UserMapping));
+ um->umid = umid;
+
+ /* Extract the umuser */
+ datum = SysCacheGetAttr(USERMAPPINGOID,
+ tp,
+ Anum_pg_user_mapping_umuser,
+ &isnull);
+ Assert(!isnull);
+ um->userid = DatumGetObjectId(datum);
+
+ /* Extract the umserver */
+ datum = SysCacheGetAttr(USERMAPPINGOID,
+ tp,
+ Anum_pg_user_mapping_umserver,
+ &isnull);
+ Assert(!isnull);
+ um->serverid = DatumGetObjectId(datum);
+
+ /* Extract the umoptions */
+ datum = SysCacheGetAttr(USERMAPPINGOID,
+ tp,
+ Anum_pg_user_mapping_umoptions,
+ &isnull);
+ if (isnull)
+ um->options = NIL;
+ else
+ um->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return um;
+}
/*
* GetUserMapping - look up the user mapping.
@@ -240,8 +288,8 @@ find_user_mapping(Oid userid, Oid serverid)
/* Not found for the specific user -- try PUBLIC */
tp = SearchSysCache2(USERMAPPINGUSERSERVER,
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(serverid));
+ ObjectIdGetDatum(InvalidOid),
+ ObjectIdGetDatum(serverid));
if (!HeapTupleIsValid(tp))
ereport(ERROR,
@@ -732,3 +780,115 @@ get_foreign_server_oid(const char *servername, bool missing_ok)
errmsg("server \"%s\" does not exist", servername)));
return oid;
}
+
+/*
+ * Get a copy of an existing local path for a given join relation.
+ *
+ * This function is usually helpful to obtain an alternate local path for EPQ
+ * checks.
+ *
+ * Right now, this function only supports unparameterized foreign joins, so we
+ * only search for unparameterized path in the given list of paths. Since we
+ * are searching for a path which can be used to construct an alternative local
+ * plan for a foreign join, we look for only MergeJoin, HashJoin or NestLoop
+ * paths.
+ *
+ * If the inner or outer subpath of the chosen path is a ForeignScan, we
+ * replace it with its outer subpath. For this reason, and also because the
+ * planner might free the original path later, the path returned by this
+ * function is a shallow copy of the original. There's no need to copy
+ * the substructure, so we don't.
+ *
+ * Since the plan created using this path will presumably only be used to
+ * execute EPQ checks, efficiency of the path is not a concern. But since the
+ * list passed is expected to be from RelOptInfo, it's anyway sorted by total
+ * cost and hence we are likely to choose the most efficient path, which is
+ * all for the best.
+ */
+extern Path *
+GetExistingLocalJoinPath(RelOptInfo *joinrel)
+{
+ ListCell *lc;
+
+ Assert(joinrel->reloptkind == RELOPT_JOINREL);
+
+ foreach(lc, joinrel->pathlist)
+ {
+ Path *path = (Path *) lfirst(lc);
+ JoinPath *joinpath = NULL;
+
+ /* Skip parameterised or non-parallel-safe paths. */
+ if (path->param_info != NULL || !path->parallel_safe)
+ continue;
+
+ switch (path->pathtype)
+ {
+ case T_HashJoin:
+ {
+ HashPath *hash_path = makeNode(HashPath);
+
+ memcpy(hash_path, path, sizeof(HashPath));
+ joinpath = (JoinPath *) hash_path;
+ }
+ break;
+
+ case T_NestLoop:
+ {
+ NestPath *nest_path = makeNode(NestPath);
+
+ memcpy(nest_path, path, sizeof(NestPath));
+ joinpath = (JoinPath *) nest_path;
+ }
+ break;
+
+ case T_MergeJoin:
+ {
+ MergePath *merge_path = makeNode(MergePath);
+
+ memcpy(merge_path, path, sizeof(MergePath));
+ joinpath = (JoinPath *) merge_path;
+ }
+ break;
+
+ default:
+
+ /*
+ * Just skip anything else. We don't know if corresponding
+ * plan would build the output row from whole-row references
+ * of base relations and execute the EPQ checks.
+ */
+ break;
+ }
+
+ /* This path isn't good for us, check next. */
+ if (!joinpath)
+ continue;
+
+ /*
+ * If either inner or outer path is a ForeignPath corresponding to a
+ * pushed down join, replace it with the fdw_outerpath, so that we
+ * maintain path for EPQ checks built entirely of local join
+ * strategies.
+ */
+ if (IsA(joinpath->outerjoinpath, ForeignPath))
+ {
+ ForeignPath *foreign_path;
+
+ foreign_path = (ForeignPath *) joinpath->outerjoinpath;
+ if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL)
+ joinpath->outerjoinpath = foreign_path->fdw_outerpath;
+ }
+
+ if (IsA(joinpath->innerjoinpath, ForeignPath))
+ {
+ ForeignPath *foreign_path;
+
+ foreign_path = (ForeignPath *) joinpath->innerjoinpath;
+ if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL)
+ joinpath->innerjoinpath = foreign_path->fdw_outerpath;
+ }
+
+ return (Path *) joinpath;
+ }
+ return NULL;
+}