LCOV - differential code coverage report
Current view: top level - src/backend/catalog - partition.c (source / functions) Coverage Total Hit LBC UBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.3 % 107 103 1 3 34 69 1 33
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 10 10 4 1 5 4
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 96.3 % 107 103 1 3 34 69 1 33
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 71.4 % 14 10 4 1 5 4

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

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