aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/relnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r--src/backend/optimizer/util/relnode.c82
1 files changed, 39 insertions, 43 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index a0a284b901b..806600ed107 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -15,8 +15,6 @@
#include "postgres.h"
#include "miscadmin.h"
-#include "catalog/pg_class.h"
-#include "foreign/foreign.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
@@ -107,7 +105,6 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->consider_startup = (root->tuple_fraction > 0);
rel->consider_param_startup = false; /* might get changed later */
rel->consider_parallel = false; /* might get changed later */
- rel->rel_parallel_workers = -1; /* set up in GetRelationInfo */
rel->reltarget = create_empty_pathtarget();
rel->pathlist = NIL;
rel->ppilist = NIL;
@@ -129,8 +126,10 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->allvisfrac = 0;
rel->subroot = NULL;
rel->subplan_params = NIL;
+ rel->rel_parallel_workers = -1; /* set up in GetRelationInfo */
rel->serverid = InvalidOid;
- rel->umid = InvalidOid;
+ rel->userid = rte->checkAsUser;
+ rel->useridiscurrent = false;
rel->fdwroutine = NULL;
rel->fdw_private = NULL;
rel->baserestrictinfo = NIL;
@@ -170,30 +169,6 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
break;
}
- /* For foreign tables get the user mapping */
- if (rte->relkind == RELKIND_FOREIGN_TABLE)
- {
- /*
- * This should match what ExecCheckRTEPerms() does.
- *
- * Note that if the plan ends up depending on the user OID in any way
- * - e.g. if it depends on the computed user mapping OID - we must
- * ensure that it gets invalidated in the case of a user OID change.
- * See RevalidateCachedQuery and more generally the hasForeignJoin
- * flags in PlannerGlobal and PlannedStmt.
- *
- * It's possible, and not necessarily an error, for rel->umid to be
- * InvalidOid even though rel->serverid is set. That just means there
- * is a server with no user mapping.
- */
- Oid userid;
-
- userid = OidIsValid(rte->checkAsUser) ? rte->checkAsUser : GetUserId();
- rel->umid = GetUserMappingId(userid, rel->serverid, true);
- }
- else
- rel->umid = InvalidOid;
-
/* Save the finished struct in the query's simple_rel_array */
root->simple_rel_array[relid] = rel;
@@ -423,8 +398,10 @@ build_join_rel(PlannerInfo *root,
joinrel->allvisfrac = 0;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;
+ joinrel->rel_parallel_workers = -1;
joinrel->serverid = InvalidOid;
- joinrel->umid = InvalidOid;
+ joinrel->userid = InvalidOid;
+ joinrel->useridiscurrent = false;
joinrel->fdwroutine = NULL;
joinrel->fdw_private = NULL;
joinrel->baserestrictinfo = NIL;
@@ -435,24 +412,43 @@ build_join_rel(PlannerInfo *root,
/*
* Set up foreign-join fields if outer and inner relation are foreign
- * tables (or joins) belonging to the same server and using the same user
- * mapping.
- *
- * Otherwise those fields are left invalid, so FDW API will not be called
- * for the join relation.
+ * tables (or joins) belonging to the same server and assigned to the same
+ * user to check access permissions as. In addition to an exact match of
+ * userid, we allow the case where one side has zero userid (implying
+ * current user) and the other side has explicit userid that happens to
+ * equal the current user; but in that case, pushdown of the join is only
+ * valid for the current user. The useridiscurrent field records whether
+ * we had to make such an assumption for this join or any sub-join.
*
- * For FDWs like file_fdw, which ignore user mapping, the user mapping id
- * associated with the joining relation may be invalid. A valid serverid
- * distinguishes between a pushed down join with no user mapping and a
- * join which can not be pushed down because of user mapping mismatch.
+ * Otherwise these fields are left invalid, so GetForeignJoinPaths will
+ * not be called for the join relation.
*/
if (OidIsValid(outer_rel->serverid) &&
- inner_rel->serverid == outer_rel->serverid &&
- inner_rel->umid == outer_rel->umid)
+ inner_rel->serverid == outer_rel->serverid)
{
- joinrel->serverid = outer_rel->serverid;
- joinrel->umid = outer_rel->umid;
- joinrel->fdwroutine = outer_rel->fdwroutine;
+ if (inner_rel->userid == outer_rel->userid)
+ {
+ joinrel->serverid = outer_rel->serverid;
+ joinrel->userid = outer_rel->userid;
+ joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
+ joinrel->fdwroutine = outer_rel->fdwroutine;
+ }
+ else if (!OidIsValid(inner_rel->userid) &&
+ outer_rel->userid == GetUserId())
+ {
+ joinrel->serverid = outer_rel->serverid;
+ joinrel->userid = outer_rel->userid;
+ joinrel->useridiscurrent = true;
+ joinrel->fdwroutine = outer_rel->fdwroutine;
+ }
+ else if (!OidIsValid(outer_rel->userid) &&
+ inner_rel->userid == GetUserId())
+ {
+ joinrel->serverid = outer_rel->serverid;
+ joinrel->userid = inner_rel->userid;
+ joinrel->useridiscurrent = true;
+ joinrel->fdwroutine = outer_rel->fdwroutine;
+ }
}
/*