LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_attrdef.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.2 % 130 125 2 2 1 2 54 3 66 2 52 5
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 4 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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-2023, 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/genam.h"
      18                 : #include "access/relation.h"
      19                 : #include "access/table.h"
      20                 : #include "catalog/catalog.h"
      21                 : #include "catalog/dependency.h"
      22                 : #include "catalog/indexing.h"
      23                 : #include "catalog/objectaccess.h"
      24                 : #include "catalog/pg_attrdef.h"
      25                 : #include "executor/executor.h"
      26                 : #include "optimizer/optimizer.h"
      27                 : #include "utils/array.h"
      28                 : #include "utils/builtins.h"
      29                 : #include "utils/fmgroids.h"
      30                 : #include "utils/rel.h"
      31                 : #include "utils/syscache.h"
      32                 : 
      33                 : 
      34                 : /*
      35                 :  * Store a default expression for column attnum of relation rel.
      36                 :  *
      37                 :  * Returns the OID of the new pg_attrdef tuple.
      38                 :  *
      39                 :  * add_column_mode must be true if we are storing the default for a new
      40                 :  * attribute, and false if it's for an already existing attribute. The reason
      41                 :  * for this is that the missing value must never be updated after it is set,
      42                 :  * which can only be when a column is added to the table. Otherwise we would
      43                 :  * in effect be changing existing tuples.
      44                 :  */
      45                 : Oid
      46 CBC        1717 : StoreAttrDefault(Relation rel, AttrNumber attnum,
      47                 :                  Node *expr, bool is_internal, bool add_column_mode)
      48                 : {
      49                 :     char       *adbin;
      50                 :     Relation    adrel;
      51                 :     HeapTuple   tuple;
      52                 :     Datum       values[4];
      53                 :     static bool nulls[4] = {false, false, false, false};
      54                 :     Relation    attrrel;
      55                 :     HeapTuple   atttup;
      56                 :     Form_pg_attribute attStruct;
      57                 :     char        attgenerated;
      58                 :     Oid         attrdefOid;
      59                 :     ObjectAddress colobject,
      60                 :                 defobject;
      61                 : 
      62            1717 :     adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
      63                 : 
      64                 :     /*
      65                 :      * Flatten expression to string form for storage.
      66                 :      */
      67            1717 :     adbin = nodeToString(expr);
      68                 : 
      69                 :     /*
      70                 :      * Make the pg_attrdef entry.
      71                 :      */
      72            1717 :     attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
      73                 :                                     Anum_pg_attrdef_oid);
      74            1717 :     values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
      75            1717 :     values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
      76            1717 :     values[Anum_pg_attrdef_adnum - 1] = attnum;
      77            1717 :     values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
      78                 : 
      79            1717 :     tuple = heap_form_tuple(adrel->rd_att, values, nulls);
      80            1717 :     CatalogTupleInsert(adrel, tuple);
      81                 : 
      82            1717 :     defobject.classId = AttrDefaultRelationId;
      83            1717 :     defobject.objectId = attrdefOid;
      84            1717 :     defobject.objectSubId = 0;
      85                 : 
      86            1717 :     table_close(adrel, RowExclusiveLock);
      87                 : 
      88                 :     /* now can free some of the stuff allocated above */
      89            1717 :     pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
      90            1717 :     heap_freetuple(tuple);
      91            1717 :     pfree(adbin);
      92                 : 
      93                 :     /*
      94                 :      * Update the pg_attribute entry for the column to show that a default
      95                 :      * exists.
      96                 :      */
      97            1717 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
      98            1717 :     atttup = SearchSysCacheCopy2(ATTNUM,
      99                 :                                  ObjectIdGetDatum(RelationGetRelid(rel)),
     100                 :                                  Int16GetDatum(attnum));
     101            1717 :     if (!HeapTupleIsValid(atttup))
     102 UBC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     103                 :              attnum, RelationGetRelid(rel));
     104 CBC        1717 :     attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
     105            1717 :     attgenerated = attStruct->attgenerated;
     106            1717 :     if (!attStruct->atthasdef)
     107                 :     {
     108                 :         Form_pg_attribute defAttStruct;
     109                 : 
     110                 :         ExprState  *exprState;
     111            1717 :         Expr       *expr2 = (Expr *) expr;
     112            1717 :         EState     *estate = NULL;
     113                 :         ExprContext *econtext;
     114 GNC        1717 :         Datum       valuesAtt[Natts_pg_attribute] = {0};
     115            1717 :         bool        nullsAtt[Natts_pg_attribute] = {0};
     116            1717 :         bool        replacesAtt[Natts_pg_attribute] = {0};
     117 CBC        1717 :         Datum       missingval = (Datum) 0;
     118            1717 :         bool        missingIsNull = true;
     119                 : 
     120            1717 :         valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
     121 GIC        1717 :         replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
     122                 : 
     123 CBC        1717 :         if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
     124 ECB             :             !attgenerated)
     125                 :         {
     126 CBC         220 :             expr2 = expression_planner(expr2);
     127 GIC         220 :             estate = CreateExecutorState();
     128 CBC         220 :             exprState = ExecPrepareExpr(expr2, estate);
     129 GIC         220 :             econtext = GetPerTupleExprContext(estate);
     130                 : 
     131 CBC         220 :             missingval = ExecEvalExpr(exprState, econtext,
     132                 :                                       &missingIsNull);
     133 ECB             : 
     134 GIC         220 :             FreeExecutorState(estate);
     135 ECB             : 
     136 GIC         220 :             defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
     137                 : 
     138 GBC         220 :             if (missingIsNull)
     139                 :             {
     140                 :                 /* if the default evaluates to NULL, just store a NULL array */
     141 UIC           0 :                 missingval = (Datum) 0;
     142                 :             }
     143 ECB             :             else
     144                 :             {
     145                 :                 /* otherwise make a one-element array of the value */
     146 CBC         220 :                 missingval = PointerGetDatum(construct_array(&missingval,
     147 ECB             :                                                              1,
     148                 :                                                              defAttStruct->atttypid,
     149 GIC         220 :                                                              defAttStruct->attlen,
     150             220 :                                                              defAttStruct->attbyval,
     151 CBC         220 :                                                              defAttStruct->attalign));
     152 ECB             :             }
     153                 : 
     154 CBC         220 :             valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
     155             220 :             replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
     156 GIC         220 :             valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
     157 CBC         220 :             replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
     158 GIC         220 :             nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
     159                 :         }
     160 CBC        1717 :         atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
     161                 :                                    valuesAtt, nullsAtt, replacesAtt);
     162 ECB             : 
     163 CBC        1717 :         CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
     164                 : 
     165            1717 :         if (!missingIsNull)
     166             220 :             pfree(DatumGetPointer(missingval));
     167                 :     }
     168 GIC        1717 :     table_close(attrrel, RowExclusiveLock);
     169            1717 :     heap_freetuple(atttup);
     170                 : 
     171                 :     /*
     172                 :      * Make a dependency so that the pg_attrdef entry goes away if the column
     173                 :      * (or whole table) is deleted.  In the case of a generated column, make
     174 ECB             :      * it an internal dependency to prevent the default expression from being
     175                 :      * deleted separately.
     176                 :      */
     177 GIC        1717 :     colobject.classId = RelationRelationId;
     178 CBC        1717 :     colobject.objectId = RelationGetRelid(rel);
     179 GIC        1717 :     colobject.objectSubId = attnum;
     180                 : 
     181            1717 :     recordDependencyOn(&defobject, &colobject,
     182                 :                        attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
     183                 : 
     184 ECB             :     /*
     185                 :      * Record dependencies on objects used in the expression, too.
     186                 :      */
     187 GIC        1717 :     recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
     188                 :                                     DEPENDENCY_NORMAL,
     189                 :                                     DEPENDENCY_NORMAL, false);
     190                 : 
     191                 :     /*
     192                 :      * Post creation hook for attribute defaults.
     193                 :      *
     194                 :      * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
     195                 :      * couple of deletion/creation of the attribute's default entry, so the
     196 ECB             :      * callee should check existence of an older version of this entry if it
     197                 :      * needs to distinguish.
     198                 :      */
     199 CBC        1717 :     InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
     200                 :                                   RelationGetRelid(rel), attnum, is_internal);
     201                 : 
     202 GIC        1717 :     return attrdefOid;
     203                 : }
     204                 : 
     205                 : 
     206                 : /*
     207                 :  *      RemoveAttrDefault
     208                 :  *
     209                 :  * If the specified relation/attribute has a default, remove it.
     210 ECB             :  * (If no default, raise error if complain is true, else return quietly.)
     211                 :  */
     212                 : void
     213 GIC         308 : RemoveAttrDefault(Oid relid, AttrNumber attnum,
     214                 :                   DropBehavior behavior, bool complain, bool internal)
     215                 : {
     216                 :     Relation    attrdef_rel;
     217 ECB             :     ScanKeyData scankeys[2];
     218                 :     SysScanDesc scan;
     219                 :     HeapTuple   tuple;
     220 GIC         308 :     bool        found = false;
     221 ECB             : 
     222 GIC         308 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
     223                 : 
     224             308 :     ScanKeyInit(&scankeys[0],
     225 ECB             :                 Anum_pg_attrdef_adrelid,
     226                 :                 BTEqualStrategyNumber, F_OIDEQ,
     227                 :                 ObjectIdGetDatum(relid));
     228 GIC         308 :     ScanKeyInit(&scankeys[1],
     229                 :                 Anum_pg_attrdef_adnum,
     230 ECB             :                 BTEqualStrategyNumber, F_INT2EQ,
     231                 :                 Int16GetDatum(attnum));
     232                 : 
     233 GIC         308 :     scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
     234 ECB             :                               NULL, 2, scankeys);
     235                 : 
     236                 :     /* There should be at most one matching tuple, but we loop anyway */
     237 CBC         505 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
     238                 :     {
     239 ECB             :         ObjectAddress object;
     240 CBC         197 :         Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
     241 ECB             : 
     242 GIC         197 :         object.classId = AttrDefaultRelationId;
     243 CBC         197 :         object.objectId = attrtuple->oid;
     244 GIC         197 :         object.objectSubId = 0;
     245                 : 
     246 CBC         197 :         performDeletion(&object, behavior,
     247                 :                         internal ? PERFORM_DELETION_INTERNAL : 0);
     248                 : 
     249             197 :         found = true;
     250 ECB             :     }
     251                 : 
     252 CBC         308 :     systable_endscan(scan);
     253 GBC         308 :     table_close(attrdef_rel, RowExclusiveLock);
     254                 : 
     255 CBC         308 :     if (complain && !found)
     256 UIC           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
     257                 :              relid, attnum);
     258 GIC         308 : }
     259                 : 
     260                 : /*
     261                 :  *      RemoveAttrDefaultById
     262                 :  *
     263                 :  * Remove a pg_attrdef entry specified by OID.  This is the guts of
     264                 :  * attribute-default removal.  Note it should be called via performDeletion,
     265 ECB             :  * not directly.
     266                 :  */
     267                 : void
     268 GIC        1296 : RemoveAttrDefaultById(Oid attrdefId)
     269                 : {
     270                 :     Relation    attrdef_rel;
     271                 :     Relation    attr_rel;
     272                 :     Relation    myrel;
     273                 :     ScanKeyData scankeys[1];
     274                 :     SysScanDesc scan;
     275                 :     HeapTuple   tuple;
     276                 :     Oid         myrelid;
     277 ECB             :     AttrNumber  myattnum;
     278                 : 
     279                 :     /* Grab an appropriate lock on the pg_attrdef relation */
     280 CBC        1296 :     attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
     281                 : 
     282                 :     /* Find the pg_attrdef tuple */
     283 GIC        1296 :     ScanKeyInit(&scankeys[0],
     284                 :                 Anum_pg_attrdef_oid,
     285 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
     286                 :                 ObjectIdGetDatum(attrdefId));
     287                 : 
     288 CBC        1296 :     scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
     289 ECB             :                               NULL, 1, scankeys);
     290 EUB             : 
     291 GIC        1296 :     tuple = systable_getnext(scan);
     292 CBC        1296 :     if (!HeapTupleIsValid(tuple))
     293 LBC           0 :         elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
     294                 : 
     295 GIC        1296 :     myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
     296 CBC        1296 :     myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
     297                 : 
     298                 :     /* Get an exclusive lock on the relation owning the attribute */
     299            1296 :     myrel = relation_open(myrelid, AccessExclusiveLock);
     300                 : 
     301 ECB             :     /* Now we can delete the pg_attrdef row */
     302 CBC        1296 :     CatalogTupleDelete(attrdef_rel, &tuple->t_self);
     303                 : 
     304 GIC        1296 :     systable_endscan(scan);
     305 CBC        1296 :     table_close(attrdef_rel, RowExclusiveLock);
     306                 : 
     307 ECB             :     /* Fix the pg_attribute row */
     308 GIC        1296 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
     309                 : 
     310 CBC        1296 :     tuple = SearchSysCacheCopy2(ATTNUM,
     311 EUB             :                                 ObjectIdGetDatum(myrelid),
     312                 :                                 Int16GetDatum(myattnum));
     313 GIC        1296 :     if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
     314 LBC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     315                 :              myattnum, myrelid);
     316 ECB             : 
     317 GIC        1296 :     ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
     318                 : 
     319            1296 :     CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
     320                 : 
     321                 :     /*
     322 ECB             :      * Our update of the pg_attribute row will force a relcache rebuild, so
     323                 :      * there's nothing else to do here.
     324                 :      */
     325 CBC        1296 :     table_close(attr_rel, RowExclusiveLock);
     326 ECB             : 
     327                 :     /* Keep lock on attribute's rel until end of xact */
     328 GIC        1296 :     relation_close(myrel, NoLock);
     329            1296 : }
     330                 : 
     331                 : 
     332                 : /*
     333                 :  * Get the pg_attrdef OID of the default expression for a column
     334                 :  * identified by relation OID and column number.
     335                 :  *
     336 ECB             :  * Returns InvalidOid if there is no such pg_attrdef entry.
     337                 :  */
     338                 : Oid
     339 GIC          19 : GetAttrDefaultOid(Oid relid, AttrNumber attnum)
     340                 : {
     341              19 :     Oid         result = InvalidOid;
     342                 :     Relation    attrdef;
     343                 :     ScanKeyData keys[2];
     344 ECB             :     SysScanDesc scan;
     345                 :     HeapTuple   tup;
     346                 : 
     347 GIC          19 :     attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
     348              19 :     ScanKeyInit(&keys[0],
     349                 :                 Anum_pg_attrdef_adrelid,
     350 ECB             :                 BTEqualStrategyNumber,
     351                 :                 F_OIDEQ,
     352                 :                 ObjectIdGetDatum(relid));
     353 GIC          19 :     ScanKeyInit(&keys[1],
     354                 :                 Anum_pg_attrdef_adnum,
     355 ECB             :                 BTEqualStrategyNumber,
     356                 :                 F_INT2EQ,
     357                 :                 Int16GetDatum(attnum));
     358 CBC          19 :     scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
     359                 :                               NULL, 2, keys);
     360 ECB             : 
     361 GIC          19 :     if (HeapTupleIsValid(tup = systable_getnext(scan)))
     362 ECB             :     {
     363 GIC          19 :         Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
     364                 : 
     365 CBC          19 :         result = atdform->oid;
     366 ECB             :     }
     367                 : 
     368 CBC          19 :     systable_endscan(scan);
     369 GIC          19 :     table_close(attrdef, AccessShareLock);
     370                 : 
     371              19 :     return result;
     372                 : }
     373                 : 
     374                 : /*
     375                 :  * Given a pg_attrdef OID, return the relation OID and column number of
     376                 :  * the owning column (represented as an ObjectAddress for convenience).
     377                 :  *
     378 ECB             :  * Returns InvalidObjectAddress if there is no such pg_attrdef entry.
     379                 :  */
     380                 : ObjectAddress
     381 GIC        1284 : GetAttrDefaultColumnAddress(Oid attrdefoid)
     382                 : {
     383            1284 :     ObjectAddress result = InvalidObjectAddress;
     384                 :     Relation    attrdef;
     385                 :     ScanKeyData skey[1];
     386 ECB             :     SysScanDesc scan;
     387                 :     HeapTuple   tup;
     388                 : 
     389 GIC        1284 :     attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
     390            1284 :     ScanKeyInit(&skey[0],
     391 ECB             :                 Anum_pg_attrdef_oid,
     392                 :                 BTEqualStrategyNumber, F_OIDEQ,
     393                 :                 ObjectIdGetDatum(attrdefoid));
     394 CBC        1284 :     scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true,
     395                 :                               NULL, 1, skey);
     396 ECB             : 
     397 GIC        1284 :     if (HeapTupleIsValid(tup = systable_getnext(scan)))
     398 ECB             :     {
     399 CBC        1275 :         Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
     400 ECB             : 
     401 GIC        1275 :         result.classId = RelationRelationId;
     402            1275 :         result.objectId = atdform->adrelid;
     403 CBC        1275 :         result.objectSubId = atdform->adnum;
     404 ECB             :     }
     405                 : 
     406 CBC        1284 :     systable_endscan(scan);
     407 GIC        1284 :     table_close(attrdef, AccessShareLock);
     408                 : 
     409            1284 :     return result;
     410                 : }
        

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