LCOV - code coverage report
Current view: top level - contrib/citext - citext.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 100.0 % 156 156
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 35 35
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 58.1 % 62 36

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * contrib/citext/citext.c
       3                 :             :  */
       4                 :             : #include "postgres.h"
       5                 :             : 
       6                 :             : #include "catalog/pg_collation.h"
       7                 :             : #include "common/hashfn.h"
       8                 :             : #include "fmgr.h"
       9                 :             : #include "utils/formatting.h"
      10                 :             : #include "utils/varlena.h"
      11                 :             : #include "varatt.h"
      12                 :             : 
      13                 :           3 : PG_MODULE_MAGIC_EXT(
      14                 :             :                     .name = "citext",
      15                 :             :                     .version = PG_VERSION
      16                 :             : );
      17                 :             : 
      18                 :             : /*
      19                 :             :  *      ====================
      20                 :             :  *      FORWARD DECLARATIONS
      21                 :             :  *      ====================
      22                 :             :  */
      23                 :             : 
      24                 :             : static int32 citextcmp(text *left, text *right, Oid collid);
      25                 :             : static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid);
      26                 :             : 
      27                 :             : /*
      28                 :             :  *      =================
      29                 :             :  *      UTILITY FUNCTIONS
      30                 :             :  *      =================
      31                 :             :  */
      32                 :             : 
      33                 :             : /*
      34                 :             :  * citextcmp()
      35                 :             :  * Internal comparison function for citext strings.
      36                 :             :  * Returns int32 negative, zero, or positive.
      37                 :             :  */
      38                 :             : static int32
      39                 :         150 : citextcmp(text *left, text *right, Oid collid)
      40                 :             : {
      41                 :             :     char       *lcstr,
      42                 :             :                *rcstr;
      43                 :             :     int32       result;
      44                 :             : 
      45                 :             :     /*
      46                 :             :      * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
      47                 :             :      * input collation as you might expect.  This is so that the behavior of
      48                 :             :      * citext's equality and hashing functions is not collation-dependent.  We
      49                 :             :      * should change this once the core infrastructure is able to cope with
      50                 :             :      * collation-dependent equality and hashing functions.
      51                 :             :      */
      52                 :             : 
      53                 :         150 :     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
      54                 :         150 :     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
      55                 :             : 
      56                 :         150 :     result = varstr_cmp(lcstr, strlen(lcstr),
      57                 :         150 :                         rcstr, strlen(rcstr),
      58                 :             :                         collid);
      59                 :             : 
      60                 :         150 :     pfree(lcstr);
      61                 :         150 :     pfree(rcstr);
      62                 :             : 
      63                 :         150 :     return result;
      64                 :             : }
      65                 :             : 
      66                 :             : /*
      67                 :             :  * citext_pattern_cmp()
      68                 :             :  * Internal character-by-character comparison function for citext strings.
      69                 :             :  * Returns int32 negative, zero, or positive.
      70                 :             :  */
      71                 :             : static int32
      72                 :          54 : internal_citext_pattern_cmp(text *left, text *right, Oid collid)
      73                 :             : {
      74                 :             :     char       *lcstr,
      75                 :             :                *rcstr;
      76                 :             :     int         llen,
      77                 :             :                 rlen;
      78                 :             :     int32       result;
      79                 :             : 
      80                 :          54 :     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
      81                 :          54 :     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
      82                 :             : 
      83                 :          54 :     llen = strlen(lcstr);
      84                 :          54 :     rlen = strlen(rcstr);
      85                 :             : 
      86                 :          54 :     result = memcmp(lcstr, rcstr, Min(llen, rlen));
      87         [ +  + ]:          54 :     if (result == 0)
      88                 :             :     {
      89         [ +  + ]:          20 :         if (llen < rlen)
      90                 :           1 :             result = -1;
      91         [ +  + ]:          19 :         else if (llen > rlen)
      92                 :           1 :             result = 1;
      93                 :             :     }
      94                 :             : 
      95                 :          54 :     pfree(lcstr);
      96                 :          54 :     pfree(rcstr);
      97                 :             : 
      98                 :          54 :     return result;
      99                 :             : }
     100                 :             : 
     101                 :             : /*
     102                 :             :  *      ==================
     103                 :             :  *      INDEXING FUNCTIONS
     104                 :             :  *      ==================
     105                 :             :  */
     106                 :             : 
     107                 :           5 : PG_FUNCTION_INFO_V1(citext_cmp);
     108                 :             : 
     109                 :             : Datum
     110                 :         131 : citext_cmp(PG_FUNCTION_ARGS)
     111                 :             : {
     112                 :         131 :     text       *left = PG_GETARG_TEXT_PP(0);
     113                 :         131 :     text       *right = PG_GETARG_TEXT_PP(1);
     114                 :             :     int32       result;
     115                 :             : 
     116                 :         131 :     result = citextcmp(left, right, PG_GET_COLLATION());
     117                 :             : 
     118         [ -  + ]:         131 :     PG_FREE_IF_COPY(left, 0);
     119         [ -  + ]:         131 :     PG_FREE_IF_COPY(right, 1);
     120                 :             : 
     121                 :         131 :     PG_RETURN_INT32(result);
     122                 :             : }
     123                 :             : 
     124                 :           4 : PG_FUNCTION_INFO_V1(citext_pattern_cmp);
     125                 :             : 
     126                 :             : Datum
     127                 :          10 : citext_pattern_cmp(PG_FUNCTION_ARGS)
     128                 :             : {
     129                 :          10 :     text       *left = PG_GETARG_TEXT_PP(0);
     130                 :          10 :     text       *right = PG_GETARG_TEXT_PP(1);
     131                 :             :     int32       result;
     132                 :             : 
     133                 :          10 :     result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
     134                 :             : 
     135         [ -  + ]:          10 :     PG_FREE_IF_COPY(left, 0);
     136         [ -  + ]:          10 :     PG_FREE_IF_COPY(right, 1);
     137                 :             : 
     138                 :          10 :     PG_RETURN_INT32(result);
     139                 :             : }
     140                 :             : 
     141                 :           3 : PG_FUNCTION_INFO_V1(citext_hash);
     142                 :             : 
     143                 :             : Datum
     144                 :          10 : citext_hash(PG_FUNCTION_ARGS)
     145                 :             : {
     146                 :          10 :     text       *txt = PG_GETARG_TEXT_PP(0);
     147                 :             :     char       *str;
     148                 :             :     Datum       result;
     149                 :             : 
     150                 :          10 :     str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
     151                 :          10 :     result = hash_any((unsigned char *) str, strlen(str));
     152                 :          10 :     pfree(str);
     153                 :             : 
     154                 :             :     /* Avoid leaking memory for toasted inputs */
     155         [ -  + ]:          10 :     PG_FREE_IF_COPY(txt, 0);
     156                 :             : 
     157                 :          10 :     PG_RETURN_DATUM(result);
     158                 :             : }
     159                 :             : 
     160                 :           3 : PG_FUNCTION_INFO_V1(citext_hash_extended);
     161                 :             : 
     162                 :             : Datum
     163                 :          10 : citext_hash_extended(PG_FUNCTION_ARGS)
     164                 :             : {
     165                 :          10 :     text       *txt = PG_GETARG_TEXT_PP(0);
     166                 :          10 :     uint64      seed = PG_GETARG_INT64(1);
     167                 :             :     char       *str;
     168                 :             :     Datum       result;
     169                 :             : 
     170                 :          10 :     str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
     171                 :          10 :     result = hash_any_extended((unsigned char *) str, strlen(str), seed);
     172                 :          10 :     pfree(str);
     173                 :             : 
     174                 :             :     /* Avoid leaking memory for toasted inputs */
     175         [ -  + ]:          10 :     PG_FREE_IF_COPY(txt, 0);
     176                 :             : 
     177                 :          10 :     PG_RETURN_DATUM(result);
     178                 :             : }
     179                 :             : 
     180                 :             : /*
     181                 :             :  *      ==================
     182                 :             :  *      OPERATOR FUNCTIONS
     183                 :             :  *      ==================
     184                 :             :  */
     185                 :             : 
     186                 :           5 : PG_FUNCTION_INFO_V1(citext_eq);
     187                 :             : 
     188                 :             : Datum
     189                 :          85 : citext_eq(PG_FUNCTION_ARGS)
     190                 :             : {
     191                 :          85 :     text       *left = PG_GETARG_TEXT_PP(0);
     192                 :          85 :     text       *right = PG_GETARG_TEXT_PP(1);
     193                 :             :     char       *lcstr,
     194                 :             :                *rcstr;
     195                 :             :     bool        result;
     196                 :             : 
     197                 :             :     /* We can't compare lengths in advance of downcasing ... */
     198                 :             : 
     199                 :          85 :     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
     200                 :          85 :     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
     201                 :             : 
     202                 :             :     /*
     203                 :             :      * Since we only care about equality or not-equality, we can avoid all the
     204                 :             :      * expense of strcoll() here, and just do bitwise comparison.
     205                 :             :      */
     206                 :          85 :     result = (strcmp(lcstr, rcstr) == 0);
     207                 :             : 
     208                 :          85 :     pfree(lcstr);
     209                 :          85 :     pfree(rcstr);
     210         [ -  + ]:          85 :     PG_FREE_IF_COPY(left, 0);
     211         [ -  + ]:          85 :     PG_FREE_IF_COPY(right, 1);
     212                 :             : 
     213                 :          85 :     PG_RETURN_BOOL(result);
     214                 :             : }
     215                 :             : 
     216                 :           4 : PG_FUNCTION_INFO_V1(citext_ne);
     217                 :             : 
     218                 :             : Datum
     219                 :          22 : citext_ne(PG_FUNCTION_ARGS)
     220                 :             : {
     221                 :          22 :     text       *left = PG_GETARG_TEXT_PP(0);
     222                 :          22 :     text       *right = PG_GETARG_TEXT_PP(1);
     223                 :             :     char       *lcstr,
     224                 :             :                *rcstr;
     225                 :             :     bool        result;
     226                 :             : 
     227                 :             :     /* We can't compare lengths in advance of downcasing ... */
     228                 :             : 
     229                 :          22 :     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
     230                 :          22 :     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
     231                 :             : 
     232                 :             :     /*
     233                 :             :      * Since we only care about equality or not-equality, we can avoid all the
     234                 :             :      * expense of strcoll() here, and just do bitwise comparison.
     235                 :             :      */
     236                 :          22 :     result = (strcmp(lcstr, rcstr) != 0);
     237                 :             : 
     238                 :          22 :     pfree(lcstr);
     239                 :          22 :     pfree(rcstr);
     240         [ -  + ]:          22 :     PG_FREE_IF_COPY(left, 0);
     241         [ -  + ]:          22 :     PG_FREE_IF_COPY(right, 1);
     242                 :             : 
     243                 :          22 :     PG_RETURN_BOOL(result);
     244                 :             : }
     245                 :             : 
     246                 :           3 : PG_FUNCTION_INFO_V1(citext_lt);
     247                 :             : 
     248                 :             : Datum
     249                 :           1 : citext_lt(PG_FUNCTION_ARGS)
     250                 :             : {
     251                 :           1 :     text       *left = PG_GETARG_TEXT_PP(0);
     252                 :           1 :     text       *right = PG_GETARG_TEXT_PP(1);
     253                 :             :     bool        result;
     254                 :             : 
     255                 :           1 :     result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
     256                 :             : 
     257         [ -  + ]:           1 :     PG_FREE_IF_COPY(left, 0);
     258         [ -  + ]:           1 :     PG_FREE_IF_COPY(right, 1);
     259                 :             : 
     260                 :           1 :     PG_RETURN_BOOL(result);
     261                 :             : }
     262                 :             : 
     263                 :           3 : PG_FUNCTION_INFO_V1(citext_le);
     264                 :             : 
     265                 :             : Datum
     266                 :           1 : citext_le(PG_FUNCTION_ARGS)
     267                 :             : {
     268                 :           1 :     text       *left = PG_GETARG_TEXT_PP(0);
     269                 :           1 :     text       *right = PG_GETARG_TEXT_PP(1);
     270                 :             :     bool        result;
     271                 :             : 
     272                 :           1 :     result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
     273                 :             : 
     274         [ -  + ]:           1 :     PG_FREE_IF_COPY(left, 0);
     275         [ -  + ]:           1 :     PG_FREE_IF_COPY(right, 1);
     276                 :             : 
     277                 :           1 :     PG_RETURN_BOOL(result);
     278                 :             : }
     279                 :             : 
     280                 :           3 : PG_FUNCTION_INFO_V1(citext_gt);
     281                 :             : 
     282                 :             : Datum
     283                 :           3 : citext_gt(PG_FUNCTION_ARGS)
     284                 :             : {
     285                 :           3 :     text       *left = PG_GETARG_TEXT_PP(0);
     286                 :           3 :     text       *right = PG_GETARG_TEXT_PP(1);
     287                 :             :     bool        result;
     288                 :             : 
     289                 :           3 :     result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
     290                 :             : 
     291         [ -  + ]:           3 :     PG_FREE_IF_COPY(left, 0);
     292         [ -  + ]:           3 :     PG_FREE_IF_COPY(right, 1);
     293                 :             : 
     294                 :           3 :     PG_RETURN_BOOL(result);
     295                 :             : }
     296                 :             : 
     297                 :           3 : PG_FUNCTION_INFO_V1(citext_ge);
     298                 :             : 
     299                 :             : Datum
     300                 :           1 : citext_ge(PG_FUNCTION_ARGS)
     301                 :             : {
     302                 :           1 :     text       *left = PG_GETARG_TEXT_PP(0);
     303                 :           1 :     text       *right = PG_GETARG_TEXT_PP(1);
     304                 :             :     bool        result;
     305                 :             : 
     306                 :           1 :     result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
     307                 :             : 
     308         [ -  + ]:           1 :     PG_FREE_IF_COPY(left, 0);
     309         [ -  + ]:           1 :     PG_FREE_IF_COPY(right, 1);
     310                 :             : 
     311                 :           1 :     PG_RETURN_BOOL(result);
     312                 :             : }
     313                 :             : 
     314                 :           4 : PG_FUNCTION_INFO_V1(citext_pattern_lt);
     315                 :             : 
     316                 :             : Datum
     317                 :           9 : citext_pattern_lt(PG_FUNCTION_ARGS)
     318                 :             : {
     319                 :           9 :     text       *left = PG_GETARG_TEXT_PP(0);
     320                 :           9 :     text       *right = PG_GETARG_TEXT_PP(1);
     321                 :             :     bool        result;
     322                 :             : 
     323                 :           9 :     result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
     324                 :             : 
     325         [ -  + ]:           9 :     PG_FREE_IF_COPY(left, 0);
     326         [ -  + ]:           9 :     PG_FREE_IF_COPY(right, 1);
     327                 :             : 
     328                 :           9 :     PG_RETURN_BOOL(result);
     329                 :             : }
     330                 :             : 
     331                 :           4 : PG_FUNCTION_INFO_V1(citext_pattern_le);
     332                 :             : 
     333                 :             : Datum
     334                 :          13 : citext_pattern_le(PG_FUNCTION_ARGS)
     335                 :             : {
     336                 :          13 :     text       *left = PG_GETARG_TEXT_PP(0);
     337                 :          13 :     text       *right = PG_GETARG_TEXT_PP(1);
     338                 :             :     bool        result;
     339                 :             : 
     340                 :          13 :     result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
     341                 :             : 
     342         [ -  + ]:          13 :     PG_FREE_IF_COPY(left, 0);
     343         [ -  + ]:          13 :     PG_FREE_IF_COPY(right, 1);
     344                 :             : 
     345                 :          13 :     PG_RETURN_BOOL(result);
     346                 :             : }
     347                 :             : 
     348                 :           4 : PG_FUNCTION_INFO_V1(citext_pattern_gt);
     349                 :             : 
     350                 :             : Datum
     351                 :          10 : citext_pattern_gt(PG_FUNCTION_ARGS)
     352                 :             : {
     353                 :          10 :     text       *left = PG_GETARG_TEXT_PP(0);
     354                 :          10 :     text       *right = PG_GETARG_TEXT_PP(1);
     355                 :             :     bool        result;
     356                 :             : 
     357                 :          10 :     result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
     358                 :             : 
     359         [ -  + ]:          10 :     PG_FREE_IF_COPY(left, 0);
     360         [ -  + ]:          10 :     PG_FREE_IF_COPY(right, 1);
     361                 :             : 
     362                 :          10 :     PG_RETURN_BOOL(result);
     363                 :             : }
     364                 :             : 
     365                 :           4 : PG_FUNCTION_INFO_V1(citext_pattern_ge);
     366                 :             : 
     367                 :             : Datum
     368                 :          12 : citext_pattern_ge(PG_FUNCTION_ARGS)
     369                 :             : {
     370                 :          12 :     text       *left = PG_GETARG_TEXT_PP(0);
     371                 :          12 :     text       *right = PG_GETARG_TEXT_PP(1);
     372                 :             :     bool        result;
     373                 :             : 
     374                 :          12 :     result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
     375                 :             : 
     376         [ -  + ]:          12 :     PG_FREE_IF_COPY(left, 0);
     377         [ -  + ]:          12 :     PG_FREE_IF_COPY(right, 1);
     378                 :             : 
     379                 :          12 :     PG_RETURN_BOOL(result);
     380                 :             : }
     381                 :             : 
     382                 :             : /*
     383                 :             :  *      ===================
     384                 :             :  *      AGGREGATE FUNCTIONS
     385                 :             :  *      ===================
     386                 :             :  */
     387                 :             : 
     388                 :           3 : PG_FUNCTION_INFO_V1(citext_smaller);
     389                 :             : 
     390                 :             : Datum
     391                 :           7 : citext_smaller(PG_FUNCTION_ARGS)
     392                 :             : {
     393                 :           7 :     text       *left = PG_GETARG_TEXT_PP(0);
     394                 :           7 :     text       *right = PG_GETARG_TEXT_PP(1);
     395                 :             :     text       *result;
     396                 :             : 
     397         [ +  + ]:           7 :     result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
     398                 :           7 :     PG_RETURN_TEXT_P(result);
     399                 :             : }
     400                 :             : 
     401                 :           3 : PG_FUNCTION_INFO_V1(citext_larger);
     402                 :             : 
     403                 :             : Datum
     404                 :           6 : citext_larger(PG_FUNCTION_ARGS)
     405                 :             : {
     406                 :           6 :     text       *left = PG_GETARG_TEXT_PP(0);
     407                 :           6 :     text       *right = PG_GETARG_TEXT_PP(1);
     408                 :             :     text       *result;
     409                 :             : 
     410         [ +  + ]:           6 :     result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
     411                 :           6 :     PG_RETURN_TEXT_P(result);
     412                 :             : }
        

Generated by: LCOV version 2.0-1