PostgreSQL Source Code git master
Loading...
Searching...
No Matches
shippable.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * shippable.c
4 * Determine which database objects are shippable to a remote server.
5 *
6 * We need to determine whether particular functions, operators, and indeed
7 * data types are shippable to a remote server for execution --- that is,
8 * do they exist and have the same behavior remotely as they do locally?
9 * Built-in objects are generally considered shippable. Other objects can
10 * be shipped if they are declared as such by the user.
11 *
12 * Note: there are additional filter rules that prevent shipping mutable
13 * functions or functions using nonportable collations. Those considerations
14 * need not be accounted for here.
15 *
16 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
17 *
18 * IDENTIFICATION
19 * contrib/postgres_fdw/shippable.c
20 *
21 *-------------------------------------------------------------------------
22 */
23
24#include "postgres.h"
25
26#include "access/transam.h"
27#include "catalog/dependency.h"
28#include "postgres_fdw.h"
29#include "utils/hsearch.h"
30#include "utils/inval.h"
31#include "utils/syscache.h"
32
33/* Hash table for caching the results of shippability lookups */
35
36/*
37 * Hash key for shippability lookups. We include the FDW server OID because
38 * decisions may differ per-server. Otherwise, objects are identified by
39 * their (local!) OID and catalog OID.
40 */
41typedef struct
42{
43 /* XXX we assume this struct contains no padding bytes */
44 Oid objid; /* function/operator/type OID */
45 Oid classid; /* OID of its catalog (pg_proc, etc) */
46 Oid serverid; /* FDW server we are concerned with */
48
49typedef struct
50{
51 ShippableCacheKey key; /* hash key - must be first */
54
55
56/*
57 * Flush cache entries when pg_foreign_server is updated.
58 *
59 * We do this because of the possibility of ALTER SERVER being used to change
60 * a server's extensions option. We do not currently bother to check whether
61 * objects' extension membership changes once a shippability decision has been
62 * made for them, however.
63 */
64static void
66 uint32 hashvalue)
67{
68 HASH_SEQ_STATUS status;
70
71 /*
72 * In principle we could flush only cache entries relating to the
73 * pg_foreign_server entry being outdated; but that would be more
74 * complicated, and it's probably not worth the trouble. So for now, just
75 * flush all entries.
76 */
78 while ((entry = (ShippableCacheEntry *) hash_seq_search(&status)) != NULL)
79 {
81 &entry->key,
83 NULL) == NULL)
84 elog(ERROR, "hash table corrupted");
85 }
86}
87
88/*
89 * Initialize the backend-lifespan cache of shippability decisions.
90 */
91static void
93{
95
96 /* Create the hash table. */
98 ctl.entrysize = sizeof(ShippableCacheEntry);
100 hash_create("Shippability cache", 256, &ctl, HASH_ELEM | HASH_BLOBS);
101
102 /* Set up invalidation callback on pg_foreign_server. */
105 (Datum) 0);
106}
107
108/*
109 * Returns true if given object (operator/function/type) is shippable
110 * according to the server options.
111 *
112 * Right now "shippability" is exclusively a function of whether the object
113 * belongs to an extension declared by the user. In the future we could
114 * additionally have a list of functions/operators declared one at a time.
115 */
116static bool
118{
120
121 /*
122 * Is object a member of some extension? (Note: this is a fairly
123 * expensive lookup, which is why we try to cache the results.)
124 */
125 extensionOid = getExtensionOfObject(classId, objectId);
126
127 /* If so, is that extension in fpinfo->shippable_extensions? */
129 list_member_oid(fpinfo->shippable_extensions, extensionOid))
130 return true;
131
132 return false;
133}
134
135/*
136 * Return true if given object is one of PostgreSQL's built-in objects.
137 *
138 * We use FirstGenbkiObjectId as the cutoff, so that we only consider
139 * objects with hand-assigned OIDs to be "built in", not for instance any
140 * function or type defined in the information_schema.
141 *
142 * Our constraints for dealing with types are tighter than they are for
143 * functions or operators: we want to accept only types that are in pg_catalog,
144 * else deparse_type_name might incorrectly fail to schema-qualify their names.
145 * Thus we must exclude information_schema types.
146 *
147 * XXX there is a problem with this, which is that the set of built-in
148 * objects expands over time. Something that is built-in to us might not
149 * be known to the remote server, if it's of an older version. But keeping
150 * track of that would be a huge exercise.
151 */
152bool
154{
155 return (objectId < FirstGenbkiObjectId);
156}
157
158/*
159 * is_shippable
160 * Is this object (function/operator/type) shippable to foreign server?
161 */
162bool
164{
166 ShippableCacheEntry *entry;
167
168 /* Built-in objects are presumed shippable. */
169 if (is_builtin(objectId))
170 return true;
171
172 /* Otherwise, give up if user hasn't specified any shippable extensions. */
173 if (fpinfo->shippable_extensions == NIL)
174 return false;
175
176 /* Initialize cache if first time through. */
179
180 /* Set up cache hash key */
181 key.objid = objectId;
182 key.classid = classId;
183 key.serverid = fpinfo->server->serverid;
184
185 /* See if we already cached the result. */
186 entry = (ShippableCacheEntry *)
188
189 if (!entry)
190 {
191 /* Not found in cache, so perform shippability lookup. */
192 bool shippable = lookup_shippable(objectId, classId, fpinfo);
193
194 /*
195 * Don't create a new hash entry until *after* we have the shippable
196 * result in hand, as the underlying catalog lookups might trigger a
197 * cache invalidation.
198 */
199 entry = (ShippableCacheEntry *)
201
202 entry->shippable = shippable;
203 }
204
205 return entry->shippable;
206}
uint32_t uint32
Definition c.h:558
#define OidIsValid(objectId)
Definition c.h:800
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
Datum arg
Definition elog.c:1322
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
@ HASH_FIND
Definition hsearch.h:113
@ HASH_REMOVE
Definition hsearch.h:115
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_BLOBS
Definition hsearch.h:97
void CacheRegisterSyscacheCallback(SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1816
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition pg_depend.c:734
#define NIL
Definition pg_list.h:68
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
tree ctl
Definition radixtree.h:1838
bool is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition shippable.c:163
static bool lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition shippable.c:117
bool is_builtin(Oid objectId)
Definition shippable.c:153
static void InitializeShippableCache(void)
Definition shippable.c:92
static HTAB * ShippableCacheHash
Definition shippable.c:34
static void InvalidateShippableCacheCallback(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition shippable.c:65
Size keysize
Definition hsearch.h:75
ShippableCacheKey key
Definition shippable.c:51
#define FirstGenbkiObjectId
Definition transam.h:195