LCOV - code coverage report
Current view: top level - contrib/citext - citext.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 201 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 35 0
Legend: Lines:     hit not hit

            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            0 : 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            0 : citextcmp(text *left, text *right, Oid collid)
      40              : {
      41            0 :         char       *lcstr,
      42              :                            *rcstr;
      43            0 :         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            0 :         lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
      54            0 :         rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
      55              : 
      56            0 :         result = varstr_cmp(lcstr, strlen(lcstr),
      57            0 :                                                 rcstr, strlen(rcstr),
      58            0 :                                                 collid);
      59              : 
      60            0 :         pfree(lcstr);
      61            0 :         pfree(rcstr);
      62              : 
      63            0 :         return result;
      64            0 : }
      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            0 : internal_citext_pattern_cmp(text *left, text *right, Oid collid)
      73              : {
      74            0 :         char       *lcstr,
      75              :                            *rcstr;
      76            0 :         int                     llen,
      77              :                                 rlen;
      78            0 :         int32           result;
      79              : 
      80            0 :         lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
      81            0 :         rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
      82              : 
      83            0 :         llen = strlen(lcstr);
      84            0 :         rlen = strlen(rcstr);
      85              : 
      86            0 :         result = memcmp(lcstr, rcstr, Min(llen, rlen));
      87            0 :         if (result == 0)
      88              :         {
      89            0 :                 if (llen < rlen)
      90            0 :                         result = -1;
      91            0 :                 else if (llen > rlen)
      92            0 :                         result = 1;
      93            0 :         }
      94              : 
      95            0 :         pfree(lcstr);
      96            0 :         pfree(rcstr);
      97              : 
      98            0 :         return result;
      99            0 : }
     100              : 
     101              : /*
     102              :  *              ==================
     103              :  *              INDEXING FUNCTIONS
     104              :  *              ==================
     105              :  */
     106              : 
     107            0 : PG_FUNCTION_INFO_V1(citext_cmp);
     108              : 
     109              : Datum
     110            0 : citext_cmp(PG_FUNCTION_ARGS)
     111              : {
     112            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     113            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     114            0 :         int32           result;
     115              : 
     116            0 :         result = citextcmp(left, right, PG_GET_COLLATION());
     117              : 
     118            0 :         PG_FREE_IF_COPY(left, 0);
     119            0 :         PG_FREE_IF_COPY(right, 1);
     120              : 
     121            0 :         PG_RETURN_INT32(result);
     122            0 : }
     123              : 
     124            0 : PG_FUNCTION_INFO_V1(citext_pattern_cmp);
     125              : 
     126              : Datum
     127            0 : citext_pattern_cmp(PG_FUNCTION_ARGS)
     128              : {
     129            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     130            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     131            0 :         int32           result;
     132              : 
     133            0 :         result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
     134              : 
     135            0 :         PG_FREE_IF_COPY(left, 0);
     136            0 :         PG_FREE_IF_COPY(right, 1);
     137              : 
     138            0 :         PG_RETURN_INT32(result);
     139            0 : }
     140              : 
     141            0 : PG_FUNCTION_INFO_V1(citext_hash);
     142              : 
     143              : Datum
     144            0 : citext_hash(PG_FUNCTION_ARGS)
     145              : {
     146            0 :         text       *txt = PG_GETARG_TEXT_PP(0);
     147            0 :         char       *str;
     148            0 :         Datum           result;
     149              : 
     150            0 :         str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
     151            0 :         result = hash_any((unsigned char *) str, strlen(str));
     152            0 :         pfree(str);
     153              : 
     154              :         /* Avoid leaking memory for toasted inputs */
     155            0 :         PG_FREE_IF_COPY(txt, 0);
     156              : 
     157            0 :         PG_RETURN_DATUM(result);
     158            0 : }
     159              : 
     160            0 : PG_FUNCTION_INFO_V1(citext_hash_extended);
     161              : 
     162              : Datum
     163            0 : citext_hash_extended(PG_FUNCTION_ARGS)
     164              : {
     165            0 :         text       *txt = PG_GETARG_TEXT_PP(0);
     166            0 :         uint64          seed = PG_GETARG_INT64(1);
     167            0 :         char       *str;
     168            0 :         Datum           result;
     169              : 
     170            0 :         str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
     171            0 :         result = hash_any_extended((unsigned char *) str, strlen(str), seed);
     172            0 :         pfree(str);
     173              : 
     174              :         /* Avoid leaking memory for toasted inputs */
     175            0 :         PG_FREE_IF_COPY(txt, 0);
     176              : 
     177            0 :         PG_RETURN_DATUM(result);
     178            0 : }
     179              : 
     180              : /*
     181              :  *              ==================
     182              :  *              OPERATOR FUNCTIONS
     183              :  *              ==================
     184              :  */
     185              : 
     186            0 : PG_FUNCTION_INFO_V1(citext_eq);
     187              : 
     188              : Datum
     189            0 : citext_eq(PG_FUNCTION_ARGS)
     190              : {
     191            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     192            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     193            0 :         char       *lcstr,
     194              :                            *rcstr;
     195            0 :         bool            result;
     196              : 
     197              :         /* We can't compare lengths in advance of downcasing ... */
     198              : 
     199            0 :         lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
     200            0 :         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            0 :         result = (strcmp(lcstr, rcstr) == 0);
     207              : 
     208            0 :         pfree(lcstr);
     209            0 :         pfree(rcstr);
     210            0 :         PG_FREE_IF_COPY(left, 0);
     211            0 :         PG_FREE_IF_COPY(right, 1);
     212              : 
     213            0 :         PG_RETURN_BOOL(result);
     214            0 : }
     215              : 
     216            0 : PG_FUNCTION_INFO_V1(citext_ne);
     217              : 
     218              : Datum
     219            0 : citext_ne(PG_FUNCTION_ARGS)
     220              : {
     221            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     222            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     223            0 :         char       *lcstr,
     224              :                            *rcstr;
     225            0 :         bool            result;
     226              : 
     227              :         /* We can't compare lengths in advance of downcasing ... */
     228              : 
     229            0 :         lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
     230            0 :         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            0 :         result = (strcmp(lcstr, rcstr) != 0);
     237              : 
     238            0 :         pfree(lcstr);
     239            0 :         pfree(rcstr);
     240            0 :         PG_FREE_IF_COPY(left, 0);
     241            0 :         PG_FREE_IF_COPY(right, 1);
     242              : 
     243            0 :         PG_RETURN_BOOL(result);
     244            0 : }
     245              : 
     246            0 : PG_FUNCTION_INFO_V1(citext_lt);
     247              : 
     248              : Datum
     249            0 : citext_lt(PG_FUNCTION_ARGS)
     250              : {
     251            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     252            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     253            0 :         bool            result;
     254              : 
     255            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
     256              : 
     257            0 :         PG_FREE_IF_COPY(left, 0);
     258            0 :         PG_FREE_IF_COPY(right, 1);
     259              : 
     260            0 :         PG_RETURN_BOOL(result);
     261            0 : }
     262              : 
     263            0 : PG_FUNCTION_INFO_V1(citext_le);
     264              : 
     265              : Datum
     266            0 : citext_le(PG_FUNCTION_ARGS)
     267              : {
     268            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     269            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     270            0 :         bool            result;
     271              : 
     272            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
     273              : 
     274            0 :         PG_FREE_IF_COPY(left, 0);
     275            0 :         PG_FREE_IF_COPY(right, 1);
     276              : 
     277            0 :         PG_RETURN_BOOL(result);
     278            0 : }
     279              : 
     280            0 : PG_FUNCTION_INFO_V1(citext_gt);
     281              : 
     282              : Datum
     283            0 : citext_gt(PG_FUNCTION_ARGS)
     284              : {
     285            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     286            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     287            0 :         bool            result;
     288              : 
     289            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
     290              : 
     291            0 :         PG_FREE_IF_COPY(left, 0);
     292            0 :         PG_FREE_IF_COPY(right, 1);
     293              : 
     294            0 :         PG_RETURN_BOOL(result);
     295            0 : }
     296              : 
     297            0 : PG_FUNCTION_INFO_V1(citext_ge);
     298              : 
     299              : Datum
     300            0 : citext_ge(PG_FUNCTION_ARGS)
     301              : {
     302            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     303            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     304            0 :         bool            result;
     305              : 
     306            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
     307              : 
     308            0 :         PG_FREE_IF_COPY(left, 0);
     309            0 :         PG_FREE_IF_COPY(right, 1);
     310              : 
     311            0 :         PG_RETURN_BOOL(result);
     312            0 : }
     313              : 
     314            0 : PG_FUNCTION_INFO_V1(citext_pattern_lt);
     315              : 
     316              : Datum
     317            0 : citext_pattern_lt(PG_FUNCTION_ARGS)
     318              : {
     319            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     320            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     321            0 :         bool            result;
     322              : 
     323            0 :         result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
     324              : 
     325            0 :         PG_FREE_IF_COPY(left, 0);
     326            0 :         PG_FREE_IF_COPY(right, 1);
     327              : 
     328            0 :         PG_RETURN_BOOL(result);
     329            0 : }
     330              : 
     331            0 : PG_FUNCTION_INFO_V1(citext_pattern_le);
     332              : 
     333              : Datum
     334            0 : citext_pattern_le(PG_FUNCTION_ARGS)
     335              : {
     336            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     337            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     338            0 :         bool            result;
     339              : 
     340            0 :         result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
     341              : 
     342            0 :         PG_FREE_IF_COPY(left, 0);
     343            0 :         PG_FREE_IF_COPY(right, 1);
     344              : 
     345            0 :         PG_RETURN_BOOL(result);
     346            0 : }
     347              : 
     348            0 : PG_FUNCTION_INFO_V1(citext_pattern_gt);
     349              : 
     350              : Datum
     351            0 : citext_pattern_gt(PG_FUNCTION_ARGS)
     352              : {
     353            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     354            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     355            0 :         bool            result;
     356              : 
     357            0 :         result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
     358              : 
     359            0 :         PG_FREE_IF_COPY(left, 0);
     360            0 :         PG_FREE_IF_COPY(right, 1);
     361              : 
     362            0 :         PG_RETURN_BOOL(result);
     363            0 : }
     364              : 
     365            0 : PG_FUNCTION_INFO_V1(citext_pattern_ge);
     366              : 
     367              : Datum
     368            0 : citext_pattern_ge(PG_FUNCTION_ARGS)
     369              : {
     370            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     371            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     372            0 :         bool            result;
     373              : 
     374            0 :         result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
     375              : 
     376            0 :         PG_FREE_IF_COPY(left, 0);
     377            0 :         PG_FREE_IF_COPY(right, 1);
     378              : 
     379            0 :         PG_RETURN_BOOL(result);
     380            0 : }
     381              : 
     382              : /*
     383              :  *              ===================
     384              :  *              AGGREGATE FUNCTIONS
     385              :  *              ===================
     386              :  */
     387              : 
     388            0 : PG_FUNCTION_INFO_V1(citext_smaller);
     389              : 
     390              : Datum
     391            0 : citext_smaller(PG_FUNCTION_ARGS)
     392              : {
     393            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     394            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     395            0 :         text       *result;
     396              : 
     397            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
     398            0 :         PG_RETURN_TEXT_P(result);
     399            0 : }
     400              : 
     401            0 : PG_FUNCTION_INFO_V1(citext_larger);
     402              : 
     403              : Datum
     404            0 : citext_larger(PG_FUNCTION_ARGS)
     405              : {
     406            0 :         text       *left = PG_GETARG_TEXT_PP(0);
     407            0 :         text       *right = PG_GETARG_TEXT_PP(1);
     408            0 :         text       *result;
     409              : 
     410            0 :         result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
     411            0 :         PG_RETURN_TEXT_P(result);
     412            0 : }
        

Generated by: LCOV version 2.3.2-1