LCOV - code coverage report
Current view: top level - src/backend/commands - comment.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 95.9 % 194 186
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 76.8 % 82 63

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * comment.c
       4                 :             :  *
       5                 :             :  * PostgreSQL object comments utility code.
       6                 :             :  *
       7                 :             :  * Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/backend/commands/comment.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : 
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "access/genam.h"
      18                 :             : #include "access/htup_details.h"
      19                 :             : #include "access/relation.h"
      20                 :             : #include "access/table.h"
      21                 :             : #include "catalog/indexing.h"
      22                 :             : #include "catalog/objectaddress.h"
      23                 :             : #include "catalog/pg_database.h"
      24                 :             : #include "catalog/pg_description.h"
      25                 :             : #include "catalog/pg_shdescription.h"
      26                 :             : #include "commands/comment.h"
      27                 :             : #include "miscadmin.h"
      28                 :             : #include "utils/builtins.h"
      29                 :             : #include "utils/fmgroids.h"
      30                 :             : #include "utils/rel.h"
      31                 :             : 
      32                 :             : 
      33                 :             : /*
      34                 :             :  * CommentObject --
      35                 :             :  *
      36                 :             :  * This routine is used to add the associated comment into
      37                 :             :  * pg_description for the object specified by the given SQL command.
      38                 :             :  */
      39                 :             : ObjectAddress
      40                 :         196 : CommentObject(CommentStmt *stmt)
      41                 :             : {
      42                 :         196 :         Relation        relation;
      43                 :         196 :         ObjectAddress address = InvalidObjectAddress;
      44                 :             : 
      45                 :             :         /*
      46                 :             :          * When loading a dump, we may see a COMMENT ON DATABASE for the old name
      47                 :             :          * of the database.  Erroring out would prevent pg_restore from completing
      48                 :             :          * (which is really pg_restore's fault, but for now we will work around
      49                 :             :          * the problem here).  Consensus is that the best fix is to treat wrong
      50                 :             :          * database name as a WARNING not an ERROR; hence, the following special
      51                 :             :          * case.
      52                 :             :          */
      53         [ +  + ]:         196 :         if (stmt->objtype == OBJECT_DATABASE)
      54                 :             :         {
      55                 :           4 :                 char       *database = strVal(stmt->object);
      56                 :             : 
      57         [ +  - ]:           4 :                 if (!OidIsValid(get_database_oid(database, true)))
      58                 :             :                 {
      59   [ #  #  #  # ]:           0 :                         ereport(WARNING,
      60                 :             :                                         (errcode(ERRCODE_UNDEFINED_DATABASE),
      61                 :             :                                          errmsg("database \"%s\" does not exist", database)));
      62                 :           0 :                         return address;
      63                 :             :                 }
      64         [ -  + ]:           4 :         }
      65                 :             : 
      66                 :             :         /*
      67                 :             :          * Translate the parser representation that identifies this object into an
      68                 :             :          * ObjectAddress.  get_object_address() will throw an error if the object
      69                 :             :          * does not exist, and will also acquire a lock on the target to guard
      70                 :             :          * against concurrent DROP operations.
      71                 :             :          */
      72                 :         196 :         address = get_object_address(stmt->objtype, stmt->object,
      73                 :             :                                                                  &relation, ShareUpdateExclusiveLock, false);
      74                 :             : 
      75                 :             :         /* Require ownership of the target object. */
      76                 :         392 :         check_object_ownership(GetUserId(), stmt->objtype, address,
      77                 :         196 :                                                    stmt->object, relation);
      78                 :             : 
      79                 :             :         /* Perform other integrity checks as needed. */
      80         [ +  + ]:         196 :         switch (stmt->objtype)
      81                 :             :         {
      82                 :             :                 case OBJECT_COLUMN:
      83                 :             : 
      84                 :             :                         /*
      85                 :             :                          * Allow comments only on columns of tables, views, materialized
      86                 :             :                          * views, composite types, and foreign tables (which are the only
      87                 :             :                          * relkinds for which pg_dump will dump per-column comments).  In
      88                 :             :                          * particular we wish to disallow comments on index columns,
      89                 :             :                          * because the naming of an index's columns may change across PG
      90                 :             :                          * versions, so dumping per-column comments could create reload
      91                 :             :                          * failures.
      92                 :             :                          */
      93         [ +  + ]:          33 :                         if (relation->rd_rel->relkind != RELKIND_RELATION &&
      94         [ +  - ]:           9 :                                 relation->rd_rel->relkind != RELKIND_VIEW &&
      95         [ +  - ]:           9 :                                 relation->rd_rel->relkind != RELKIND_MATVIEW &&
      96         [ +  + ]:           9 :                                 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
      97   [ +  +  +  - ]:           7 :                                 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
      98                 :           3 :                                 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
      99   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     100                 :             :                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     101                 :             :                                                  errmsg("cannot set comment on relation \"%s\"",
     102                 :             :                                                                 RelationGetRelationName(relation)),
     103                 :             :                                                  errdetail_relkind_not_supported(relation->rd_rel->relkind)));
     104                 :          33 :                         break;
     105                 :             :                 default:
     106                 :         163 :                         break;
     107                 :             :         }
     108                 :             : 
     109                 :             :         /*
     110                 :             :          * Databases, tablespaces, and roles are cluster-wide objects, so any
     111                 :             :          * comments on those objects are recorded in the shared pg_shdescription
     112                 :             :          * catalog.  Comments on all other objects are recorded in pg_description.
     113                 :             :          */
     114         [ +  + ]:         196 :         if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE
     115   [ +  -  +  + ]:         192 :                 || stmt->objtype == OBJECT_ROLE)
     116                 :           5 :                 CreateSharedComments(address.objectId, address.classId, stmt->comment);
     117                 :             :         else
     118                 :         382 :                 CreateComments(address.objectId, address.classId, address.objectSubId,
     119                 :         191 :                                            stmt->comment);
     120                 :             : 
     121                 :             :         /*
     122                 :             :          * If get_object_address() opened the relation for us, we close it to keep
     123                 :             :          * the reference count correct - but we retain any locks acquired by
     124                 :             :          * get_object_address() until commit time, to guard against concurrent
     125                 :             :          * activity.
     126                 :             :          */
     127         [ +  + ]:         196 :         if (relation != NULL)
     128                 :          97 :                 relation_close(relation, NoLock);
     129                 :             : 
     130                 :         196 :         return address;
     131                 :         196 : }
     132                 :             : 
     133                 :             : /*
     134                 :             :  * CreateComments --
     135                 :             :  *
     136                 :             :  * Create a comment for the specified object descriptor.  Inserts a new
     137                 :             :  * pg_description tuple, or replaces an existing one with the same key.
     138                 :             :  *
     139                 :             :  * If the comment given is null or an empty string, instead delete any
     140                 :             :  * existing comment for the specified key.
     141                 :             :  */
     142                 :             : void
     143                 :        1066 : CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
     144                 :             : {
     145                 :        1066 :         Relation        description;
     146                 :        1066 :         ScanKeyData skey[3];
     147                 :        1066 :         SysScanDesc sd;
     148                 :        1066 :         HeapTuple       oldtuple;
     149                 :        1066 :         HeapTuple       newtuple = NULL;
     150                 :        1066 :         Datum           values[Natts_pg_description];
     151                 :        1066 :         bool            nulls[Natts_pg_description];
     152                 :        1066 :         bool            replaces[Natts_pg_description];
     153                 :        1066 :         int                     i;
     154                 :             : 
     155                 :             :         /* Reduce empty-string to NULL case */
     156   [ +  +  +  - ]:        1066 :         if (comment != NULL && strlen(comment) == 0)
     157                 :           0 :                 comment = NULL;
     158                 :             : 
     159                 :             :         /* Prepare to form or update a tuple, if necessary */
     160         [ +  + ]:        1066 :         if (comment != NULL)
     161                 :             :         {
     162         [ +  + ]:        5250 :                 for (i = 0; i < Natts_pg_description; i++)
     163                 :             :                 {
     164                 :        4200 :                         nulls[i] = false;
     165                 :        4200 :                         replaces[i] = true;
     166                 :        4200 :                 }
     167                 :        1050 :                 values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(oid);
     168                 :        1050 :                 values[Anum_pg_description_classoid - 1] = ObjectIdGetDatum(classoid);
     169                 :        1050 :                 values[Anum_pg_description_objsubid - 1] = Int32GetDatum(subid);
     170                 :        1050 :                 values[Anum_pg_description_description - 1] = CStringGetTextDatum(comment);
     171                 :        1050 :         }
     172                 :             : 
     173                 :             :         /* Use the index to search for a matching old tuple */
     174                 :             : 
     175                 :        2132 :         ScanKeyInit(&skey[0],
     176                 :             :                                 Anum_pg_description_objoid,
     177                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     178                 :        1066 :                                 ObjectIdGetDatum(oid));
     179                 :        2132 :         ScanKeyInit(&skey[1],
     180                 :             :                                 Anum_pg_description_classoid,
     181                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     182                 :        1066 :                                 ObjectIdGetDatum(classoid));
     183                 :        2132 :         ScanKeyInit(&skey[2],
     184                 :             :                                 Anum_pg_description_objsubid,
     185                 :             :                                 BTEqualStrategyNumber, F_INT4EQ,
     186                 :        1066 :                                 Int32GetDatum(subid));
     187                 :             : 
     188                 :        1066 :         description = table_open(DescriptionRelationId, RowExclusiveLock);
     189                 :             : 
     190                 :        2132 :         sd = systable_beginscan(description, DescriptionObjIndexId, true,
     191                 :        1066 :                                                         NULL, 3, skey);
     192                 :             : 
     193         [ +  + ]:        1066 :         while ((oldtuple = systable_getnext(sd)) != NULL)
     194                 :             :         {
     195                 :             :                 /* Found the old tuple, so delete or update it */
     196                 :             : 
     197         [ +  + ]:          18 :                 if (comment == NULL)
     198                 :          16 :                         CatalogTupleDelete(description, &oldtuple->t_self);
     199                 :             :                 else
     200                 :             :                 {
     201                 :           4 :                         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(description), values,
     202                 :           2 :                                                                                  nulls, replaces);
     203                 :           2 :                         CatalogTupleUpdate(description, &oldtuple->t_self, newtuple);
     204                 :             :                 }
     205                 :             : 
     206                 :          18 :                 break;                                  /* Assume there can be only one match */
     207                 :             :         }
     208                 :             : 
     209                 :        1066 :         systable_endscan(sd);
     210                 :             : 
     211                 :             :         /* If we didn't find an old tuple, insert a new one */
     212                 :             : 
     213   [ +  +  +  + ]:        1066 :         if (newtuple == NULL && comment != NULL)
     214                 :             :         {
     215                 :        2096 :                 newtuple = heap_form_tuple(RelationGetDescr(description),
     216                 :        1048 :                                                                    values, nulls);
     217                 :        1048 :                 CatalogTupleInsert(description, newtuple);
     218                 :        1048 :         }
     219                 :             : 
     220         [ +  + ]:        1066 :         if (newtuple != NULL)
     221                 :        1050 :                 heap_freetuple(newtuple);
     222                 :             : 
     223                 :             :         /* Done */
     224                 :             : 
     225                 :        1066 :         table_close(description, NoLock);
     226                 :        1066 : }
     227                 :             : 
     228                 :             : /*
     229                 :             :  * CreateSharedComments --
     230                 :             :  *
     231                 :             :  * Create a comment for the specified shared object descriptor.  Inserts a
     232                 :             :  * new pg_shdescription tuple, or replaces an existing one with the same key.
     233                 :             :  *
     234                 :             :  * If the comment given is null or an empty string, instead delete any
     235                 :             :  * existing comment for the specified key.
     236                 :             :  */
     237                 :             : void
     238                 :           5 : CreateSharedComments(Oid oid, Oid classoid, const char *comment)
     239                 :             : {
     240                 :           5 :         Relation        shdescription;
     241                 :           5 :         ScanKeyData skey[2];
     242                 :           5 :         SysScanDesc sd;
     243                 :           5 :         HeapTuple       oldtuple;
     244                 :           5 :         HeapTuple       newtuple = NULL;
     245                 :           5 :         Datum           values[Natts_pg_shdescription];
     246                 :           5 :         bool            nulls[Natts_pg_shdescription];
     247                 :           5 :         bool            replaces[Natts_pg_shdescription];
     248                 :           5 :         int                     i;
     249                 :             : 
     250                 :             :         /* Reduce empty-string to NULL case */
     251   [ +  +  +  - ]:           5 :         if (comment != NULL && strlen(comment) == 0)
     252                 :           0 :                 comment = NULL;
     253                 :             : 
     254                 :             :         /* Prepare to form or update a tuple, if necessary */
     255         [ +  + ]:           5 :         if (comment != NULL)
     256                 :             :         {
     257         [ +  + ]:          16 :                 for (i = 0; i < Natts_pg_shdescription; i++)
     258                 :             :                 {
     259                 :          12 :                         nulls[i] = false;
     260                 :          12 :                         replaces[i] = true;
     261                 :          12 :                 }
     262                 :           4 :                 values[Anum_pg_shdescription_objoid - 1] = ObjectIdGetDatum(oid);
     263                 :           4 :                 values[Anum_pg_shdescription_classoid - 1] = ObjectIdGetDatum(classoid);
     264                 :           4 :                 values[Anum_pg_shdescription_description - 1] = CStringGetTextDatum(comment);
     265                 :           4 :         }
     266                 :             : 
     267                 :             :         /* Use the index to search for a matching old tuple */
     268                 :             : 
     269                 :          10 :         ScanKeyInit(&skey[0],
     270                 :             :                                 Anum_pg_shdescription_objoid,
     271                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     272                 :           5 :                                 ObjectIdGetDatum(oid));
     273                 :          10 :         ScanKeyInit(&skey[1],
     274                 :             :                                 Anum_pg_shdescription_classoid,
     275                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     276                 :           5 :                                 ObjectIdGetDatum(classoid));
     277                 :             : 
     278                 :           5 :         shdescription = table_open(SharedDescriptionRelationId, RowExclusiveLock);
     279                 :             : 
     280                 :          10 :         sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
     281                 :           5 :                                                         NULL, 2, skey);
     282                 :             : 
     283         [ +  + ]:           5 :         while ((oldtuple = systable_getnext(sd)) != NULL)
     284                 :             :         {
     285                 :             :                 /* Found the old tuple, so delete or update it */
     286                 :             : 
     287         [ -  + ]:           1 :                 if (comment == NULL)
     288                 :           1 :                         CatalogTupleDelete(shdescription, &oldtuple->t_self);
     289                 :             :                 else
     290                 :             :                 {
     291                 :           0 :                         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(shdescription),
     292                 :           0 :                                                                                  values, nulls, replaces);
     293                 :           0 :                         CatalogTupleUpdate(shdescription, &oldtuple->t_self, newtuple);
     294                 :             :                 }
     295                 :             : 
     296                 :           1 :                 break;                                  /* Assume there can be only one match */
     297                 :             :         }
     298                 :             : 
     299                 :           5 :         systable_endscan(sd);
     300                 :             : 
     301                 :             :         /* If we didn't find an old tuple, insert a new one */
     302                 :             : 
     303   [ +  -  +  + ]:           5 :         if (newtuple == NULL && comment != NULL)
     304                 :             :         {
     305                 :           8 :                 newtuple = heap_form_tuple(RelationGetDescr(shdescription),
     306                 :           4 :                                                                    values, nulls);
     307                 :           4 :                 CatalogTupleInsert(shdescription, newtuple);
     308                 :           4 :         }
     309                 :             : 
     310         [ +  + ]:           5 :         if (newtuple != NULL)
     311                 :           4 :                 heap_freetuple(newtuple);
     312                 :             : 
     313                 :             :         /* Done */
     314                 :             : 
     315                 :           5 :         table_close(shdescription, NoLock);
     316                 :           5 : }
     317                 :             : 
     318                 :             : /*
     319                 :             :  * DeleteComments -- remove comments for an object
     320                 :             :  *
     321                 :             :  * If subid is nonzero then only comments matching it will be removed.
     322                 :             :  * If subid is zero, all comments matching the oid/classoid will be removed
     323                 :             :  * (this corresponds to deleting a whole object).
     324                 :             :  */
     325                 :             : void
     326                 :       24705 : DeleteComments(Oid oid, Oid classoid, int32 subid)
     327                 :             : {
     328                 :       24705 :         Relation        description;
     329                 :       24705 :         ScanKeyData skey[3];
     330                 :       24705 :         int                     nkeys;
     331                 :       24705 :         SysScanDesc sd;
     332                 :       24705 :         HeapTuple       oldtuple;
     333                 :             : 
     334                 :             :         /* Use the index to search for all matching old tuples */
     335                 :             : 
     336                 :       49410 :         ScanKeyInit(&skey[0],
     337                 :             :                                 Anum_pg_description_objoid,
     338                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     339                 :       24705 :                                 ObjectIdGetDatum(oid));
     340                 :       49410 :         ScanKeyInit(&skey[1],
     341                 :             :                                 Anum_pg_description_classoid,
     342                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     343                 :       24705 :                                 ObjectIdGetDatum(classoid));
     344                 :             : 
     345         [ +  + ]:       24705 :         if (subid != 0)
     346                 :             :         {
     347                 :         612 :                 ScanKeyInit(&skey[2],
     348                 :             :                                         Anum_pg_description_objsubid,
     349                 :             :                                         BTEqualStrategyNumber, F_INT4EQ,
     350                 :         306 :                                         Int32GetDatum(subid));
     351                 :         306 :                 nkeys = 3;
     352                 :         306 :         }
     353                 :             :         else
     354                 :       24399 :                 nkeys = 2;
     355                 :             : 
     356                 :       24705 :         description = table_open(DescriptionRelationId, RowExclusiveLock);
     357                 :             : 
     358                 :       49410 :         sd = systable_beginscan(description, DescriptionObjIndexId, true,
     359                 :       24705 :                                                         NULL, nkeys, skey);
     360                 :             : 
     361         [ +  + ]:       24794 :         while ((oldtuple = systable_getnext(sd)) != NULL)
     362                 :          89 :                 CatalogTupleDelete(description, &oldtuple->t_self);
     363                 :             : 
     364                 :             :         /* Done */
     365                 :             : 
     366                 :       24705 :         systable_endscan(sd);
     367                 :       24705 :         table_close(description, RowExclusiveLock);
     368                 :       24705 : }
     369                 :             : 
     370                 :             : /*
     371                 :             :  * DeleteSharedComments -- remove comments for a shared object
     372                 :             :  */
     373                 :             : void
     374                 :         210 : DeleteSharedComments(Oid oid, Oid classoid)
     375                 :             : {
     376                 :         210 :         Relation        shdescription;
     377                 :         210 :         ScanKeyData skey[2];
     378                 :         210 :         SysScanDesc sd;
     379                 :         210 :         HeapTuple       oldtuple;
     380                 :             : 
     381                 :             :         /* Use the index to search for all matching old tuples */
     382                 :             : 
     383                 :         420 :         ScanKeyInit(&skey[0],
     384                 :             :                                 Anum_pg_shdescription_objoid,
     385                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     386                 :         210 :                                 ObjectIdGetDatum(oid));
     387                 :         420 :         ScanKeyInit(&skey[1],
     388                 :             :                                 Anum_pg_shdescription_classoid,
     389                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     390                 :         210 :                                 ObjectIdGetDatum(classoid));
     391                 :             : 
     392                 :         210 :         shdescription = table_open(SharedDescriptionRelationId, RowExclusiveLock);
     393                 :             : 
     394                 :         420 :         sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
     395                 :         210 :                                                         NULL, 2, skey);
     396                 :             : 
     397         [ +  + ]:         211 :         while ((oldtuple = systable_getnext(sd)) != NULL)
     398                 :           1 :                 CatalogTupleDelete(shdescription, &oldtuple->t_self);
     399                 :             : 
     400                 :             :         /* Done */
     401                 :             : 
     402                 :         210 :         systable_endscan(sd);
     403                 :         210 :         table_close(shdescription, RowExclusiveLock);
     404                 :         210 : }
     405                 :             : 
     406                 :             : /*
     407                 :             :  * GetComment -- get the comment for an object, or null if not found.
     408                 :             :  */
     409                 :             : char *
     410                 :         271 : GetComment(Oid oid, Oid classoid, int32 subid)
     411                 :             : {
     412                 :         271 :         Relation        description;
     413                 :         271 :         ScanKeyData skey[3];
     414                 :         271 :         SysScanDesc sd;
     415                 :         271 :         TupleDesc       tupdesc;
     416                 :         271 :         HeapTuple       tuple;
     417                 :         271 :         char       *comment;
     418                 :             : 
     419                 :             :         /* Use the index to search for a matching old tuple */
     420                 :             : 
     421                 :         542 :         ScanKeyInit(&skey[0],
     422                 :             :                                 Anum_pg_description_objoid,
     423                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     424                 :         271 :                                 ObjectIdGetDatum(oid));
     425                 :         542 :         ScanKeyInit(&skey[1],
     426                 :             :                                 Anum_pg_description_classoid,
     427                 :             :                                 BTEqualStrategyNumber, F_OIDEQ,
     428                 :         271 :                                 ObjectIdGetDatum(classoid));
     429                 :         542 :         ScanKeyInit(&skey[2],
     430                 :             :                                 Anum_pg_description_objsubid,
     431                 :             :                                 BTEqualStrategyNumber, F_INT4EQ,
     432                 :         271 :                                 Int32GetDatum(subid));
     433                 :             : 
     434                 :         271 :         description = table_open(DescriptionRelationId, AccessShareLock);
     435                 :         271 :         tupdesc = RelationGetDescr(description);
     436                 :             : 
     437                 :         542 :         sd = systable_beginscan(description, DescriptionObjIndexId, true,
     438                 :         271 :                                                         NULL, 3, skey);
     439                 :             : 
     440                 :         271 :         comment = NULL;
     441         [ +  + ]:         271 :         while ((tuple = systable_getnext(sd)) != NULL)
     442                 :             :         {
     443                 :          58 :                 Datum           value;
     444                 :          58 :                 bool            isnull;
     445                 :             : 
     446                 :             :                 /* Found the tuple, get description field */
     447                 :          58 :                 value = heap_getattr(tuple, Anum_pg_description_description, tupdesc, &isnull);
     448         [ -  + ]:          58 :                 if (!isnull)
     449                 :          58 :                         comment = TextDatumGetCString(value);
     450                 :             :                 break;                                  /* Assume there can be only one match */
     451                 :          58 :         }
     452                 :             : 
     453                 :         271 :         systable_endscan(sd);
     454                 :             : 
     455                 :             :         /* Done */
     456                 :         271 :         table_close(description, AccessShareLock);
     457                 :             : 
     458                 :         542 :         return comment;
     459                 :         271 : }
        

Generated by: LCOV version 2.3.2-1