LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - partitionfuncs.c (source / functions) Coverage Total Hit UNC GIC GNC CBC ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 98.7 % 76 75 1 32 6 37 33 1 5
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 4 4 2 1 1 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 66.7 % 3 2 1 2
Legend: Lines: hit not hit (180,240] days: 100.0 % 2 2 2
(240..) days: 100.0 % 71 71 32 2 37 33
Function coverage date bins:
(240..) days: 66.7 % 6 4 2 1 1 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * partitionfuncs.c
                                  4                 :  *    Functions for accessing partition-related metadata
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    src/backend/utils/adt/partitionfuncs.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : 
                                 16                 : #include "postgres.h"
                                 17                 : 
                                 18                 : #include "access/htup_details.h"
                                 19                 : #include "catalog/partition.h"
                                 20                 : #include "catalog/pg_class.h"
                                 21                 : #include "catalog/pg_inherits.h"
                                 22                 : #include "catalog/pg_type.h"
                                 23                 : #include "funcapi.h"
                                 24                 : #include "utils/fmgrprotos.h"
                                 25                 : #include "utils/lsyscache.h"
                                 26                 : #include "utils/syscache.h"
                                 27                 : 
                                 28                 : /*
                                 29                 :  * Checks if a given relation can be part of a partition tree.  Returns
                                 30                 :  * false if the relation cannot be processed, in which case it is up to
                                 31                 :  * the caller to decide what to do, by either raising an error or doing
                                 32                 :  * something else.
                                 33                 :  */
                                 34                 : static bool
 1521 michael                    35 CBC        1441 : check_rel_can_be_partition(Oid relid)
                                 36                 : {
                                 37                 :     char        relkind;
                                 38                 :     bool        relispartition;
                                 39                 : 
                                 40                 :     /* Check if relation exists */
                                 41            1441 :     if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
                                 42               9 :         return false;
                                 43                 : 
                                 44            1432 :     relkind = get_rel_relkind(relid);
 1499                            45            1432 :     relispartition = get_rel_relispartition(relid);
                                 46                 : 
                                 47                 :     /* Only allow relation types that can appear in partition trees. */
  492 peter                      48            1432 :     if (!relispartition && !RELKIND_HAS_PARTITIONS(relkind))
 1521 michael                    49             314 :         return false;
                                 50                 : 
                                 51            1118 :     return true;
                                 52                 : }
                                 53                 : 
                                 54                 : /*
                                 55                 :  * pg_partition_tree
                                 56                 :  *
                                 57                 :  * Produce a view with one row per member of a partition tree, beginning
                                 58                 :  * from the top-most parent given by the caller.  This gives information
                                 59                 :  * about each partition, its immediate partitioned parent, if it is
                                 60                 :  * a leaf partition and its level in the hierarchy.
                                 61                 :  */
                                 62                 : Datum
 1622                            63             473 : pg_partition_tree(PG_FUNCTION_ARGS)
                                 64                 : {
                                 65                 : #define PG_PARTITION_TREE_COLS  4
                                 66             473 :     Oid         rootrelid = PG_GETARG_OID(0);
                                 67                 :     FuncCallContext *funcctx;
                                 68                 :     List       *partitions;
                                 69                 : 
                                 70                 :     /* stuff done only on the first call of the function */
                                 71             473 :     if (SRF_IS_FIRSTCALL())
                                 72                 :     {
                                 73                 :         MemoryContext oldcxt;
                                 74                 :         TupleDesc   tupdesc;
                                 75                 : 
                                 76                 :         /* create a function context for cross-call persistence */
                                 77             101 :         funcctx = SRF_FIRSTCALL_INIT();
                                 78                 : 
 1500                            79             101 :         if (!check_rel_can_be_partition(rootrelid))
                                 80              18 :             SRF_RETURN_DONE(funcctx);
                                 81                 : 
                                 82                 :         /* switch to memory context appropriate for multiple function calls */
 1622                            83              83 :         oldcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
                                 84                 : 
                                 85                 :         /*
                                 86                 :          * Find all members of inheritance set.  We only need AccessShareLock
                                 87                 :          * on the children for the partition information lookup.
                                 88                 :          */
                                 89              83 :         partitions = find_all_inheritors(rootrelid, AccessShareLock, NULL);
                                 90                 : 
  109 michael                    91 GNC          83 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  109 michael                    92 UNC           0 :             elog(ERROR, "return type must be a row type");
  109 michael                    93 GNC          83 :         funcctx->tuple_desc = tupdesc;
 1622 michael                    94 ECB             : 
 1364 tgl                        95                 :         /* The only state we need is the partition list */
 1364 tgl                        96 GIC          83 :         funcctx->user_fctx = (void *) partitions;
 1622 michael                    97 ECB             : 
 1622 michael                    98 GIC          83 :         MemoryContextSwitchTo(oldcxt);
                                 99                 :     }
 1622 michael                   100 ECB             : 
                                101                 :     /* stuff done on every call of the function */
 1622 michael                   102 GIC         455 :     funcctx = SRF_PERCALL_SETUP();
 1364 tgl                       103 CBC         455 :     partitions = (List *) funcctx->user_fctx;
 1622 michael                   104 ECB             : 
 1364 tgl                       105 CBC         455 :     if (funcctx->call_cntr < list_length(partitions))
 1622 michael                   106 ECB             :     {
                                107                 :         Datum       result;
  267 peter                     108 GNC         372 :         Datum       values[PG_PARTITION_TREE_COLS] = {0};
                                109             372 :         bool        nulls[PG_PARTITION_TREE_COLS] = {0};
                                110                 :         HeapTuple   tuple;
 1622 michael                   111 GIC         372 :         Oid         parentid = InvalidOid;
 1364 tgl                       112             372 :         Oid         relid = list_nth_oid(partitions, funcctx->call_cntr);
 1622 michael                   113             372 :         char        relkind = get_rel_relkind(relid);
                                114             372 :         int         level = 0;
 1364 tgl                       115 CBC         372 :         List       *ancestors = get_partition_ancestors(relid);
                                116                 :         ListCell   *lc;
                                117                 : 
 1622 michael                   118 ECB             :         /*
                                119                 :          * Form tuple with appropriate data.
                                120                 :          */
                                121                 : 
                                122                 :         /* relid */
 1622 michael                   123 GIC         372 :         values[0] = ObjectIdGetDatum(relid);
 1622 michael                   124 ECB             : 
                                125                 :         /* parentid */
 1622 michael                   126 GIC         372 :         if (ancestors != NIL)
 1622 michael                   127 CBC         307 :             parentid = linitial_oid(ancestors);
 1622 michael                   128 GIC         372 :         if (OidIsValid(parentid))
 1622 michael                   129 CBC         307 :             values[1] = ObjectIdGetDatum(parentid);
                                130                 :         else
                                131              65 :             nulls[1] = true;
 1622 michael                   132 ECB             : 
                                133                 :         /* isleaf */
  492 peter                     134 GIC         372 :         values[2] = BoolGetDatum(!RELKIND_HAS_PARTITIONS(relkind));
                                135                 : 
 1622 michael                   136 ECB             :         /* level */
 1622 michael                   137 GIC         372 :         if (relid != rootrelid)
 1622 michael                   138 ECB             :         {
 1622 michael                   139 CBC         412 :             foreach(lc, ancestors)
 1622 michael                   140 ECB             :             {
 1622 michael                   141 GIC         412 :                 level++;
                                142             412 :                 if (lfirst_oid(lc) == rootrelid)
                                143             289 :                     break;
 1622 michael                   144 ECB             :             }
                                145                 :         }
 1622 michael                   146 GIC         372 :         values[3] = Int32GetDatum(level);
                                147                 : 
                                148             372 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
                                149             372 :         result = HeapTupleGetDatum(tuple);
                                150             372 :         SRF_RETURN_NEXT(funcctx, result);
                                151                 :     }
                                152                 : 
                                153                 :     /* done when there are no more elements left */
                                154              83 :     SRF_RETURN_DONE(funcctx);
 1622 michael                   155 ECB             : }
                                156                 : 
 1521                           157                 : /*
                                158                 :  * pg_partition_root
                                159                 :  *
                                160                 :  * Returns the top-most parent of the partition tree to which a given
                                161                 :  * relation belongs, or NULL if it's not (or cannot be) part of any
                                162                 :  * partition tree.
                                163                 :  */
                                164                 : Datum
 1521 michael                   165 CBC          48 : pg_partition_root(PG_FUNCTION_ARGS)
                                166                 : {
 1521 michael                   167 GIC          48 :     Oid         relid = PG_GETARG_OID(0);
                                168                 :     Oid         rootrelid;
                                169                 :     List       *ancestors;
                                170                 : 
 1521 michael                   171 CBC          48 :     if (!check_rel_can_be_partition(relid))
                                172              18 :         PG_RETURN_NULL();
                                173                 : 
 1479 michael                   174 ECB             :     /* fetch the list of ancestors */
 1521 michael                   175 CBC          30 :     ancestors = get_partition_ancestors(relid);
                                176                 : 
                                177                 :     /*
                                178                 :      * If the input relation is already the top-most parent, just return
                                179                 :      * itself.
                                180                 :      */
 1479                           181              30 :     if (ancestors == NIL)
                                182               6 :         PG_RETURN_OID(relid);
                                183                 : 
 1521 michael                   184 GIC          24 :     rootrelid = llast_oid(ancestors);
                                185              24 :     list_free(ancestors);
                                186                 : 
                                187                 :     /*
                                188                 :      * "rootrelid" must contain a valid OID, given that the input relation is
                                189                 :      * a valid partition tree member as checked above.
                                190                 :      */
                                191              24 :     Assert(OidIsValid(rootrelid));
 1521 michael                   192 CBC          24 :     PG_RETURN_OID(rootrelid);
                                193                 : }
 1497 alvherre                  194 ECB             : 
                                195                 : /*
                                196                 :  * pg_partition_ancestors
                                197                 :  *
                                198                 :  * Produces a view with one row per ancestor of the given partition,
                                199                 :  * including the input relation itself.
                                200                 :  */
                                201                 : Datum
 1497 alvherre                  202 CBC        3006 : pg_partition_ancestors(PG_FUNCTION_ARGS)
                                203                 : {
                                204            3006 :     Oid         relid = PG_GETARG_OID(0);
 1497 alvherre                  205 ECB             :     FuncCallContext *funcctx;
                                206                 :     List       *ancestors;
                                207                 : 
 1497 alvherre                  208 GIC        3006 :     if (SRF_IS_FIRSTCALL())
 1497 alvherre                  209 ECB             :     {
                                210                 :         MemoryContext oldcxt;
                                211                 : 
 1497 alvherre                  212 GIC        1292 :         funcctx = SRF_FIRSTCALL_INIT();
 1497 alvherre                  213 ECB             : 
 1497 alvherre                  214 GIC        1292 :         if (!check_rel_can_be_partition(relid))
 1497 alvherre                  215 CBC         287 :             SRF_RETURN_DONE(funcctx);
                                216                 : 
 1497 alvherre                  217 GIC        1005 :         oldcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 1497 alvherre                  218 ECB             : 
 1497 alvherre                  219 CBC        1005 :         ancestors = get_partition_ancestors(relid);
 1497 alvherre                  220 GIC        1005 :         ancestors = lcons_oid(relid, ancestors);
 1497 alvherre                  221 ECB             : 
                                222                 :         /* The only state we need is the ancestors list */
 1364 tgl                       223 CBC        1005 :         funcctx->user_fctx = (void *) ancestors;
                                224                 : 
 1497 alvherre                  225            1005 :         MemoryContextSwitchTo(oldcxt);
                                226                 :     }
                                227                 : 
                                228            2719 :     funcctx = SRF_PERCALL_SETUP();
 1364 tgl                       229 GIC        2719 :     ancestors = (List *) funcctx->user_fctx;
                                230                 : 
                                231            2719 :     if (funcctx->call_cntr < list_length(ancestors))
                                232                 :     {
  186 drowley                   233 GNC        1714 :         Oid         resultrel = list_nth_oid(ancestors, funcctx->call_cntr);
                                234                 : 
                                235            1714 :         SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(resultrel));
                                236                 :     }
                                237                 : 
 1497 alvherre                  238 GIC        1005 :     SRF_RETURN_DONE(funcctx);
                                239                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a