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

Generated by: LCOV version 1.13