LCOV - code coverage report
Current view: top level - contrib/postgres_fdw - shippable.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 50 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 5 0
Legend: Lines:     hit not hit

            Line data    Source code
       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 */
      34              : static HTAB *ShippableCacheHash = NULL;
      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              :  */
      41              : typedef 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 */
      47              : } ShippableCacheKey;
      48              : 
      49              : typedef struct
      50              : {
      51              :         ShippableCacheKey key;          /* hash key - must be first */
      52              :         bool            shippable;
      53              : } ShippableCacheEntry;
      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              :  */
      64              : static void
      65            0 : InvalidateShippableCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      66              : {
      67            0 :         HASH_SEQ_STATUS status;
      68            0 :         ShippableCacheEntry *entry;
      69              : 
      70              :         /*
      71              :          * In principle we could flush only cache entries relating to the
      72              :          * pg_foreign_server entry being outdated; but that would be more
      73              :          * complicated, and it's probably not worth the trouble.  So for now, just
      74              :          * flush all entries.
      75              :          */
      76            0 :         hash_seq_init(&status, ShippableCacheHash);
      77            0 :         while ((entry = (ShippableCacheEntry *) hash_seq_search(&status)) != NULL)
      78              :         {
      79            0 :                 if (hash_search(ShippableCacheHash,
      80            0 :                                                 &entry->key,
      81              :                                                 HASH_REMOVE,
      82            0 :                                                 NULL) == NULL)
      83            0 :                         elog(ERROR, "hash table corrupted");
      84              :         }
      85            0 : }
      86              : 
      87              : /*
      88              :  * Initialize the backend-lifespan cache of shippability decisions.
      89              :  */
      90              : static void
      91            0 : InitializeShippableCache(void)
      92              : {
      93            0 :         HASHCTL         ctl;
      94              : 
      95              :         /* Create the hash table. */
      96            0 :         ctl.keysize = sizeof(ShippableCacheKey);
      97            0 :         ctl.entrysize = sizeof(ShippableCacheEntry);
      98            0 :         ShippableCacheHash =
      99            0 :                 hash_create("Shippability cache", 256, &ctl, HASH_ELEM | HASH_BLOBS);
     100              : 
     101              :         /* Set up invalidation callback on pg_foreign_server. */
     102            0 :         CacheRegisterSyscacheCallback(FOREIGNSERVEROID,
     103              :                                                                   InvalidateShippableCacheCallback,
     104              :                                                                   (Datum) 0);
     105            0 : }
     106              : 
     107              : /*
     108              :  * Returns true if given object (operator/function/type) is shippable
     109              :  * according to the server options.
     110              :  *
     111              :  * Right now "shippability" is exclusively a function of whether the object
     112              :  * belongs to an extension declared by the user.  In the future we could
     113              :  * additionally have a list of functions/operators declared one at a time.
     114              :  */
     115              : static bool
     116            0 : lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
     117              : {
     118            0 :         Oid                     extensionOid;
     119              : 
     120              :         /*
     121              :          * Is object a member of some extension?  (Note: this is a fairly
     122              :          * expensive lookup, which is why we try to cache the results.)
     123              :          */
     124            0 :         extensionOid = getExtensionOfObject(classId, objectId);
     125              : 
     126              :         /* If so, is that extension in fpinfo->shippable_extensions? */
     127            0 :         if (OidIsValid(extensionOid) &&
     128            0 :                 list_member_oid(fpinfo->shippable_extensions, extensionOid))
     129            0 :                 return true;
     130              : 
     131            0 :         return false;
     132            0 : }
     133              : 
     134              : /*
     135              :  * Return true if given object is one of PostgreSQL's built-in objects.
     136              :  *
     137              :  * We use FirstGenbkiObjectId as the cutoff, so that we only consider
     138              :  * objects with hand-assigned OIDs to be "built in", not for instance any
     139              :  * function or type defined in the information_schema.
     140              :  *
     141              :  * Our constraints for dealing with types are tighter than they are for
     142              :  * functions or operators: we want to accept only types that are in pg_catalog,
     143              :  * else deparse_type_name might incorrectly fail to schema-qualify their names.
     144              :  * Thus we must exclude information_schema types.
     145              :  *
     146              :  * XXX there is a problem with this, which is that the set of built-in
     147              :  * objects expands over time.  Something that is built-in to us might not
     148              :  * be known to the remote server, if it's of an older version.  But keeping
     149              :  * track of that would be a huge exercise.
     150              :  */
     151              : bool
     152            0 : is_builtin(Oid objectId)
     153              : {
     154            0 :         return (objectId < FirstGenbkiObjectId);
     155              : }
     156              : 
     157              : /*
     158              :  * is_shippable
     159              :  *         Is this object (function/operator/type) shippable to foreign server?
     160              :  */
     161              : bool
     162            0 : is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
     163              : {
     164            0 :         ShippableCacheKey key;
     165            0 :         ShippableCacheEntry *entry;
     166              : 
     167              :         /* Built-in objects are presumed shippable. */
     168            0 :         if (is_builtin(objectId))
     169            0 :                 return true;
     170              : 
     171              :         /* Otherwise, give up if user hasn't specified any shippable extensions. */
     172            0 :         if (fpinfo->shippable_extensions == NIL)
     173            0 :                 return false;
     174              : 
     175              :         /* Initialize cache if first time through. */
     176            0 :         if (!ShippableCacheHash)
     177            0 :                 InitializeShippableCache();
     178              : 
     179              :         /* Set up cache hash key */
     180            0 :         key.objid = objectId;
     181            0 :         key.classid = classId;
     182            0 :         key.serverid = fpinfo->server->serverid;
     183              : 
     184              :         /* See if we already cached the result. */
     185            0 :         entry = (ShippableCacheEntry *)
     186            0 :                 hash_search(ShippableCacheHash, &key, HASH_FIND, NULL);
     187              : 
     188            0 :         if (!entry)
     189              :         {
     190              :                 /* Not found in cache, so perform shippability lookup. */
     191            0 :                 bool            shippable = lookup_shippable(objectId, classId, fpinfo);
     192              : 
     193              :                 /*
     194              :                  * Don't create a new hash entry until *after* we have the shippable
     195              :                  * result in hand, as the underlying catalog lookups might trigger a
     196              :                  * cache invalidation.
     197              :                  */
     198            0 :                 entry = (ShippableCacheEntry *)
     199            0 :                         hash_search(ShippableCacheHash, &key, HASH_ENTER, NULL);
     200              : 
     201            0 :                 entry->shippable = shippable;
     202            0 :         }
     203              : 
     204            0 :         return entry->shippable;
     205            0 : }
        

Generated by: LCOV version 2.3.2-1