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

Generated by: LCOV version 1.14