Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita104a01

Browse files
committed
Add some additional core functions to support join pushdown for FDWs.
GetExistingLocalJoinPath() is useful for handling EvalPlanQual rechecksproperly, and GetUserMappingById() is needed to make sure you're usingthe right credentials.Shigeru Hanada, Etsuro Fujita, Ashutosh Bapat, Robert Haas
1 parentc1772ad commita104a01

File tree

4 files changed

+196
-2
lines changed

4 files changed

+196
-2
lines changed

‎doc/src/sgml/fdwhandler.sgml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,21 @@ GetForeignJoinPaths (PlannerInfo *root,
341341
See <xref linkend="fdw-planning"> for additional information.
342342
</para>
343343

344+
<para>
345+
<programlisting>
346+
void
347+
GetExistingLocalJoinPath(RelOptInfo *joinrel)
348+
</programlisting>
349+
The function returns copy of a local join path, which can be converted
350+
into an alternative local join plan, which may be useful when
351+
implementing a <literal>RecheckForeignScan</> method. The function
352+
searches for a parallel-safe, unparameterized path in the
353+
<literal>pathlist</> of given <literal>joinrel</>. If it does not find
354+
such a path, it returns NULL, in which case a foreign data wrapper may
355+
build the local path by itself or may choose not to create access paths
356+
for that join.
357+
</para>
358+
344359
</sect2>
345360

346361
<sect2 id="fdw-callbacks-update">
@@ -794,6 +809,9 @@ RecheckForeignScan (ForeignScanState *node, TupleTableSlot *slot);
794809
can be executed and the resulting tuple can be stored in the slot.
795810
This plan need not be efficient since no base table will return more
796811
than one row; for example, it may implement all joins as nested loops.
812+
<literal>GetExistingLocalJoinPath</> may be used to search existing paths
813+
for a suitable local join path, which can be used as the alternative
814+
local join plan.
797815
</para>
798816
</sect2>
799817

@@ -1069,6 +1087,20 @@ GetForeignTable(Oid relid);
10691087

10701088
<para>
10711089
<programlisting>
1090+
UserMapping *
1091+
GetUserMappingById(Oid umid);
1092+
</programlisting>
1093+
1094+
This function returns the <structname>UserMapping</structname> object for
1095+
the given user mapping OID. The OID of a user mapping for a foreign scan
1096+
is available in the <structname>RelOptInfo</structname>.
1097+
If there is no mapping for the OID, this function will throw an error.
1098+
A <structname>UserMapping</structname> object contains properties of the
1099+
user mapping (see <filename>foreign/foreign.h</filename> for details).
1100+
</para>
1101+
1102+
<para>
1103+
<programlisting>
10721104
List *
10731105
GetForeignColumnOptions(Oid relid, AttrNumber attnum);
10741106
</programlisting>

‎src/backend/foreign/foreign.c

Lines changed: 162 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,54 @@ GetForeignServerByName(const char *srvname, bool missing_ok)
160160
returnGetForeignServer(serverid);
161161
}
162162

163+
/*
164+
* GetUserMappingById - look up the user mapping by its OID.
165+
*/
166+
UserMapping*
167+
GetUserMappingById(Oidumid)
168+
{
169+
Datumdatum;
170+
HeapTupletp;
171+
boolisnull;
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+
returnum;
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
returnoid;
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+
externPath*
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+
caseT_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+
caseT_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+
caseT_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+
returnNULL;
894+
}

‎src/include/foreign/fdwapi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,5 +202,6 @@ extern FdwRoutine *GetFdwRoutineByRelId(Oid relid);
202202
externFdwRoutine*GetFdwRoutineForRelation(Relationrelation,boolmakecopy);
203203
externboolIsImportableForeignTable(constchar*tablename,
204204
ImportForeignSchemaStmt*stmt);
205+
externPath*GetExistingLocalJoinPath(RelOptInfo*joinrel);
205206

206207
#endif/* FDWAPI_H */

‎src/include/foreign/foreign.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ extern ForeignServer *GetForeignServer(Oid serverid);
7373
externForeignServer*GetForeignServerByName(constchar*name,boolmissing_ok);
7474
externUserMapping*GetUserMapping(Oiduserid,Oidserverid);
7575
externOidGetUserMappingId(Oiduserid,Oidserverid);
76+
externUserMapping*GetUserMappingById(Oidumid);
7677
externForeignDataWrapper*GetForeignDataWrapper(Oidfdwid);
7778
externForeignDataWrapper*GetForeignDataWrapperByName(constchar*name,
7879
boolmissing_ok);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp