FdwRoutine *fdwroutine;
bool ok = false;
- fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(onerel));
+ fdwroutine = GetFdwRoutineForRelation(onerel, false);
if (fdwroutine->AnalyzeForeignTable != NULL)
ok = fdwroutine->AnalyzeForeignTable(onerel,
/*
* 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;
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
#include "utils/syscache.h"
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
/* 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);
}
#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"
* 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
*
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);
/*
MemoryContextDelete(relation->rd_indexcxt);
if (relation->rd_rulescxt)
MemoryContextDelete(relation->rd_rulescxt);
+ if (relation->rd_fdwroutine)
+ pfree(relation->rd_fdwroutine);
pfree(relation);
}
* 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;
rel->rd_exclops = NULL;
rel->rd_exclprocs = NULL;
rel->rd_exclstrats = NULL;
+ rel->rd_fdwroutine = NULL;
/*
* Reset transient-state fields in the relcache entry
/* 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 */
void *rd_amcache; /* available for use by index AM */
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