LCOV - code coverage report
Current view: top level - src/backend/tsearch - regis.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 78.4 % 125 98
Test Date: 2026-07-25 22:15:46 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 60.8 % 97 59

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * regis.c
       4                 :             :  *      Fast regex subset
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *    src/backend/tsearch/regis.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : 
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "tsearch/dicts/regis.h"
      18                 :             : #include "tsearch/ts_locale.h"
      19                 :             : 
      20                 :             : #define RS_IN_ONEOF 1
      21                 :             : #define RS_IN_ONEOF_IN  2
      22                 :             : #define RS_IN_NONEOF    3
      23                 :             : #define RS_IN_WAIT  4
      24                 :             : 
      25                 :             : 
      26                 :             : /*
      27                 :             :  * Test whether a regex is of the subset supported here.
      28                 :             :  * Keep this in sync with RS_compile!
      29                 :             :  */
      30                 :             : bool
      31                 :         522 : RS_isRegis(const char *str)
      32                 :             : {
      33                 :         522 :     int         state = RS_IN_WAIT;
      34                 :         522 :     const char *c = str;
      35                 :             : 
      36         [ +  + ]:        3162 :     while (*c)
      37                 :             :     {
      38         [ +  + ]:        2726 :         if (state == RS_IN_WAIT)
      39                 :             :         {
      40         [ +  + ]:         691 :             if (t_isalpha_cstr(c))
      41                 :             :                  /* okay */ ;
      42         [ +  + ]:         543 :             else if (t_iseq(c, '['))
      43                 :         457 :                 state = RS_IN_ONEOF;
      44                 :             :             else
      45                 :          86 :                 return false;
      46                 :             :         }
      47         [ +  + ]:        2035 :         else if (state == RS_IN_ONEOF)
      48                 :             :         {
      49         [ +  - ]:         457 :             if (t_iseq(c, '^'))
      50                 :         457 :                 state = RS_IN_NONEOF;
      51         [ #  # ]:           0 :             else if (t_isalpha_cstr(c))
      52                 :           0 :                 state = RS_IN_ONEOF_IN;
      53                 :             :             else
      54                 :           0 :                 return false;
      55                 :             :         }
      56   [ +  -  +  - ]:        1578 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
      57                 :             :         {
      58         [ +  + ]:        2035 :             if (t_isalpha_cstr(c))
      59                 :             :                  /* okay */ ;
      60         [ +  - ]:         457 :             else if (t_iseq(c, ']'))
      61                 :         457 :                 state = RS_IN_WAIT;
      62                 :             :             else
      63                 :           0 :                 return false;
      64                 :             :         }
      65                 :             :         else
      66         [ #  # ]:           0 :             elog(ERROR, "internal error in RS_isRegis: state %d", state);
      67                 :        2640 :         c += pg_mblen_cstr(c);
      68                 :             :     }
      69                 :             : 
      70                 :         436 :     return (state == RS_IN_WAIT);
      71                 :             : }
      72                 :             : 
      73                 :             : static RegisNode *
      74                 :         498 : newRegisNode(RegisNode *prev, int len)
      75                 :             : {
      76                 :             :     RegisNode  *ptr;
      77                 :             : 
      78                 :         498 :     ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
      79         [ +  + ]:         498 :     if (prev)
      80                 :          62 :         prev->next = ptr;
      81                 :         498 :     return ptr;
      82                 :             : }
      83                 :             : 
      84                 :             : void
      85                 :         436 : RS_compile(Regis *r, bool issuffix, const char *str)
      86                 :             : {
      87                 :         436 :     int         len = strlen(str);
      88                 :         436 :     int         state = RS_IN_WAIT;
      89                 :         436 :     const char *c = str;
      90                 :         436 :     RegisNode  *ptr = NULL;
      91                 :             : 
      92                 :         436 :     memset(r, 0, sizeof(Regis));
      93                 :         436 :     r->issuffix = (issuffix) ? 1 : 0;
      94                 :             : 
      95         [ +  + ]:        2822 :     while (*c)
      96                 :             :     {
      97         [ +  + ]:        2386 :         if (state == RS_IN_WAIT)
      98                 :             :         {
      99         [ +  + ]:         498 :             if (t_isalpha_cstr(c))
     100                 :             :             {
     101         [ +  - ]:          62 :                 if (ptr)
     102                 :          62 :                     ptr = newRegisNode(ptr, len);
     103                 :             :                 else
     104                 :           0 :                     ptr = r->node = newRegisNode(NULL, len);
     105                 :          62 :                 ptr->type = RSF_ONEOF;
     106                 :          62 :                 ptr->len = ts_copychar_cstr(ptr->data, c);
     107                 :             :             }
     108         [ +  - ]:         436 :             else if (t_iseq(c, '['))
     109                 :             :             {
     110         [ -  + ]:         436 :                 if (ptr)
     111                 :           0 :                     ptr = newRegisNode(ptr, len);
     112                 :             :                 else
     113                 :         436 :                     ptr = r->node = newRegisNode(NULL, len);
     114                 :         436 :                 ptr->type = RSF_ONEOF;
     115                 :         436 :                 state = RS_IN_ONEOF;
     116                 :             :             }
     117                 :             :             else                /* shouldn't get here */
     118         [ #  # ]:           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     119                 :             :         }
     120         [ +  + ]:        1888 :         else if (state == RS_IN_ONEOF)
     121                 :             :         {
     122         [ +  - ]:         436 :             if (t_iseq(c, '^'))
     123                 :             :             {
     124                 :         436 :                 ptr->type = RSF_NONEOF;
     125                 :         436 :                 state = RS_IN_NONEOF;
     126                 :             :             }
     127         [ #  # ]:           0 :             else if (t_isalpha_cstr(c))
     128                 :             :             {
     129                 :           0 :                 ptr->len = ts_copychar_cstr(ptr->data, c);
     130                 :           0 :                 state = RS_IN_ONEOF_IN;
     131                 :             :             }
     132                 :             :             else                /* shouldn't get here */
     133         [ #  # ]:           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     134                 :             :         }
     135   [ +  -  +  - ]:        1452 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
     136                 :             :         {
     137         [ +  + ]:        2904 :             if (t_isalpha_cstr(c))
     138                 :        1016 :                 ptr->len += ts_copychar_cstr(ptr->data + ptr->len, c);
     139         [ +  - ]:         436 :             else if (t_iseq(c, ']'))
     140                 :         436 :                 state = RS_IN_WAIT;
     141                 :             :             else                /* shouldn't get here */
     142         [ #  # ]:           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     143                 :             :         }
     144                 :             :         else
     145         [ #  # ]:           0 :             elog(ERROR, "internal error in RS_compile: state %d", state);
     146                 :        2386 :         c += pg_mblen_cstr(c);
     147                 :             :     }
     148                 :             : 
     149         [ -  + ]:         436 :     if (state != RS_IN_WAIT)    /* shouldn't get here */
     150         [ #  # ]:           0 :         elog(ERROR, "invalid regis pattern: \"%s\"", str);
     151                 :             : 
     152                 :         436 :     ptr = r->node;
     153         [ +  + ]:         934 :     while (ptr)
     154                 :             :     {
     155                 :         498 :         r->nchar++;
     156                 :         498 :         ptr = ptr->next;
     157                 :             :     }
     158                 :         436 : }
     159                 :             : 
     160                 :             : void
     161                 :           0 : RS_free(Regis *r)
     162                 :             : {
     163                 :           0 :     RegisNode  *ptr = r->node,
     164                 :             :                *tmp;
     165                 :             : 
     166         [ #  # ]:           0 :     while (ptr)
     167                 :             :     {
     168                 :           0 :         tmp = ptr->next;
     169                 :           0 :         pfree(ptr);
     170                 :           0 :         ptr = tmp;
     171                 :             :     }
     172                 :             : 
     173                 :           0 :     r->node = NULL;
     174                 :           0 : }
     175                 :             : 
     176                 :             : static bool
     177                 :         590 : mb_strchr(char *str, char *c)
     178                 :             : {
     179                 :             :     int         clen,
     180                 :             :                 plen,
     181                 :             :                 i;
     182                 :         590 :     char       *ptr = str;
     183                 :         590 :     bool        res = false;
     184                 :             : 
     185                 :         590 :     clen = pg_mblen_cstr(c);
     186   [ +  +  +  - ]:        1940 :     while (*ptr && !res)
     187                 :             :     {
     188                 :        1350 :         plen = pg_mblen_cstr(ptr);
     189         [ +  - ]:        1350 :         if (plen == clen)
     190                 :             :         {
     191                 :        1350 :             i = plen;
     192                 :        1350 :             res = true;
     193         [ +  + ]:        1380 :             while (i--)
     194         [ +  + ]:        1350 :                 if (*(ptr + i) != *(c + i))
     195                 :             :                 {
     196                 :        1320 :                     res = false;
     197                 :        1320 :                     break;
     198                 :             :                 }
     199                 :             :         }
     200                 :             : 
     201                 :        1350 :         ptr += plen;
     202                 :             :     }
     203                 :             : 
     204                 :         590 :     return res;
     205                 :             : }
     206                 :             : 
     207                 :             : bool
     208                 :         590 : RS_execute(Regis *r, char *str)
     209                 :             : {
     210                 :         590 :     RegisNode  *ptr = r->node;
     211                 :         590 :     char       *c = str;
     212                 :         590 :     int         len = 0;
     213                 :             : 
     214         [ +  + ]:        3900 :     while (*c)
     215                 :             :     {
     216                 :        3310 :         len++;
     217                 :        3310 :         c += pg_mblen_cstr(c);
     218                 :             :     }
     219                 :             : 
     220         [ +  + ]:         590 :     if (len < r->nchar)
     221                 :          30 :         return 0;
     222                 :             : 
     223                 :         560 :     c = str;
     224         [ +  - ]:         560 :     if (r->issuffix)
     225                 :             :     {
     226                 :         560 :         len -= r->nchar;
     227         [ +  + ]:        3280 :         while (len-- > 0)
     228                 :        2720 :             c += pg_mblen_cstr(c);
     229                 :             :     }
     230                 :             : 
     231                 :             : 
     232         [ +  + ]:        1150 :     while (ptr)
     233                 :             :     {
     234      [ +  +  - ]:         590 :         switch (ptr->type)
     235                 :             :         {
     236                 :          30 :             case RSF_ONEOF:
     237         [ -  + ]:          30 :                 if (!mb_strchr((char *) ptr->data, c))
     238                 :           0 :                     return false;
     239                 :          30 :                 break;
     240                 :         560 :             case RSF_NONEOF:
     241         [ -  + ]:         560 :                 if (mb_strchr((char *) ptr->data, c))
     242                 :           0 :                     return false;
     243                 :         560 :                 break;
     244                 :           0 :             default:
     245         [ #  # ]:           0 :                 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
     246                 :             :         }
     247                 :         590 :         ptr = ptr->next;
     248                 :         590 :         c += pg_mblen_cstr(c);
     249                 :             :     }
     250                 :             : 
     251                 :         560 :     return true;
     252                 :             : }
        

Generated by: LCOV version 2.0-1