aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/analyze.c2
-rw-r--r--src/backend/executor/nodeForeignscan.c2
-rw-r--r--src/backend/foreign/foreign.c46
-rw-r--r--src/backend/optimizer/path/allpaths.c3
-rw-r--r--src/backend/optimizer/util/plancat.c8
-rw-r--r--src/backend/utils/cache/relcache.c5
-rw-r--r--src/include/foreign/fdwapi.h1
-rw-r--r--src/include/utils/rel.h11
8 files changed, 72 insertions, 6 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ad9c911542d..d6d20fde9af 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -227,7 +227,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
FdwRoutine *fdwroutine;
bool ok = false;
- fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(onerel));
+ fdwroutine = GetFdwRoutineForRelation(onerel, false);
if (fdwroutine->AnalyzeForeignTable != NULL)
ok = fdwroutine->AnalyzeForeignTable(onerel,
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 6ebffadef19..63478cd12ad 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -160,7 +160,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
/*
* Acquire function pointers from the FDW's handler, and init fdw_state.
*/
- fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(currentRelation));
+ fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
scanstate->fdwroutine = fdwroutine;
scanstate->fdw_state = NULL;
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index bfcc323924a..2b75f73e08f 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -23,6 +23,8 @@
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
#include "utils/syscache.h"
@@ -352,6 +354,50 @@ GetFdwRoutineByRelId(Oid relid)
return GetFdwRoutine(fdwhandler);
}
+/*
+ * GetFdwRoutineForRelation - look up the handler of the foreign-data wrapper
+ * for the given foreign table, and retrieve its FdwRoutine struct.
+ *
+ * This function is preferred over GetFdwRoutineByRelId because it caches
+ * the data in the relcache entry, saving a number of catalog lookups.
+ *
+ * If makecopy is true then the returned data is freshly palloc'd in the
+ * caller's memory context. Otherwise, it's a pointer to the relcache data,
+ * which will be lost in any relcache reset --- so don't rely on it long.
+ */
+FdwRoutine *
+GetFdwRoutineForRelation(Relation relation, bool makecopy)
+{
+ FdwRoutine *fdwroutine;
+ FdwRoutine *cfdwroutine;
+
+ if (relation->rd_fdwroutine == NULL)
+ {
+ /* Get the info by consulting the catalogs and the FDW code */
+ fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(relation));
+
+ /* Save the data for later reuse in CacheMemoryContext */
+ cfdwroutine = (FdwRoutine *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(FdwRoutine));
+ memcpy(cfdwroutine, fdwroutine, sizeof(FdwRoutine));
+ relation->rd_fdwroutine = cfdwroutine;
+
+ /* Give back the locally palloc'd copy regardless of makecopy */
+ return fdwroutine;
+ }
+
+ /* We have valid cached data --- does the caller want a copy? */
+ if (makecopy)
+ {
+ fdwroutine = (FdwRoutine *) palloc(sizeof(FdwRoutine));
+ memcpy(fdwroutine, relation->rd_fdwroutine, sizeof(FdwRoutine));
+ return fdwroutine;
+ }
+
+ /* Only a short-lived reference is needed, so just hand back cached copy */
+ return relation->rd_fdwroutine;
+}
+
/*
* deflist_to_tuplestore - Helper function to convert DefElem list to
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 0545f958f67..86d5bb71b0a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -410,9 +410,6 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Mark rel with estimated output rows, width, etc */
set_foreign_size_estimates(root, rel);
- /* Get FDW routine pointers for the rel */
- rel->fdwroutine = GetFdwRoutineByRelId(rte->relid);
-
/* Let FDW adjust the size estimates, if it can */
rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid);
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index bff7aff593d..954666ce04c 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -26,6 +26,7 @@
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
+#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@@ -67,6 +68,7 @@ static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
* min_attr lowest valid AttrNumber
* max_attr highest valid AttrNumber
* indexlist list of IndexOptInfos for relation's indexes
+ * fdwroutine if it's a foreign table, the FDW function pointers
* pages number of pages
* tuples number of tuples
*
@@ -374,6 +376,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->indexlist = indexinfos;
+ /* Grab the fdwroutine info using the relcache, while we have it */
+ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
+ else
+ rel->fdwroutine = NULL;
+
heap_close(relation, NoLock);
/*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ba03dfcbb2d..5b1d1e5b10a 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1846,6 +1846,8 @@ RelationDestroyRelation(Relation relation)
MemoryContextDelete(relation->rd_indexcxt);
if (relation->rd_rulescxt)
MemoryContextDelete(relation->rd_rulescxt);
+ if (relation->rd_fdwroutine)
+ pfree(relation->rd_fdwroutine);
pfree(relation);
}
@@ -4410,7 +4412,7 @@ load_relcache_init_file(bool shared)
* format is complex and subject to change). They must be rebuilt if
* needed by RelationCacheInitializePhase3. This is not expected to
* be a big performance hit since few system catalogs have such. Ditto
- * for index expressions, predicates, and exclusion info.
+ * for index expressions, predicates, exclusion info, and FDW info.
*/
rel->rd_rules = NULL;
rel->rd_rulescxt = NULL;
@@ -4420,6 +4422,7 @@ load_relcache_init_file(bool shared)
rel->rd_exclops = NULL;
rel->rd_exclprocs = NULL;
rel->rd_exclstrats = NULL;
+ rel->rd_fdwroutine = NULL;
/*
* Reset transient-state fields in the relcache entry
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 13dcbfdf8c7..562d5412df7 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -96,5 +96,6 @@ typedef struct FdwRoutine
/* Functions in foreign/foreign.c */
extern FdwRoutine *GetFdwRoutine(Oid fdwhandler);
extern FdwRoutine *GetFdwRoutineByRelId(Oid relid);
+extern FdwRoutine *GetFdwRoutineForRelation(Relation relation, bool makecopy);
#endif /* FDWAPI_H */
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 06e1531e9a3..a4daf772e57 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -166,6 +166,17 @@ typedef struct RelationData
Oid *rd_indcollation; /* OIDs of index collations */
/*
+ * foreign-table support
+ *
+ * rd_fdwroutine must point to a single memory chunk palloc'd in
+ * CacheMemoryContext. It will be freed and reset to NULL on a relcache
+ * reset.
+ */
+
+ /* use "struct" here to avoid needing to include fdwapi.h: */
+ struct FdwRoutine *rd_fdwroutine; /* cached function pointers, or NULL */
+
+ /*
* Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new
* version of a table, we need to make any toast pointers inserted into it
* have the existing toast table's OID, not the OID of the transient toast