@@ -160,6 +160,54 @@ GetForeignServerByName(const char *srvname, bool missing_ok)
160
160
return GetForeignServer (serverid );
161
161
}
162
162
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
+ }
163
211
164
212
/*
165
213
* GetUserMapping - look up the user mapping.
@@ -240,8 +288,8 @@ find_user_mapping(Oid userid, Oid serverid)
240
288
241
289
/* Not found for the specific user -- try PUBLIC */
242
290
tp = SearchSysCache2 (USERMAPPINGUSERSERVER ,
243
- ObjectIdGetDatum (InvalidOid ),
244
- ObjectIdGetDatum (serverid ));
291
+ ObjectIdGetDatum (InvalidOid ),
292
+ ObjectIdGetDatum (serverid ));
245
293
246
294
if (!HeapTupleIsValid (tp ))
247
295
ereport (ERROR ,
@@ -732,3 +780,115 @@ get_foreign_server_oid(const char *servername, bool missing_ok)
732
780
errmsg ("server \"%s\" does not exist" , servername )));
733
781
return oid ;
734
782
}
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