PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 white-listed 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-2017, PostgreSQL Global Development Group
17  *
18  * IDENTIFICATION
19  * contrib/postgres_fdw/shippable.c
20  *
21  *-------------------------------------------------------------------------
22  */
23 
24 #include "postgres.h"
25 
26 #include "postgres_fdw.h"
27 
28 #include "access/transam.h"
29 #include "catalog/dependency.h"
30 #include "utils/hsearch.h"
31 #include "utils/inval.h"
32 #include "utils/syscache.h"
33 
34 
35 /* Hash table for caching the results of shippability lookups */
37 
38 /*
39  * Hash key for shippability lookups. We include the FDW server OID because
40  * decisions may differ per-server. Otherwise, objects are identified by
41  * their (local!) OID and catalog OID.
42  */
43 typedef struct
44 {
45  /* XXX we assume this struct contains no padding bytes */
46  Oid objid; /* function/operator/type OID */
47  Oid classid; /* OID of its catalog (pg_proc, etc) */
48  Oid serverid; /* FDW server we are concerned with */
50 
51 typedef struct
52 {
53  ShippableCacheKey key; /* hash key - must be first */
54  bool shippable;
56 
57 
58 /*
59  * Flush cache entries when pg_foreign_server is updated.
60  *
61  * We do this because of the possibility of ALTER SERVER being used to change
62  * a server's extensions option. We do not currently bother to check whether
63  * objects' extension membership changes once a shippability decision has been
64  * made for them, however.
65  */
66 static void
68 {
70  ShippableCacheEntry *entry;
71 
72  /*
73  * In principle we could flush only cache entries relating to the
74  * pg_foreign_server entry being outdated; but that would be more
75  * complicated, and it's probably not worth the trouble. So for now, just
76  * flush all entries.
77  */
78  hash_seq_init(&status, ShippableCacheHash);
79  while ((entry = (ShippableCacheEntry *) hash_seq_search(&status)) != NULL)
80  {
81  if (hash_search(ShippableCacheHash,
82  (void *) &entry->key,
84  NULL) == NULL)
85  elog(ERROR, "hash table corrupted");
86  }
87 }
88 
89 /*
90  * Initialize the backend-lifespan cache of shippability decisions.
91  */
92 static void
94 {
95  HASHCTL ctl;
96 
97  /* Create the hash table. */
98  MemSet(&ctl, 0, sizeof(ctl));
99  ctl.keysize = sizeof(ShippableCacheKey);
100  ctl.entrysize = sizeof(ShippableCacheEntry);
101  ShippableCacheHash =
102  hash_create("Shippability cache", 256, &ctl, HASH_ELEM | HASH_BLOBS);
103 
104  /* Set up invalidation callback on pg_foreign_server. */
107  (Datum) 0);
108 }
109 
110 /*
111  * Returns true if given object (operator/function/type) is shippable
112  * according to the server options.
113  *
114  * Right now "shippability" is exclusively a function of whether the object
115  * belongs to an extension declared by the user. In the future we could
116  * additionally have a whitelist of functions/operators declared one at a time.
117  */
118 static bool
119 lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
120 {
121  Oid extensionOid;
122 
123  /*
124  * Is object a member of some extension? (Note: this is a fairly
125  * expensive lookup, which is why we try to cache the results.)
126  */
127  extensionOid = getExtensionOfObject(classId, objectId);
128 
129  /* If so, is that extension in fpinfo->shippable_extensions? */
130  if (OidIsValid(extensionOid) &&
131  list_member_oid(fpinfo->shippable_extensions, extensionOid))
132  return true;
133 
134  return false;
135 }
136 
137 /*
138  * Return true if given object is one of PostgreSQL's built-in objects.
139  *
140  * We use FirstBootstrapObjectId as the cutoff, so that we only consider
141  * objects with hand-assigned OIDs to be "built in", not for instance any
142  * function or type defined in the information_schema.
143  *
144  * Our constraints for dealing with types are tighter than they are for
145  * functions or operators: we want to accept only types that are in pg_catalog,
146  * else deparse_type_name might incorrectly fail to schema-qualify their names.
147  * Thus we must exclude information_schema types.
148  *
149  * XXX there is a problem with this, which is that the set of built-in
150  * objects expands over time. Something that is built-in to us might not
151  * be known to the remote server, if it's of an older version. But keeping
152  * track of that would be a huge exercise.
153  */
154 bool
155 is_builtin(Oid objectId)
156 {
157  return (objectId < FirstBootstrapObjectId);
158 }
159 
160 /*
161  * is_shippable
162  * Is this object (function/operator/type) shippable to foreign server?
163  */
164 bool
165 is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
166 {
167  ShippableCacheKey key;
168  ShippableCacheEntry *entry;
169 
170  /* Built-in objects are presumed shippable. */
171  if (is_builtin(objectId))
172  return true;
173 
174  /* Otherwise, give up if user hasn't specified any shippable extensions. */
175  if (fpinfo->shippable_extensions == NIL)
176  return false;
177 
178  /* Initialize cache if first time through. */
179  if (!ShippableCacheHash)
181 
182  /* Set up cache hash key */
183  key.objid = objectId;
184  key.classid = classId;
185  key.serverid = fpinfo->server->serverid;
186 
187  /* See if we already cached the result. */
188  entry = (ShippableCacheEntry *)
189  hash_search(ShippableCacheHash,
190  (void *) &key,
191  HASH_FIND,
192  NULL);
193 
194  if (!entry)
195  {
196  /* Not found in cache, so perform shippability lookup. */
197  bool shippable = lookup_shippable(objectId, classId, fpinfo);
198 
199  /*
200  * Don't create a new hash entry until *after* we have the shippable
201  * result in hand, as the underlying catalog lookups might trigger a
202  * cache invalidation.
203  */
204  entry = (ShippableCacheEntry *)
205  hash_search(ShippableCacheHash,
206  (void *) &key,
207  HASH_ENTER,
208  NULL);
209 
210  entry->shippable = shippable;
211  }
212 
213  return entry->shippable;
214 }
#define NIL
Definition: pg_list.h:69
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:447
bool is_builtin(Oid objectId)
Definition: shippable.c:155
#define HASH_ELEM
Definition: hsearch.h:87
ForeignServer * server
Definition: postgres_fdw.h:76
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:857
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
static void InitializeShippableCache(void)
Definition: shippable.c:93
static bool lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition: shippable.c:119
Definition: dynahash.c:193
#define ERROR
Definition: elog.h:43
unsigned int uint32
Definition: c.h:268
#define FirstBootstrapObjectId
Definition: transam.h:93
#define HASH_BLOBS
Definition: hsearch.h:88
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1389
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
uintptr_t Datum
Definition: postgres.h:372
bool is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition: shippable.c:165
Size keysize
Definition: hsearch.h:72
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1351
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1341
static void InvalidateShippableCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: shippable.c:67
static HTAB * ShippableCacheHash
Definition: shippable.c:36
void * arg
#define elog
Definition: elog.h:219
ShippableCacheKey key
Definition: shippable.c:53
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
List * shippable_extensions
Definition: postgres_fdw.h:72
Oid serverid
Definition: foreign.h:47