LCOV - differential code coverage report
Current view: top level - contrib/postgres_fdw - shippable.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 97.4 % 38 37 1 37
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 5 5 5
Baseline: 16@8cea358b128 Branches: 77.8 % 18 14 4 14
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 97.4 % 38 37 1 37
Function coverage date bins:
(240..) days: 100.0 % 5 5 5
Branch coverage date bins:
(240..) days: 77.8 % 18 14 4 14

 Age         Owner                    Branch data    TLA  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-2024, 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
 3085 tgl@sss.pgh.pa.us          65                 :CBC         128 : InvalidateShippableCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
                                 66                 :                : {
                                 67                 :                :     HASH_SEQ_STATUS status;
                                 68                 :                :     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                 :            128 :     hash_seq_init(&status, ShippableCacheHash);
                                 77         [ +  + ]:            143 :     while ((entry = (ShippableCacheEntry *) hash_seq_search(&status)) != NULL)
                                 78                 :                :     {
                                 79         [ -  + ]:             15 :         if (hash_search(ShippableCacheHash,
  433 peter@eisentraut.org       80                 :             15 :                         &entry->key,
                                 81                 :                :                         HASH_REMOVE,
                                 82                 :                :                         NULL) == NULL)
 3085 tgl@sss.pgh.pa.us          83         [ #  # ]:UBC           0 :             elog(ERROR, "hash table corrupted");
                                 84                 :                :     }
 3085 tgl@sss.pgh.pa.us          85                 :CBC         128 : }
                                 86                 :                : 
                                 87                 :                : /*
                                 88                 :                :  * Initialize the backend-lifespan cache of shippability decisions.
                                 89                 :                :  */
                                 90                 :                : static void
                                 91                 :              2 : InitializeShippableCache(void)
                                 92                 :                : {
                                 93                 :                :     HASHCTL     ctl;
                                 94                 :                : 
                                 95                 :                :     /* Create the hash table. */
                                 96                 :              2 :     ctl.keysize = sizeof(ShippableCacheKey);
                                 97                 :              2 :     ctl.entrysize = sizeof(ShippableCacheEntry);
                                 98                 :              2 :     ShippableCacheHash =
                                 99                 :              2 :         hash_create("Shippability cache", 256, &ctl, HASH_ELEM | HASH_BLOBS);
                                100                 :                : 
                                101                 :                :     /* Set up invalidation callback on pg_foreign_server. */
                                102                 :              2 :     CacheRegisterSyscacheCallback(FOREIGNSERVEROID,
                                103                 :                :                                   InvalidateShippableCacheCallback,
                                104                 :                :                                   (Datum) 0);
                                105                 :              2 : }
                                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                 :             18 : lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
                                117                 :                : {
                                118                 :                :     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                 :             18 :     extensionOid = getExtensionOfObject(classId, objectId);
                                125                 :                : 
                                126                 :                :     /* If so, is that extension in fpinfo->shippable_extensions? */
                                127   [ +  +  +  - ]:             27 :     if (OidIsValid(extensionOid) &&
                                128                 :              9 :         list_member_oid(fpinfo->shippable_extensions, extensionOid))
                                129                 :              9 :         return true;
                                130                 :                : 
                                131                 :              9 :     return false;
                                132                 :                : }
                                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                 :          10499 : is_builtin(Oid objectId)
                                153                 :                : {
 1949 andres@anarazel.de        154                 :          10499 :     return (objectId < FirstGenbkiObjectId);
                                155                 :                : }
                                156                 :                : 
                                157                 :                : /*
                                158                 :                :  * is_shippable
                                159                 :                :  *     Is this object (function/operator/type) shippable to foreign server?
                                160                 :                :  */
                                161                 :                : bool
 3085 tgl@sss.pgh.pa.us         162                 :           9972 : is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
                                163                 :                : {
                                164                 :                :     ShippableCacheKey key;
                                165                 :                :     ShippableCacheEntry *entry;
                                166                 :                : 
                                167                 :                :     /* Built-in objects are presumed shippable. */
                                168         [ +  + ]:           9972 :     if (is_builtin(objectId))
                                169                 :           9862 :         return true;
                                170                 :                : 
                                171                 :                :     /* Otherwise, give up if user hasn't specified any shippable extensions. */
                                172         [ +  + ]:            110 :     if (fpinfo->shippable_extensions == NIL)
                                173                 :             58 :         return false;
                                174                 :                : 
                                175                 :                :     /* Initialize cache if first time through. */
                                176         [ +  + ]:             52 :     if (!ShippableCacheHash)
                                177                 :              2 :         InitializeShippableCache();
                                178                 :                : 
                                179                 :                :     /* Set up cache hash key */
                                180                 :             52 :     key.objid = objectId;
                                181                 :             52 :     key.classid = classId;
                                182                 :             52 :     key.serverid = fpinfo->server->serverid;
                                183                 :                : 
                                184                 :                :     /* See if we already cached the result. */
                                185                 :                :     entry = (ShippableCacheEntry *)
  331                           186                 :             52 :         hash_search(ShippableCacheHash, &key, HASH_FIND, NULL);
                                187                 :                : 
 3085                           188         [ +  + ]:             52 :     if (!entry)
                                189                 :                :     {
                                190                 :                :         /* Not found in cache, so perform shippability lookup. */
                                191                 :             18 :         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                 :                :         entry = (ShippableCacheEntry *)
  331                           199                 :             18 :             hash_search(ShippableCacheHash, &key, HASH_ENTER, NULL);
                                200                 :                : 
 3085                           201                 :             18 :         entry->shippable = shippable;
                                202                 :                :     }
                                203                 :                : 
                                204                 :             52 :     return entry->shippable;
                                205                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622