@@ -160,6 +160,54 @@ GetForeignServerByName(const char *srvname, bool missing_ok)
160160 return GetForeignServer (serverid );
161161}
162162
163+ /*
164+ * GetUserMappingById - look up the user mapping by its OID.
165+ */
166+ UserMapping *
167+ GetUserMappingById (Oid umid )
168+ {
169+ Datum datum ;
170+ HeapTuple tp ;
171+ bool isnull ;
172+ UserMapping * um ;
173+
174+ tp = SearchSysCache1 (USERMAPPINGOID , ObjectIdGetDatum (umid ));
175+ if (!HeapTupleIsValid (tp ))
176+ elog (ERROR , "cache lookup failed for user mapping %u" , umid );
177+
178+ um = (UserMapping * ) palloc (sizeof (UserMapping ));
179+ um -> umid = umid ;
180+
181+ /* Extract the umuser */
182+ datum = SysCacheGetAttr (USERMAPPINGOID ,
183+ tp ,
184+ Anum_pg_user_mapping_umuser ,
185+ & isnull );
186+ Assert (!isnull );
187+ um -> userid = DatumGetObjectId (datum );
188+
189+ /* Extract the umserver */
190+ datum = SysCacheGetAttr (USERMAPPINGOID ,
191+ tp ,
192+ Anum_pg_user_mapping_umserver ,
193+ & isnull );
194+ Assert (!isnull );
195+ um -> serverid = DatumGetObjectId (datum );
196+
197+ /* Extract the umoptions */
198+ datum = SysCacheGetAttr (USERMAPPINGOID ,
199+ tp ,
200+ Anum_pg_user_mapping_umoptions ,
201+ & isnull );
202+ if (isnull )
203+ um -> options = NIL ;
204+ else
205+ um -> options = untransformRelOptions (datum );
206+
207+ ReleaseSysCache (tp );
208+
209+ return um ;
210+ }
163211
164212/*
165213 * GetUserMapping - look up the user mapping.
@@ -240,8 +288,8 @@ find_user_mapping(Oid userid, Oid serverid)
240288
241289 /* Not found for the specific user -- try PUBLIC */
242290 tp = SearchSysCache2 (USERMAPPINGUSERSERVER ,
243- ObjectIdGetDatum (InvalidOid ),
244- ObjectIdGetDatum (serverid ));
291+ ObjectIdGetDatum (InvalidOid ),
292+ ObjectIdGetDatum (serverid ));
245293
246294 if (!HeapTupleIsValid (tp ))
247295 ereport (ERROR ,
@@ -732,3 +780,115 @@ get_foreign_server_oid(const char *servername, bool missing_ok)
732780 errmsg ("server \"%s\" does not exist" , servername )));
733781 return oid ;
734782}
783+
784+ /*
785+ * Get a copy of an existing local path for a given join relation.
786+ *
787+ * This function is usually helpful to obtain an alternate local path for EPQ
788+ * checks.
789+ *
790+ * Right now, this function only supports unparameterized foreign joins, so we
791+ * only search for unparameterized path in the given list of paths. Since we
792+ * are searching for a path which can be used to construct an alternative local
793+ * plan for a foreign join, we look for only MergeJoin, HashJoin or NestLoop
794+ * paths.
795+ *
796+ * If the inner or outer subpath of the chosen path is a ForeignScan, we
797+ * replace it with its outer subpath. For this reason, and also because the
798+ * planner might free the original path later, the path returned by this
799+ * function is a shallow copy of the original. There's no need to copy
800+ * the substructure, so we don't.
801+ *
802+ * Since the plan created using this path will presumably only be used to
803+ * execute EPQ checks, efficiency of the path is not a concern. But since the
804+ * list passed is expected to be from RelOptInfo, it's anyway sorted by total
805+ * cost and hence we are likely to choose the most efficient path, which is
806+ * all for the best.
807+ */
808+ extern Path *
809+ GetExistingLocalJoinPath (RelOptInfo * joinrel )
810+ {
811+ ListCell * lc ;
812+
813+ Assert (joinrel -> reloptkind == RELOPT_JOINREL );
814+
815+ foreach (lc , joinrel -> pathlist )
816+ {
817+ Path * path = (Path * ) lfirst (lc );
818+ JoinPath * joinpath = NULL ;
819+
820+ /* Skip parameterised or non-parallel-safe paths. */
821+ if (path -> param_info != NULL || !path -> parallel_safe )
822+ continue ;
823+
824+ switch (path -> pathtype )
825+ {
826+ case T_HashJoin :
827+ {
828+ HashPath * hash_path = makeNode (HashPath );
829+
830+ memcpy (hash_path , path , sizeof (HashPath ));
831+ joinpath = (JoinPath * ) hash_path ;
832+ }
833+ break ;
834+
835+ case T_NestLoop :
836+ {
837+ NestPath * nest_path = makeNode (NestPath );
838+
839+ memcpy (nest_path , path , sizeof (NestPath ));
840+ joinpath = (JoinPath * ) nest_path ;
841+ }
842+ break ;
843+
844+ case T_MergeJoin :
845+ {
846+ MergePath * merge_path = makeNode (MergePath );
847+
848+ memcpy (merge_path , path , sizeof (MergePath ));
849+ joinpath = (JoinPath * ) merge_path ;
850+ }
851+ break ;
852+
853+ default :
854+
855+ /*
856+ * Just skip anything else. We don't know if corresponding
857+ * plan would build the output row from whole-row references
858+ * of base relations and execute the EPQ checks.
859+ */
860+ break ;
861+ }
862+
863+ /* This path isn't good for us, check next. */
864+ if (!joinpath )
865+ continue ;
866+
867+ /*
868+ * If either inner or outer path is a ForeignPath corresponding to a
869+ * pushed down join, replace it with the fdw_outerpath, so that we
870+ * maintain path for EPQ checks built entirely of local join
871+ * strategies.
872+ */
873+ if (IsA (joinpath -> outerjoinpath , ForeignPath ))
874+ {
875+ ForeignPath * foreign_path ;
876+
877+ foreign_path = (ForeignPath * ) joinpath -> outerjoinpath ;
878+ if (foreign_path -> path .parent -> reloptkind == RELOPT_JOINREL )
879+ joinpath -> outerjoinpath = foreign_path -> fdw_outerpath ;
880+ }
881+
882+ if (IsA (joinpath -> innerjoinpath , ForeignPath ))
883+ {
884+ ForeignPath * foreign_path ;
885+
886+ foreign_path = (ForeignPath * ) joinpath -> innerjoinpath ;
887+ if (foreign_path -> path .parent -> reloptkind == RELOPT_JOINREL )
888+ joinpath -> innerjoinpath = foreign_path -> fdw_outerpath ;
889+ }
890+
891+ return (Path * ) joinpath ;
892+ }
893+ return NULL ;
894+ }
0 commit comments