LCOV - code coverage report
Current view: top level - src/backend/tsearch - regis.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 80.0 % 145 116
Test Date: 2026-01-26 10:56:24 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 54.1 % 111 60

             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                 :         120 : RS_isRegis(const char *str)
      32                 :             : {
      33                 :         120 :         int                     state = RS_IN_WAIT;
      34                 :         120 :         const char *c = str;
      35                 :             : 
      36         [ +  + ]:         726 :         while (*c)
      37                 :             :         {
      38         [ +  + ]:         626 :                 if (state == RS_IN_WAIT)
      39                 :             :                 {
      40         [ +  + ]:         159 :                         if (t_isalpha(c))
      41                 :             :                                  /* okay */ ;
      42         [ +  + ]:         125 :                         else if (t_iseq(c, '['))
      43                 :         105 :                                 state = RS_IN_ONEOF;
      44                 :             :                         else
      45                 :          20 :                                 return false;
      46                 :         139 :                 }
      47         [ +  + ]:         467 :                 else if (state == RS_IN_ONEOF)
      48                 :             :                 {
      49         [ +  - ]:         105 :                         if (t_iseq(c, '^'))
      50                 :         105 :                                 state = RS_IN_NONEOF;
      51         [ #  # ]:           0 :                         else if (t_isalpha(c))
      52                 :           0 :                                 state = RS_IN_ONEOF_IN;
      53                 :             :                         else
      54                 :           0 :                                 return false;
      55                 :         105 :                 }
      56   [ +  -  +  - ]:         362 :                 else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
      57                 :             :                 {
      58         [ +  + ]:         362 :                         if (t_isalpha(c))
      59                 :             :                                  /* okay */ ;
      60         [ -  + ]:         105 :                         else if (t_iseq(c, ']'))
      61                 :         105 :                                 state = RS_IN_WAIT;
      62                 :             :                         else
      63                 :           0 :                                 return false;
      64                 :         362 :                 }
      65                 :             :                 else
      66   [ #  #  #  # ]:           0 :                         elog(ERROR, "internal error in RS_isRegis: state %d", state);
      67                 :         606 :                 c += pg_mblen(c);
      68                 :             :         }
      69                 :             : 
      70                 :         100 :         return (state == RS_IN_WAIT);
      71                 :         120 : }
      72                 :             : 
      73                 :             : static RegisNode *
      74                 :         114 : newRegisNode(RegisNode *prev, int len)
      75                 :             : {
      76                 :         114 :         RegisNode  *ptr;
      77                 :             : 
      78                 :         114 :         ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
      79         [ +  + ]:         114 :         if (prev)
      80                 :          14 :                 prev->next = ptr;
      81                 :         228 :         return ptr;
      82                 :         114 : }
      83                 :             : 
      84                 :             : void
      85                 :         100 : RS_compile(Regis *r, bool issuffix, const char *str)
      86                 :             : {
      87                 :         100 :         int                     len = strlen(str);
      88                 :         100 :         int                     state = RS_IN_WAIT;
      89                 :         100 :         const char *c = str;
      90                 :         100 :         RegisNode  *ptr = NULL;
      91                 :             : 
      92                 :         100 :         memset(r, 0, sizeof(Regis));
      93                 :         100 :         r->issuffix = (issuffix) ? 1 : 0;
      94                 :             : 
      95         [ +  + ]:         646 :         while (*c)
      96                 :             :         {
      97         [ +  + ]:         546 :                 if (state == RS_IN_WAIT)
      98                 :             :                 {
      99         [ +  + ]:         114 :                         if (t_isalpha(c))
     100                 :             :                         {
     101         [ +  - ]:          14 :                                 if (ptr)
     102                 :          14 :                                         ptr = newRegisNode(ptr, len);
     103                 :             :                                 else
     104                 :           0 :                                         ptr = r->node = newRegisNode(NULL, len);
     105                 :          14 :                                 COPYCHAR(ptr->data, c);
     106                 :          14 :                                 ptr->type = RSF_ONEOF;
     107                 :          14 :                                 ptr->len = pg_mblen(c);
     108                 :          14 :                         }
     109         [ +  - ]:         100 :                         else if (t_iseq(c, '['))
     110                 :             :                         {
     111         [ -  + ]:         100 :                                 if (ptr)
     112                 :           0 :                                         ptr = newRegisNode(ptr, len);
     113                 :             :                                 else
     114                 :         100 :                                         ptr = r->node = newRegisNode(NULL, len);
     115                 :         100 :                                 ptr->type = RSF_ONEOF;
     116                 :         100 :                                 state = RS_IN_ONEOF;
     117                 :         100 :                         }
     118                 :             :                         else                            /* shouldn't get here */
     119   [ #  #  #  # ]:           0 :                                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     120                 :         114 :                 }
     121         [ +  + ]:         432 :                 else if (state == RS_IN_ONEOF)
     122                 :             :                 {
     123         [ +  - ]:         100 :                         if (t_iseq(c, '^'))
     124                 :             :                         {
     125                 :         100 :                                 ptr->type = RSF_NONEOF;
     126                 :         100 :                                 state = RS_IN_NONEOF;
     127                 :         100 :                         }
     128         [ #  # ]:           0 :                         else if (t_isalpha(c))
     129                 :             :                         {
     130                 :           0 :                                 COPYCHAR(ptr->data, c);
     131                 :           0 :                                 ptr->len = pg_mblen(c);
     132                 :           0 :                                 state = RS_IN_ONEOF_IN;
     133                 :           0 :                         }
     134                 :             :                         else                            /* shouldn't get here */
     135   [ #  #  #  # ]:           0 :                                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     136                 :         100 :                 }
     137   [ +  -  +  - ]:         332 :                 else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
     138                 :             :                 {
     139         [ +  + ]:         332 :                         if (t_isalpha(c))
     140                 :             :                         {
     141                 :         232 :                                 COPYCHAR(ptr->data + ptr->len, c);
     142                 :         232 :                                 ptr->len += pg_mblen(c);
     143                 :         232 :                         }
     144         [ +  - ]:         100 :                         else if (t_iseq(c, ']'))
     145                 :         100 :                                 state = RS_IN_WAIT;
     146                 :             :                         else                            /* shouldn't get here */
     147   [ #  #  #  # ]:           0 :                                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     148                 :         332 :                 }
     149                 :             :                 else
     150   [ #  #  #  # ]:           0 :                         elog(ERROR, "internal error in RS_compile: state %d", state);
     151                 :         546 :                 c += pg_mblen(c);
     152                 :             :         }
     153                 :             : 
     154         [ +  - ]:         100 :         if (state != RS_IN_WAIT)        /* shouldn't get here */
     155   [ #  #  #  # ]:           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     156                 :             : 
     157                 :         100 :         ptr = r->node;
     158         [ +  + ]:         214 :         while (ptr)
     159                 :             :         {
     160                 :         114 :                 r->nchar++;
     161                 :         114 :                 ptr = ptr->next;
     162                 :             :         }
     163                 :         100 : }
     164                 :             : 
     165                 :             : void
     166                 :           0 : RS_free(Regis *r)
     167                 :             : {
     168                 :           0 :         RegisNode  *ptr = r->node,
     169                 :             :                            *tmp;
     170                 :             : 
     171         [ #  # ]:           0 :         while (ptr)
     172                 :             :         {
     173                 :           0 :                 tmp = ptr->next;
     174                 :           0 :                 pfree(ptr);
     175                 :           0 :                 ptr = tmp;
     176                 :             :         }
     177                 :             : 
     178                 :           0 :         r->node = NULL;
     179                 :           0 : }
     180                 :             : 
     181                 :             : static bool
     182                 :         118 : mb_strchr(char *str, char *c)
     183                 :             : {
     184                 :         118 :         int                     clen,
     185                 :             :                                 plen,
     186                 :             :                                 i;
     187                 :         118 :         char       *ptr = str;
     188                 :         118 :         bool            res = false;
     189                 :             : 
     190                 :         118 :         clen = pg_mblen(c);
     191   [ +  +  +  + ]:         388 :         while (*ptr && !res)
     192                 :             :         {
     193                 :         270 :                 plen = pg_mblen(ptr);
     194         [ -  + ]:         270 :                 if (plen == clen)
     195                 :             :                 {
     196                 :         270 :                         i = plen;
     197                 :         270 :                         res = true;
     198         [ +  + ]:         276 :                         while (i--)
     199         [ +  + ]:         270 :                                 if (*(ptr + i) != *(c + i))
     200                 :             :                                 {
     201                 :         264 :                                         res = false;
     202                 :         264 :                                         break;
     203                 :             :                                 }
     204                 :         270 :                 }
     205                 :             : 
     206                 :         270 :                 ptr += plen;
     207                 :             :         }
     208                 :             : 
     209                 :         236 :         return res;
     210                 :         118 : }
     211                 :             : 
     212                 :             : bool
     213                 :         118 : RS_execute(Regis *r, char *str)
     214                 :             : {
     215                 :         118 :         RegisNode  *ptr = r->node;
     216                 :         118 :         char       *c = str;
     217                 :         118 :         int                     len = 0;
     218                 :             : 
     219         [ +  + ]:         780 :         while (*c)
     220                 :             :         {
     221                 :         662 :                 len++;
     222                 :         662 :                 c += pg_mblen(c);
     223                 :             :         }
     224                 :             : 
     225         [ +  + ]:         118 :         if (len < r->nchar)
     226                 :           6 :                 return 0;
     227                 :             : 
     228                 :         112 :         c = str;
     229         [ -  + ]:         112 :         if (r->issuffix)
     230                 :             :         {
     231                 :         112 :                 len -= r->nchar;
     232         [ +  + ]:         656 :                 while (len-- > 0)
     233                 :         544 :                         c += pg_mblen(c);
     234                 :         112 :         }
     235                 :             : 
     236                 :             : 
     237         [ +  + ]:         230 :         while (ptr)
     238                 :             :         {
     239      [ +  +  - ]:         118 :                 switch (ptr->type)
     240                 :             :                 {
     241                 :             :                         case RSF_ONEOF:
     242         [ -  + ]:           6 :                                 if (!mb_strchr((char *) ptr->data, c))
     243                 :           0 :                                         return false;
     244                 :           6 :                                 break;
     245                 :             :                         case RSF_NONEOF:
     246         [ +  - ]:         112 :                                 if (mb_strchr((char *) ptr->data, c))
     247                 :           0 :                                         return false;
     248                 :         112 :                                 break;
     249                 :             :                         default:
     250   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
     251                 :           0 :                 }
     252                 :         118 :                 ptr = ptr->next;
     253                 :         118 :                 c += pg_mblen(c);
     254                 :             :         }
     255                 :             : 
     256                 :         112 :         return true;
     257                 :         118 : }
        

Generated by: LCOV version 2.3.2-1