LCOV - differential code coverage report
Current view: top level - src/backend/catalog - partition.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 96.3 % 107 103 4 103
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 10 10 10
Baseline: 16@8cea358b128 Branches: 75.0 % 56 42 14 42
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: 96.3 % 107 103 4 103
Function coverage date bins:
(240..) days: 100.0 % 10 10 10
Branch coverage date bins:
(240..) days: 75.0 % 56 42 14 42

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * partition.c
                                  4                 :                :  *        Partitioning related data structures and functions.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *        src/backend/catalog/partition.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                : */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/attmap.h"
                                 18                 :                : #include "access/genam.h"
                                 19                 :                : #include "access/htup_details.h"
                                 20                 :                : #include "access/sysattr.h"
                                 21                 :                : #include "access/table.h"
                                 22                 :                : #include "catalog/indexing.h"
                                 23                 :                : #include "catalog/partition.h"
                                 24                 :                : #include "catalog/pg_inherits.h"
                                 25                 :                : #include "catalog/pg_partitioned_table.h"
                                 26                 :                : #include "nodes/makefuncs.h"
                                 27                 :                : #include "optimizer/optimizer.h"
                                 28                 :                : #include "rewrite/rewriteManip.h"
                                 29                 :                : #include "utils/fmgroids.h"
                                 30                 :                : #include "utils/partcache.h"
                                 31                 :                : #include "utils/rel.h"
                                 32                 :                : #include "utils/syscache.h"
                                 33                 :                : 
                                 34                 :                : static Oid  get_partition_parent_worker(Relation inhRel, Oid relid,
                                 35                 :                :                                         bool *detach_pending);
                                 36                 :                : static void get_partition_ancestors_worker(Relation inhRel, Oid relid,
                                 37                 :                :                                            List **ancestors);
                                 38                 :                : 
                                 39                 :                : /*
                                 40                 :                :  * get_partition_parent
                                 41                 :                :  *      Obtain direct parent of given relation
                                 42                 :                :  *
                                 43                 :                :  * Returns inheritance parent of a partition by scanning pg_inherits
                                 44                 :                :  *
                                 45                 :                :  * If the partition is in the process of being detached, an error is thrown,
                                 46                 :                :  * unless even_if_detached is passed as true.
                                 47                 :                :  *
                                 48                 :                :  * Note: Because this function assumes that the relation whose OID is passed
                                 49                 :                :  * as an argument will have precisely one parent, it should only be called
                                 50                 :                :  * when it is known that the relation is a partition.
                                 51                 :                :  */
                                 52                 :                : Oid
 1116 alvherre@alvh.no-ip.       53                 :CBC        6629 : get_partition_parent(Oid relid, bool even_if_detached)
                                 54                 :                : {
                                 55                 :                :     Relation    catalogRelation;
                                 56                 :                :     Oid         result;
                                 57                 :                :     bool        detach_pending;
                                 58                 :                : 
 1910 andres@anarazel.de         59                 :           6629 :     catalogRelation = table_open(InheritsRelationId, AccessShareLock);
                                 60                 :                : 
 1116 alvherre@alvh.no-ip.       61                 :           6629 :     result = get_partition_parent_worker(catalogRelation, relid,
                                 62                 :                :                                          &detach_pending);
                                 63                 :                : 
 2192                            64         [ -  + ]:           6629 :     if (!OidIsValid(result))
 2192 alvherre@alvh.no-ip.       65         [ #  # ]:UBC           0 :         elog(ERROR, "could not find tuple for parent of relation %u", relid);
                                 66                 :                : 
 1116 alvherre@alvh.no-ip.       67   [ +  +  -  + ]:CBC        6629 :     if (detach_pending && !even_if_detached)
 1116 alvherre@alvh.no-ip.       68         [ #  # ]:UBC           0 :         elog(ERROR, "relation %u has no parent because it's being detached",
                                 69                 :                :              relid);
                                 70                 :                : 
 1910 andres@anarazel.de         71                 :CBC        6629 :     table_close(catalogRelation, AccessShareLock);
                                 72                 :                : 
 2192 alvherre@alvh.no-ip.       73                 :           6629 :     return result;
                                 74                 :                : }
                                 75                 :                : 
                                 76                 :                : /*
                                 77                 :                :  * get_partition_parent_worker
                                 78                 :                :  *      Scan the pg_inherits relation to return the OID of the parent of the
                                 79                 :                :  *      given relation
                                 80                 :                :  *
                                 81                 :                :  * If the partition is being detached, *detach_pending is set true (but the
                                 82                 :                :  * original parent is still returned.)
                                 83                 :                :  */
                                 84                 :                : static Oid
 1116                            85                 :          12159 : get_partition_parent_worker(Relation inhRel, Oid relid, bool *detach_pending)
                                 86                 :                : {
                                 87                 :                :     SysScanDesc scan;
                                 88                 :                :     ScanKeyData key[2];
 2192                            89                 :          12159 :     Oid         result = InvalidOid;
                                 90                 :                :     HeapTuple   tuple;
                                 91                 :                : 
 1116                            92                 :          12159 :     *detach_pending = false;
                                 93                 :                : 
 2192                            94                 :          12159 :     ScanKeyInit(&key[0],
                                 95                 :                :                 Anum_pg_inherits_inhrelid,
                                 96                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                                 97                 :                :                 ObjectIdGetDatum(relid));
                                 98                 :          12159 :     ScanKeyInit(&key[1],
                                 99                 :                :                 Anum_pg_inherits_inhseqno,
                                100                 :                :                 BTEqualStrategyNumber, F_INT4EQ,
                                101                 :                :                 Int32GetDatum(1));
                                102                 :                : 
                                103                 :          12159 :     scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, true,
                                104                 :                :                               NULL, 2, key);
                                105                 :          12159 :     tuple = systable_getnext(scan);
                                106         [ +  + ]:          12159 :     if (HeapTupleIsValid(tuple))
                                107                 :                :     {
                                108                 :           9513 :         Form_pg_inherits form = (Form_pg_inherits) GETSTRUCT(tuple);
                                109                 :                : 
                                110                 :                :         /* Let caller know of partition being detached */
 1116                           111         [ +  + ]:           9513 :         if (form->inhdetachpending)
                                112                 :             37 :             *detach_pending = true;
 2192                           113                 :           9513 :         result = form->inhparent;
                                114                 :                :     }
                                115                 :                : 
                                116                 :          12159 :     systable_endscan(scan);
                                117                 :                : 
                                118                 :          12159 :     return result;
                                119                 :                : }
                                120                 :                : 
                                121                 :                : /*
                                122                 :                :  * get_partition_ancestors
                                123                 :                :  *      Obtain ancestors of given relation
                                124                 :                :  *
                                125                 :                :  * Returns a list of ancestors of the given relation.  The list is ordered:
                                126                 :                :  * The first element is the immediate parent and the last one is the topmost
                                127                 :                :  * parent in the partition hierarchy.
                                128                 :                :  *
                                129                 :                :  * Note: Because this function assumes that the relation whose OID is passed
                                130                 :                :  * as an argument and each ancestor will have precisely one parent, it should
                                131                 :                :  * only be called when it is known that the relation is a partition.
                                132                 :                :  */
                                133                 :                : List *
                                134                 :           2647 : get_partition_ancestors(Oid relid)
                                135                 :                : {
                                136                 :           2647 :     List       *result = NIL;
                                137                 :                :     Relation    inhRel;
                                138                 :                : 
 1910 andres@anarazel.de        139                 :           2647 :     inhRel = table_open(InheritsRelationId, AccessShareLock);
                                140                 :                : 
 2192 alvherre@alvh.no-ip.      141                 :           2647 :     get_partition_ancestors_worker(inhRel, relid, &result);
                                142                 :                : 
 1910 andres@anarazel.de        143                 :           2647 :     table_close(inhRel, AccessShareLock);
                                144                 :                : 
 2192 alvherre@alvh.no-ip.      145                 :           2647 :     return result;
                                146                 :                : }
                                147                 :                : 
                                148                 :                : /*
                                149                 :                :  * get_partition_ancestors_worker
                                150                 :                :  *      recursive worker for get_partition_ancestors
                                151                 :                :  */
                                152                 :                : static void
                                153                 :           5530 : get_partition_ancestors_worker(Relation inhRel, Oid relid, List **ancestors)
                                154                 :                : {
                                155                 :                :     Oid         parentOid;
                                156                 :                :     bool        detach_pending;
                                157                 :                : 
                                158                 :                :     /*
                                159                 :                :      * Recursion ends at the topmost level, ie., when there's no parent; also
                                160                 :                :      * when the partition is being detached.
                                161                 :                :      */
 1116                           162                 :           5530 :     parentOid = get_partition_parent_worker(inhRel, relid, &detach_pending);
                                163   [ +  +  +  + ]:           5530 :     if (parentOid == InvalidOid || detach_pending)
 2192                           164                 :           2647 :         return;
                                165                 :                : 
                                166                 :           2883 :     *ancestors = lappend_oid(*ancestors, parentOid);
                                167                 :           2883 :     get_partition_ancestors_worker(inhRel, parentOid, ancestors);
                                168                 :                : }
                                169                 :                : 
                                170                 :                : /*
                                171                 :                :  * index_get_partition
                                172                 :                :  *      Return the OID of index of the given partition that is a child
                                173                 :                :  *      of the given index, or InvalidOid if there isn't one.
                                174                 :                :  */
                                175                 :                : Oid
 1852                           176                 :            534 : index_get_partition(Relation partition, Oid indexId)
                                177                 :                : {
                                178                 :            534 :     List       *idxlist = RelationGetIndexList(partition);
                                179                 :                :     ListCell   *l;
                                180                 :                : 
                                181   [ +  -  +  +  :            808 :     foreach(l, idxlist)
                                              +  + ]
                                182                 :                :     {
                                183                 :            637 :         Oid         partIdx = lfirst_oid(l);
                                184                 :                :         HeapTuple   tup;
                                185                 :                :         Form_pg_class classForm;
                                186                 :                :         bool        ispartition;
                                187                 :                : 
                                188                 :            637 :         tup = SearchSysCache1(RELOID, ObjectIdGetDatum(partIdx));
 1806 tgl@sss.pgh.pa.us         189         [ -  + ]:            637 :         if (!HeapTupleIsValid(tup))
 1852 alvherre@alvh.no-ip.      190         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for relation %u", partIdx);
 1852 alvherre@alvh.no-ip.      191                 :CBC         637 :         classForm = (Form_pg_class) GETSTRUCT(tup);
                                192                 :            637 :         ispartition = classForm->relispartition;
                                193                 :            637 :         ReleaseSysCache(tup);
                                194         [ +  + ]:            637 :         if (!ispartition)
                                195                 :            259 :             continue;
 1116                           196         [ +  + ]:            378 :         if (get_partition_parent(partIdx, false) == indexId)
                                197                 :                :         {
 1852                           198                 :            363 :             list_free(idxlist);
                                199                 :            363 :             return partIdx;
                                200                 :                :         }
                                201                 :                :     }
                                202                 :                : 
 1255                           203                 :            171 :     list_free(idxlist);
 1852                           204                 :            171 :     return InvalidOid;
                                205                 :                : }
                                206                 :                : 
                                207                 :                : /*
                                208                 :                :  * map_partition_varattnos - maps varattnos of all Vars in 'expr' (that have
                                209                 :                :  * varno 'fromrel_varno') from the attnums of 'from_rel' to the attnums of
                                210                 :                :  * 'to_rel', each of which may be either a leaf partition or a partitioned
                                211                 :                :  * table, but both of which must be from the same partitioning hierarchy.
                                212                 :                :  *
                                213                 :                :  * We need this because even though all of the same column names must be
                                214                 :                :  * present in all relations in the hierarchy, and they must also have the
                                215                 :                :  * same types, the attnums may be different.
                                216                 :                :  *
                                217                 :                :  * Note: this will work on any node tree, so really the argument and result
                                218                 :                :  * should be declared "Node *".  But a substantial majority of the callers
                                219                 :                :  * are working on Lists, so it's less messy to do the casts internally.
                                220                 :                :  */
                                221                 :                : List *
 2192                           222                 :           4068 : map_partition_varattnos(List *expr, int fromrel_varno,
                                223                 :                :                         Relation to_rel, Relation from_rel)
                                224                 :                : {
                                225         [ +  + ]:           4068 :     if (expr != NIL)
                                226                 :                :     {
                                227                 :                :         AttrMap    *part_attmap;
                                228                 :                :         bool        found_whole_row;
                                229                 :                : 
 1579 michael@paquier.xyz       230                 :           3376 :         part_attmap = build_attrmap_by_name(RelationGetDescr(to_rel),
                                231                 :                :                                             RelationGetDescr(from_rel),
                                232                 :                :                                             false);
 2192 alvherre@alvh.no-ip.      233                 :           3376 :         expr = (List *) map_variable_attnos((Node *) expr,
                                234                 :                :                                             fromrel_varno, 0,
                                235                 :                :                                             part_attmap,
                                236                 :           3376 :                                             RelationGetForm(to_rel)->reltype,
                                237                 :                :                                             &found_whole_row);
                                238                 :                :         /* Since we provided a to_rowtype, we may ignore found_whole_row. */
                                239                 :                :     }
                                240                 :                : 
                                241                 :           4068 :     return expr;
                                242                 :                : }
                                243                 :                : 
                                244                 :                : /*
                                245                 :                :  * Checks if any of the 'attnums' is a partition key attribute for rel
                                246                 :                :  *
                                247                 :                :  * Sets *used_in_expr if any of the 'attnums' is found to be referenced in some
                                248                 :                :  * partition key expression.  It's possible for a column to be both used
                                249                 :                :  * directly and as part of an expression; if that happens, *used_in_expr may
                                250                 :                :  * end up as either true or false.  That's OK for current uses of this
                                251                 :                :  * function, because *used_in_expr is only used to tailor the error message
                                252                 :                :  * text.
                                253                 :                :  */
                                254                 :                : bool
                                255                 :           9505 : has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
                                256                 :                : {
                                257                 :                :     PartitionKey key;
                                258                 :                :     int         partnatts;
                                259                 :                :     List       *partexprs;
                                260                 :                :     ListCell   *partexprs_item;
                                261                 :                :     int         i;
                                262                 :                : 
 2292 rhaas@postgresql.org      263   [ +  +  +  + ]:           9505 :     if (attnums == NULL || rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
                                264                 :           8391 :         return false;
                                265                 :                : 
                                266                 :           1114 :     key = RelationGetPartitionKey(rel);
                                267                 :           1114 :     partnatts = get_partition_natts(key);
                                268                 :           1114 :     partexprs = get_partition_exprs(key);
                                269                 :                : 
                                270                 :           1114 :     partexprs_item = list_head(partexprs);
                                271         [ +  + ]:           1769 :     for (i = 0; i < partnatts; i++)
                                272                 :                :     {
                                273                 :           1193 :         AttrNumber  partattno = get_partition_col_attnum(key, i);
                                274                 :                : 
                                275         [ +  + ]:           1193 :         if (partattno != 0)
                                276                 :                :         {
                                277         [ +  + ]:           1138 :             if (bms_is_member(partattno - FirstLowInvalidHeapAttributeNumber,
                                278                 :                :                               attnums))
                                279                 :                :             {
                                280         [ +  + ]:            520 :                 if (used_in_expr)
                                281                 :             15 :                     *used_in_expr = false;
                                282                 :            520 :                 return true;
                                283                 :                :             }
                                284                 :                :         }
                                285                 :                :         else
                                286                 :                :         {
                                287                 :                :             /* Arbitrary expression */
                                288                 :             55 :             Node       *expr = (Node *) lfirst(partexprs_item);
                                289                 :             55 :             Bitmapset  *expr_attrs = NULL;
                                290                 :                : 
                                291                 :                :             /* Find all attributes referenced */
                                292                 :             55 :             pull_varattnos(expr, 1, &expr_attrs);
 1735 tgl@sss.pgh.pa.us         293                 :             55 :             partexprs_item = lnext(partexprs, partexprs_item);
                                294                 :                : 
 2292 rhaas@postgresql.org      295         [ +  + ]:             55 :             if (bms_overlap(attnums, expr_attrs))
                                296                 :                :             {
                                297         [ +  + ]:             18 :                 if (used_in_expr)
                                298                 :              9 :                     *used_in_expr = true;
                                299                 :             18 :                 return true;
                                300                 :                :             }
                                301                 :                :         }
                                302                 :                :     }
                                303                 :                : 
                                304                 :            576 :     return false;
                                305                 :                : }
                                306                 :                : 
                                307                 :                : /*
                                308                 :                :  * get_default_partition_oid
                                309                 :                :  *
                                310                 :                :  * Given a relation OID, return the OID of the default partition, if one
                                311                 :                :  * exists.  Use get_default_oid_from_partdesc where possible, for
                                312                 :                :  * efficiency.
                                313                 :                :  */
                                314                 :                : Oid
 2410                           315                 :           4840 : get_default_partition_oid(Oid parentId)
                                316                 :                : {
                                317                 :                :     HeapTuple   tuple;
                                318                 :           4840 :     Oid         defaultPartId = InvalidOid;
                                319                 :                : 
                                320                 :           4840 :     tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId));
                                321                 :                : 
                                322         [ +  - ]:           4840 :     if (HeapTupleIsValid(tuple))
                                323                 :                :     {
                                324                 :                :         Form_pg_partitioned_table part_table_form;
                                325                 :                : 
                                326                 :           4840 :         part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
                                327                 :           4840 :         defaultPartId = part_table_form->partdefid;
 2360                           328                 :           4840 :         ReleaseSysCache(tuple);
                                329                 :                :     }
                                330                 :                : 
 2410                           331                 :           4840 :     return defaultPartId;
                                332                 :                : }
                                333                 :                : 
                                334                 :                : /*
                                335                 :                :  * update_default_partition_oid
                                336                 :                :  *
                                337                 :                :  * Update pg_partitioned_table.partdefid with a new default partition OID.
                                338                 :                :  */
                                339                 :                : void
                                340                 :            651 : update_default_partition_oid(Oid parentId, Oid defaultPartId)
                                341                 :                : {
                                342                 :                :     HeapTuple   tuple;
                                343                 :                :     Relation    pg_partitioned_table;
                                344                 :                :     Form_pg_partitioned_table part_table_form;
                                345                 :                : 
 1910 andres@anarazel.de        346                 :            651 :     pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
                                347                 :                : 
 2410 rhaas@postgresql.org      348                 :            651 :     tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId));
                                349                 :                : 
                                350         [ -  + ]:            651 :     if (!HeapTupleIsValid(tuple))
 2410 rhaas@postgresql.org      351         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for partition key of relation %u",
                                352                 :                :              parentId);
                                353                 :                : 
 2410 rhaas@postgresql.org      354                 :CBC         651 :     part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
                                355                 :            651 :     part_table_form->partdefid = defaultPartId;
                                356                 :            651 :     CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple);
                                357                 :                : 
                                358                 :            651 :     heap_freetuple(tuple);
 1910 andres@anarazel.de        359                 :            651 :     table_close(pg_partitioned_table, RowExclusiveLock);
 2410 rhaas@postgresql.org      360                 :            651 : }
                                361                 :                : 
                                362                 :                : /*
                                363                 :                :  * get_proposed_default_constraint
                                364                 :                :  *
                                365                 :                :  * This function returns the negation of new_part_constraints, which
                                366                 :                :  * would be an integral part of the default partition constraints after
                                367                 :                :  * addition of the partition to which the new_part_constraints belongs.
                                368                 :                :  */
                                369                 :                : List *
                                370                 :            247 : get_proposed_default_constraint(List *new_part_constraints)
                                371                 :                : {
                                372                 :                :     Expr       *defPartConstraint;
                                373                 :                : 
                                374                 :            247 :     defPartConstraint = make_ands_explicit(new_part_constraints);
                                375                 :                : 
                                376                 :                :     /*
                                377                 :                :      * Derive the partition constraints of default partition by negating the
                                378                 :                :      * given partition constraints. The partition constraint never evaluates
                                379                 :                :      * to NULL, so negating it like this is safe.
                                380                 :                :      */
                                381                 :            247 :     defPartConstraint = makeBoolExpr(NOT_EXPR,
                                382                 :            247 :                                      list_make1(defPartConstraint),
                                383                 :                :                                      -1);
                                384                 :                : 
                                385                 :                :     /* Simplify, to put the negated expression into canonical form */
                                386                 :                :     defPartConstraint =
                                387                 :            247 :         (Expr *) eval_const_expressions(NULL,
                                388                 :                :                                         (Node *) defPartConstraint);
 2226 tgl@sss.pgh.pa.us         389                 :            247 :     defPartConstraint = canonicalize_qual(defPartConstraint, true);
                                390                 :                : 
                                391                 :            247 :     return make_ands_implicit(defPartConstraint);
                                392                 :                : }
        

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