LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_collation.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 80.7 % 83 67
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.0 % 64 32

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_collation.c
       4                 :             :  *        routines to support manipulation of the pg_collation relation
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/catalog/pg_collation.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "access/htup_details.h"
      18                 :             : #include "access/table.h"
      19                 :             : #include "catalog/catalog.h"
      20                 :             : #include "catalog/dependency.h"
      21                 :             : #include "catalog/indexing.h"
      22                 :             : #include "catalog/objectaccess.h"
      23                 :             : #include "catalog/pg_collation.h"
      24                 :             : #include "catalog/pg_namespace.h"
      25                 :             : #include "mb/pg_wchar.h"
      26                 :             : #include "utils/builtins.h"
      27                 :             : #include "utils/rel.h"
      28                 :             : #include "utils/syscache.h"
      29                 :             : 
      30                 :             : 
      31                 :             : /*
      32                 :             :  * CollationCreate
      33                 :             :  *
      34                 :             :  * Add a new tuple to pg_collation.
      35                 :             :  *
      36                 :             :  * if_not_exists: if true, don't fail on duplicate name, just print a notice
      37                 :             :  * and return InvalidOid.
      38                 :             :  * quiet: if true, don't fail on duplicate name, just silently return
      39                 :             :  * InvalidOid (overrides if_not_exists).
      40                 :             :  */
      41                 :             : Oid
      42                 :        1221 : CollationCreate(const char *collname, Oid collnamespace,
      43                 :             :                                 Oid collowner,
      44                 :             :                                 char collprovider,
      45                 :             :                                 bool collisdeterministic,
      46                 :             :                                 int32 collencoding,
      47                 :             :                                 const char *collcollate, const char *collctype,
      48                 :             :                                 const char *colllocale,
      49                 :             :                                 const char *collicurules,
      50                 :             :                                 const char *collversion,
      51                 :             :                                 bool if_not_exists,
      52                 :             :                                 bool quiet)
      53                 :             : {
      54                 :        1221 :         Relation        rel;
      55                 :        1221 :         TupleDesc       tupDesc;
      56                 :        1221 :         HeapTuple       tup;
      57                 :        1221 :         Datum           values[Natts_pg_collation];
      58                 :        1221 :         bool            nulls[Natts_pg_collation];
      59                 :        1221 :         NameData        name_name;
      60                 :        1221 :         Oid                     oid;
      61                 :        1221 :         ObjectAddress myself,
      62                 :             :                                 referenced;
      63                 :             : 
      64         [ +  - ]:        1221 :         Assert(collname);
      65         [ +  - ]:        1221 :         Assert(collnamespace);
      66         [ +  - ]:        1221 :         Assert(collowner);
      67   [ +  +  +  -  :        1221 :         Assert((collprovider == COLLPROVIDER_LIBC &&
          +  -  -  +  +  
                      - ]
      68                 :             :                         collcollate && collctype && !colllocale) ||
      69                 :             :                    (collprovider != COLLPROVIDER_LIBC &&
      70                 :             :                         !collcollate && !collctype && colllocale));
      71                 :             : 
      72                 :             :         /*
      73                 :             :          * Make sure there is no existing collation of same name & encoding.
      74                 :             :          *
      75                 :             :          * This would be caught by the unique index anyway; we're just giving a
      76                 :             :          * friendlier error message.  The unique index provides a backstop against
      77                 :             :          * race conditions.
      78                 :             :          */
      79                 :        1221 :         oid = GetSysCacheOid3(COLLNAMEENCNSP,
      80                 :             :                                                   Anum_pg_collation_oid,
      81                 :             :                                                   PointerGetDatum(collname),
      82                 :             :                                                   Int32GetDatum(collencoding),
      83                 :             :                                                   ObjectIdGetDatum(collnamespace));
      84         [ +  + ]:        1221 :         if (OidIsValid(oid))
      85                 :             :         {
      86         [ +  + ]:          55 :                 if (quiet)
      87                 :          54 :                         return InvalidOid;
      88         [ -  + ]:           1 :                 else if (if_not_exists)
      89                 :             :                 {
      90                 :             :                         /*
      91                 :             :                          * If we are in an extension script, insist that the pre-existing
      92                 :             :                          * object be a member of the extension, to avoid security risks.
      93                 :             :                          */
      94                 :           0 :                         ObjectAddressSet(myself, CollationRelationId, oid);
      95                 :           0 :                         checkMembershipInCurrentExtension(&myself);
      96                 :             : 
      97                 :             :                         /* OK to skip */
      98   [ #  #  #  #  :           0 :                         ereport(NOTICE,
                   #  # ]
      99                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
     100                 :             :                                          collencoding == -1
     101                 :             :                                          ? errmsg("collation \"%s\" already exists, skipping",
     102                 :             :                                                           collname)
     103                 :             :                                          : errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping",
     104                 :             :                                                           collname, pg_encoding_to_char(collencoding))));
     105                 :           0 :                         return InvalidOid;
     106                 :             :                 }
     107                 :             :                 else
     108   [ +  -  +  -  :           1 :                         ereport(ERROR,
                   +  - ]
     109                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
     110                 :             :                                          collencoding == -1
     111                 :             :                                          ? errmsg("collation \"%s\" already exists",
     112                 :             :                                                           collname)
     113                 :             :                                          : errmsg("collation \"%s\" for encoding \"%s\" already exists",
     114                 :             :                                                           collname, pg_encoding_to_char(collencoding))));
     115                 :           0 :         }
     116                 :             : 
     117                 :             :         /* open pg_collation; see below about the lock level */
     118                 :        1166 :         rel = table_open(CollationRelationId, ShareRowExclusiveLock);
     119                 :             : 
     120                 :             :         /*
     121                 :             :          * Also forbid a specific-encoding collation shadowing an any-encoding
     122                 :             :          * collation, or an any-encoding collation being shadowed (see
     123                 :             :          * get_collation_name()).  This test is not backed up by the unique index,
     124                 :             :          * so we take a ShareRowExclusiveLock earlier, to protect against
     125                 :             :          * concurrent changes fooling this check.
     126                 :             :          */
     127         [ +  + ]:        1166 :         if (collencoding == -1)
     128                 :         897 :                 oid = GetSysCacheOid3(COLLNAMEENCNSP,
     129                 :             :                                                           Anum_pg_collation_oid,
     130                 :             :                                                           PointerGetDatum(collname),
     131                 :             :                                                           Int32GetDatum(GetDatabaseEncoding()),
     132                 :             :                                                           ObjectIdGetDatum(collnamespace));
     133                 :             :         else
     134                 :         269 :                 oid = GetSysCacheOid3(COLLNAMEENCNSP,
     135                 :             :                                                           Anum_pg_collation_oid,
     136                 :             :                                                           PointerGetDatum(collname),
     137                 :             :                                                           Int32GetDatum(-1),
     138                 :             :                                                           ObjectIdGetDatum(collnamespace));
     139         [ +  - ]:        1166 :         if (OidIsValid(oid))
     140                 :             :         {
     141         [ #  # ]:           0 :                 if (quiet)
     142                 :             :                 {
     143                 :           0 :                         table_close(rel, NoLock);
     144                 :           0 :                         return InvalidOid;
     145                 :             :                 }
     146         [ #  # ]:           0 :                 else if (if_not_exists)
     147                 :             :                 {
     148                 :             :                         /*
     149                 :             :                          * If we are in an extension script, insist that the pre-existing
     150                 :             :                          * object be a member of the extension, to avoid security risks.
     151                 :             :                          */
     152                 :           0 :                         ObjectAddressSet(myself, CollationRelationId, oid);
     153                 :           0 :                         checkMembershipInCurrentExtension(&myself);
     154                 :             : 
     155                 :             :                         /* OK to skip */
     156                 :           0 :                         table_close(rel, NoLock);
     157   [ #  #  #  # ]:           0 :                         ereport(NOTICE,
     158                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
     159                 :             :                                          errmsg("collation \"%s\" already exists, skipping",
     160                 :             :                                                         collname)));
     161                 :           0 :                         return InvalidOid;
     162                 :             :                 }
     163                 :             :                 else
     164   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     165                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
     166                 :             :                                          errmsg("collation \"%s\" already exists",
     167                 :             :                                                         collname)));
     168                 :           0 :         }
     169                 :             : 
     170                 :        1166 :         tupDesc = RelationGetDescr(rel);
     171                 :             : 
     172                 :             :         /* form a tuple */
     173                 :        1166 :         memset(nulls, 0, sizeof(nulls));
     174                 :             : 
     175                 :        1166 :         namestrcpy(&name_name, collname);
     176                 :        1166 :         oid = GetNewOidWithIndex(rel, CollationOidIndexId,
     177                 :             :                                                          Anum_pg_collation_oid);
     178                 :        1166 :         values[Anum_pg_collation_oid - 1] = ObjectIdGetDatum(oid);
     179                 :        1166 :         values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
     180                 :        1166 :         values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
     181                 :        1166 :         values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner);
     182                 :        1166 :         values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider);
     183                 :        1166 :         values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic);
     184                 :        1166 :         values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding);
     185         [ +  + ]:        1166 :         if (collcollate)
     186                 :         269 :                 values[Anum_pg_collation_collcollate - 1] = CStringGetTextDatum(collcollate);
     187                 :             :         else
     188                 :         897 :                 nulls[Anum_pg_collation_collcollate - 1] = true;
     189         [ +  + ]:        1166 :         if (collctype)
     190                 :         269 :                 values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype);
     191                 :             :         else
     192                 :         897 :                 nulls[Anum_pg_collation_collctype - 1] = true;
     193         [ +  + ]:        1166 :         if (colllocale)
     194                 :         897 :                 values[Anum_pg_collation_colllocale - 1] = CStringGetTextDatum(colllocale);
     195                 :             :         else
     196                 :         269 :                 nulls[Anum_pg_collation_colllocale - 1] = true;
     197         [ +  + ]:        1166 :         if (collicurules)
     198                 :           2 :                 values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules);
     199                 :             :         else
     200                 :        1164 :                 nulls[Anum_pg_collation_collicurules - 1] = true;
     201         [ +  + ]:        1166 :         if (collversion)
     202                 :         897 :                 values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion);
     203                 :             :         else
     204                 :         269 :                 nulls[Anum_pg_collation_collversion - 1] = true;
     205                 :             : 
     206                 :        1166 :         tup = heap_form_tuple(tupDesc, values, nulls);
     207                 :             : 
     208                 :             :         /* insert a new tuple */
     209                 :        1166 :         CatalogTupleInsert(rel, tup);
     210         [ +  - ]:        1166 :         Assert(OidIsValid(oid));
     211                 :             : 
     212                 :             :         /* set up dependencies for the new collation */
     213                 :        1166 :         myself.classId = CollationRelationId;
     214                 :        1166 :         myself.objectId = oid;
     215                 :        1166 :         myself.objectSubId = 0;
     216                 :             : 
     217                 :             :         /* create dependency on namespace */
     218                 :        1166 :         referenced.classId = NamespaceRelationId;
     219                 :        1166 :         referenced.objectId = collnamespace;
     220                 :        1166 :         referenced.objectSubId = 0;
     221                 :        1166 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     222                 :             : 
     223                 :             :         /* create dependency on owner */
     224                 :        1166 :         recordDependencyOnOwner(CollationRelationId, oid, collowner);
     225                 :             : 
     226                 :             :         /* dependency on extension */
     227                 :        1166 :         recordDependencyOnCurrentExtension(&myself, false);
     228                 :             : 
     229                 :             :         /* Post creation hook for new collation */
     230         [ +  - ]:        1166 :         InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
     231                 :             : 
     232                 :        1166 :         heap_freetuple(tup);
     233                 :        1166 :         table_close(rel, NoLock);
     234                 :             : 
     235                 :        1166 :         return oid;
     236                 :        1220 : }
        

Generated by: LCOV version 2.3.2-1