LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_attrdef.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 96.2 % 104 100 4 100
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 5 5 5
Baseline: lcov-20250906-005545-baseline Branches: 50.0 % 28 14 14 14
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 9 9 9
(360..) days: 95.8 % 95 91 4 91
Function coverage date bins:
(360..) days: 100.0 % 5 5 5
Branch coverage date bins:
(360..) days: 50.0 % 28 14 14 14

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pg_attrdef.c
                                  4                 :                :  *    routines to support manipulation of the pg_attrdef relation
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/catalog/pg_attrdef.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/relation.h"
                                 18                 :                : #include "access/table.h"
                                 19                 :                : #include "catalog/dependency.h"
                                 20                 :                : #include "catalog/indexing.h"
                                 21                 :                : #include "catalog/objectaccess.h"
                                 22                 :                : #include "catalog/pg_attrdef.h"
                                 23                 :                : #include "utils/builtins.h"
                                 24                 :                : #include "utils/fmgroids.h"
                                 25                 :                : #include "utils/rel.h"
                                 26                 :                : #include "utils/syscache.h"
                                 27                 :                : 
                                 28                 :                : 
                                 29                 :                : /*
                                 30                 :                :  * Store a default expression for column attnum of relation rel.
                                 31                 :                :  *
                                 32                 :                :  * Returns the OID of the new pg_attrdef tuple.
                                 33                 :                :  */
                                 34                 :                : Oid
 1265 tgl@sss.pgh.pa.us          35                 :CBC        2386 : StoreAttrDefault(Relation rel, AttrNumber attnum,
                                 36                 :                :                  Node *expr, bool is_internal)
                                 37                 :                : {
                                 38                 :                :     char       *adbin;
                                 39                 :                :     Relation    adrel;
                                 40                 :                :     HeapTuple   tuple;
                                 41                 :                :     Datum       values[Natts_pg_attrdef];
                                 42                 :                :     static bool nulls[Natts_pg_attrdef] = {false, false, false, false};
                                 43                 :                :     Relation    attrrel;
                                 44                 :                :     HeapTuple   atttup;
                                 45                 :                :     Form_pg_attribute attStruct;
  187                            46                 :           2386 :     Datum       valuesAtt[Natts_pg_attribute] = {0};
                                 47                 :           2386 :     bool        nullsAtt[Natts_pg_attribute] = {0};
                                 48                 :           2386 :     bool        replacesAtt[Natts_pg_attribute] = {0};
                                 49                 :                :     char        attgenerated;
                                 50                 :                :     Oid         attrdefOid;
                                 51                 :                :     ObjectAddress colobject,
                                 52                 :                :                 defobject;
                                 53                 :                : 
 1265                            54                 :           2386 :     adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
                                 55                 :                : 
                                 56                 :                :     /*
                                 57                 :                :      * Flatten expression to string form for storage.
                                 58                 :                :      */
                                 59                 :           2386 :     adbin = nodeToString(expr);
                                 60                 :                : 
                                 61                 :                :     /*
                                 62                 :                :      * Make the pg_attrdef entry.
                                 63                 :                :      */
                                 64                 :           2386 :     attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
                                 65                 :                :                                     Anum_pg_attrdef_oid);
                                 66                 :           2386 :     values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
  187                            67                 :           2386 :     values[Anum_pg_attrdef_adrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
                                 68                 :           2386 :     values[Anum_pg_attrdef_adnum - 1] = Int16GetDatum(attnum);
 1265                            69                 :           2386 :     values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
                                 70                 :                : 
                                 71                 :           2386 :     tuple = heap_form_tuple(adrel->rd_att, values, nulls);
                                 72                 :           2386 :     CatalogTupleInsert(adrel, tuple);
                                 73                 :                : 
                                 74                 :           2386 :     defobject.classId = AttrDefaultRelationId;
                                 75                 :           2386 :     defobject.objectId = attrdefOid;
                                 76                 :           2386 :     defobject.objectSubId = 0;
                                 77                 :                : 
                                 78                 :           2386 :     table_close(adrel, RowExclusiveLock);
                                 79                 :                : 
                                 80                 :                :     /* now can free some of the stuff allocated above */
                                 81                 :           2386 :     pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
                                 82                 :           2386 :     heap_freetuple(tuple);
                                 83                 :           2386 :     pfree(adbin);
                                 84                 :                : 
                                 85                 :                :     /*
                                 86                 :                :      * Update the pg_attribute entry for the column to show that a default
                                 87                 :                :      * exists.
                                 88                 :                :      */
                                 89                 :           2386 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
                                 90                 :           2386 :     atttup = SearchSysCacheCopy2(ATTNUM,
                                 91                 :                :                                  ObjectIdGetDatum(RelationGetRelid(rel)),
                                 92                 :                :                                  Int16GetDatum(attnum));
                                 93         [ -  + ]:           2386 :     if (!HeapTupleIsValid(atttup))
 1265 tgl@sss.pgh.pa.us          94         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                                 95                 :                :              attnum, RelationGetRelid(rel));
 1265 tgl@sss.pgh.pa.us          96                 :CBC        2386 :     attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
                                 97                 :           2386 :     attgenerated = attStruct->attgenerated;
                                 98                 :                : 
  187                            99                 :           2386 :     valuesAtt[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(true);
                                100                 :           2386 :     replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
                                101                 :                : 
                                102                 :           2386 :     atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
                                103                 :                :                                valuesAtt, nullsAtt, replacesAtt);
                                104                 :                : 
                                105                 :           2386 :     CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
                                106                 :                : 
 1265                           107                 :           2386 :     table_close(attrrel, RowExclusiveLock);
                                108                 :           2386 :     heap_freetuple(atttup);
                                109                 :                : 
                                110                 :                :     /*
                                111                 :                :      * Make a dependency so that the pg_attrdef entry goes away if the column
                                112                 :                :      * (or whole table) is deleted.  In the case of a generated column, make
                                113                 :                :      * it an internal dependency to prevent the default expression from being
                                114                 :                :      * deleted separately.
                                115                 :                :      */
                                116                 :           2386 :     colobject.classId = RelationRelationId;
                                117                 :           2386 :     colobject.objectId = RelationGetRelid(rel);
                                118                 :           2386 :     colobject.objectSubId = attnum;
                                119                 :                : 
                                120         [ +  + ]:           2386 :     recordDependencyOn(&defobject, &colobject,
                                121                 :                :                        attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
                                122                 :                : 
                                123                 :                :     /*
                                124                 :                :      * Record dependencies on objects used in the expression, too.
                                125                 :                :      */
                                126                 :           2386 :     recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
                                127                 :                :                                     DEPENDENCY_NORMAL,
                                128                 :                :                                     DEPENDENCY_NORMAL, false);
                                129                 :                : 
                                130                 :                :     /*
                                131                 :                :      * Post creation hook for attribute defaults.
                                132                 :                :      *
                                133                 :                :      * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
                                134                 :                :      * couple of deletion/creation of the attribute's default entry, so the
                                135                 :                :      * callee should check existence of an older version of this entry if it
                                136                 :                :      * needs to distinguish.
                                137                 :                :      */
                                138         [ -  + ]:           2380 :     InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
                                139                 :                :                                   RelationGetRelid(rel), attnum, is_internal);
                                140                 :                : 
                                141                 :           2380 :     return attrdefOid;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : 
                                145                 :                : /*
                                146                 :                :  *      RemoveAttrDefault
                                147                 :                :  *
                                148                 :                :  * If the specified relation/attribute has a default, remove it.
                                149                 :                :  * (If no default, raise error if complain is true, else return quietly.)
                                150                 :                :  */
                                151                 :                : void
                                152                 :            448 : RemoveAttrDefault(Oid relid, AttrNumber attnum,
                                153                 :                :                   DropBehavior behavior, bool complain, bool internal)
                                154                 :                : {
                                155                 :                :     Relation    attrdef_rel;
                                156                 :                :     ScanKeyData scankeys[2];
                                157                 :                :     SysScanDesc scan;
                                158                 :                :     HeapTuple   tuple;
                                159                 :            448 :     bool        found = false;
                                160                 :                : 
                                161                 :            448 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
                                162                 :                : 
                                163                 :            448 :     ScanKeyInit(&scankeys[0],
                                164                 :                :                 Anum_pg_attrdef_adrelid,
                                165                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                                166                 :                :                 ObjectIdGetDatum(relid));
                                167                 :            448 :     ScanKeyInit(&scankeys[1],
                                168                 :                :                 Anum_pg_attrdef_adnum,
                                169                 :                :                 BTEqualStrategyNumber, F_INT2EQ,
                                170                 :                :                 Int16GetDatum(attnum));
                                171                 :                : 
                                172                 :            448 :     scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
                                173                 :                :                               NULL, 2, scankeys);
                                174                 :                : 
                                175                 :                :     /* There should be at most one matching tuple, but we loop anyway */
                                176         [ +  + ]:            756 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                                177                 :                :     {
                                178                 :                :         ObjectAddress object;
                                179                 :            308 :         Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
                                180                 :                : 
                                181                 :            308 :         object.classId = AttrDefaultRelationId;
                                182                 :            308 :         object.objectId = attrtuple->oid;
                                183                 :            308 :         object.objectSubId = 0;
                                184                 :                : 
                                185                 :            308 :         performDeletion(&object, behavior,
                                186                 :                :                         internal ? PERFORM_DELETION_INTERNAL : 0);
                                187                 :                : 
                                188                 :            308 :         found = true;
                                189                 :                :     }
                                190                 :                : 
                                191                 :            448 :     systable_endscan(scan);
                                192                 :            448 :     table_close(attrdef_rel, RowExclusiveLock);
                                193                 :                : 
                                194   [ +  +  -  + ]:            448 :     if (complain && !found)
 1265 tgl@sss.pgh.pa.us         195         [ #  # ]:UBC           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                                196                 :                :              relid, attnum);
 1265 tgl@sss.pgh.pa.us         197                 :CBC         448 : }
                                198                 :                : 
                                199                 :                : /*
                                200                 :                :  *      RemoveAttrDefaultById
                                201                 :                :  *
                                202                 :                :  * Remove a pg_attrdef entry specified by OID.  This is the guts of
                                203                 :                :  * attribute-default removal.  Note it should be called via performDeletion,
                                204                 :                :  * not directly.
                                205                 :                :  */
                                206                 :                : void
                                207                 :           1650 : RemoveAttrDefaultById(Oid attrdefId)
                                208                 :                : {
                                209                 :                :     Relation    attrdef_rel;
                                210                 :                :     Relation    attr_rel;
                                211                 :                :     Relation    myrel;
                                212                 :                :     ScanKeyData scankeys[1];
                                213                 :                :     SysScanDesc scan;
                                214                 :                :     HeapTuple   tuple;
                                215                 :                :     Oid         myrelid;
                                216                 :                :     AttrNumber  myattnum;
                                217                 :                : 
                                218                 :                :     /* Grab an appropriate lock on the pg_attrdef relation */
                                219                 :           1650 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
                                220                 :                : 
                                221                 :                :     /* Find the pg_attrdef tuple */
                                222                 :           1650 :     ScanKeyInit(&scankeys[0],
                                223                 :                :                 Anum_pg_attrdef_oid,
                                224                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                                225                 :                :                 ObjectIdGetDatum(attrdefId));
                                226                 :                : 
                                227                 :           1650 :     scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
                                228                 :                :                               NULL, 1, scankeys);
                                229                 :                : 
                                230                 :           1650 :     tuple = systable_getnext(scan);
                                231         [ -  + ]:           1650 :     if (!HeapTupleIsValid(tuple))
 1265 tgl@sss.pgh.pa.us         232         [ #  # ]:UBC           0 :         elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
                                233                 :                : 
 1265 tgl@sss.pgh.pa.us         234                 :CBC        1650 :     myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
                                235                 :           1650 :     myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
                                236                 :                : 
                                237                 :                :     /* Get an exclusive lock on the relation owning the attribute */
                                238                 :           1650 :     myrel = relation_open(myrelid, AccessExclusiveLock);
                                239                 :                : 
                                240                 :                :     /* Now we can delete the pg_attrdef row */
                                241                 :           1650 :     CatalogTupleDelete(attrdef_rel, &tuple->t_self);
                                242                 :                : 
                                243                 :           1650 :     systable_endscan(scan);
                                244                 :           1650 :     table_close(attrdef_rel, RowExclusiveLock);
                                245                 :                : 
                                246                 :                :     /* Fix the pg_attribute row */
                                247                 :           1650 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
                                248                 :                : 
                                249                 :           1650 :     tuple = SearchSysCacheCopy2(ATTNUM,
                                250                 :                :                                 ObjectIdGetDatum(myrelid),
                                251                 :                :                                 Int16GetDatum(myattnum));
                                252         [ -  + ]:           1650 :     if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
 1265 tgl@sss.pgh.pa.us         253         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                                254                 :                :              myattnum, myrelid);
                                255                 :                : 
 1265 tgl@sss.pgh.pa.us         256                 :CBC        1650 :     ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
                                257                 :                : 
                                258                 :           1650 :     CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                                259                 :                : 
                                260                 :                :     /*
                                261                 :                :      * Our update of the pg_attribute row will force a relcache rebuild, so
                                262                 :                :      * there's nothing else to do here.
                                263                 :                :      */
                                264                 :           1650 :     table_close(attr_rel, RowExclusiveLock);
                                265                 :                : 
                                266                 :                :     /* Keep lock on attribute's rel until end of xact */
                                267                 :           1650 :     relation_close(myrel, NoLock);
                                268                 :           1650 : }
                                269                 :                : 
                                270                 :                : 
                                271                 :                : /*
                                272                 :                :  * Get the pg_attrdef OID of the default expression for a column
                                273                 :                :  * identified by relation OID and column number.
                                274                 :                :  *
                                275                 :                :  * Returns InvalidOid if there is no such pg_attrdef entry.
                                276                 :                :  */
                                277                 :                : Oid
                                278                 :            127 : GetAttrDefaultOid(Oid relid, AttrNumber attnum)
                                279                 :                : {
                                280                 :            127 :     Oid         result = InvalidOid;
                                281                 :                :     Relation    attrdef;
                                282                 :                :     ScanKeyData keys[2];
                                283                 :                :     SysScanDesc scan;
                                284                 :                :     HeapTuple   tup;
                                285                 :                : 
                                286                 :            127 :     attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
                                287                 :            127 :     ScanKeyInit(&keys[0],
                                288                 :                :                 Anum_pg_attrdef_adrelid,
                                289                 :                :                 BTEqualStrategyNumber,
                                290                 :                :                 F_OIDEQ,
                                291                 :                :                 ObjectIdGetDatum(relid));
                                292                 :            127 :     ScanKeyInit(&keys[1],
                                293                 :                :                 Anum_pg_attrdef_adnum,
                                294                 :                :                 BTEqualStrategyNumber,
                                295                 :                :                 F_INT2EQ,
                                296                 :                :                 Int16GetDatum(attnum));
                                297                 :            127 :     scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
                                298                 :                :                               NULL, 2, keys);
                                299                 :                : 
                                300         [ +  - ]:            127 :     if (HeapTupleIsValid(tup = systable_getnext(scan)))
                                301                 :                :     {
                                302                 :            127 :         Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
                                303                 :                : 
                                304                 :            127 :         result = atdform->oid;
                                305                 :                :     }
                                306                 :                : 
                                307                 :            127 :     systable_endscan(scan);
                                308                 :            127 :     table_close(attrdef, AccessShareLock);
                                309                 :                : 
                                310                 :            127 :     return result;
                                311                 :                : }
                                312                 :                : 
                                313                 :                : /*
                                314                 :                :  * Given a pg_attrdef OID, return the relation OID and column number of
                                315                 :                :  * the owning column (represented as an ObjectAddress for convenience).
                                316                 :                :  *
                                317                 :                :  * Returns InvalidObjectAddress if there is no such pg_attrdef entry.
                                318                 :                :  */
                                319                 :                : ObjectAddress
                                320                 :           1623 : GetAttrDefaultColumnAddress(Oid attrdefoid)
                                321                 :                : {
                                322                 :           1623 :     ObjectAddress result = InvalidObjectAddress;
                                323                 :                :     Relation    attrdef;
                                324                 :                :     ScanKeyData skey[1];
                                325                 :                :     SysScanDesc scan;
                                326                 :                :     HeapTuple   tup;
                                327                 :                : 
                                328                 :           1623 :     attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
                                329                 :           1623 :     ScanKeyInit(&skey[0],
                                330                 :                :                 Anum_pg_attrdef_oid,
                                331                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                                332                 :                :                 ObjectIdGetDatum(attrdefoid));
                                333                 :           1623 :     scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true,
                                334                 :                :                               NULL, 1, skey);
                                335                 :                : 
                                336         [ +  + ]:           1623 :     if (HeapTupleIsValid(tup = systable_getnext(scan)))
                                337                 :                :     {
                                338                 :           1614 :         Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
                                339                 :                : 
                                340                 :           1614 :         result.classId = RelationRelationId;
                                341                 :           1614 :         result.objectId = atdform->adrelid;
                                342                 :           1614 :         result.objectSubId = atdform->adnum;
                                343                 :                :     }
                                344                 :                : 
                                345                 :           1623 :     systable_endscan(scan);
                                346                 :           1623 :     table_close(attrdef, AccessShareLock);
                                347                 :                : 
                                348                 :           1623 :     return result;
                                349                 :                : }
        

Generated by: LCOV version 2.4-beta