LCOV - differential code coverage report
Current view: top level - src/backend/tsearch - regis.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 78.1 % 128 100 28 100
Current Date: 2023-04-08 15:15:32 Functions: 83.3 % 6 5 1 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * regis.c
       4                 :  *      Fast regex subset
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, 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 CBC         402 : RS_isRegis(const char *str)
      32                 : {
      33             402 :     int         state = RS_IN_WAIT;
      34             402 :     const char *c = str;
      35                 : 
      36            2436 :     while (*c)
      37                 :     {
      38            2100 :         if (state == RS_IN_WAIT)
      39                 :         {
      40             532 :             if (t_isalpha(c))
      41                 :                  /* okay */ ;
      42             418 :             else if (t_iseq(c, '['))
      43             352 :                 state = RS_IN_ONEOF;
      44                 :             else
      45              66 :                 return false;
      46                 :         }
      47            1568 :         else if (state == RS_IN_ONEOF)
      48                 :         {
      49             352 :             if (t_iseq(c, '^'))
      50             352 :                 state = RS_IN_NONEOF;
      51 UBC           0 :             else if (t_isalpha(c))
      52               0 :                 state = RS_IN_ONEOF_IN;
      53                 :             else
      54               0 :                 return false;
      55                 :         }
      56 CBC        1216 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
      57                 :         {
      58            1216 :             if (t_isalpha(c))
      59                 :                  /* okay */ ;
      60             352 :             else if (t_iseq(c, ']'))
      61             352 :                 state = RS_IN_WAIT;
      62                 :             else
      63 UBC           0 :                 return false;
      64                 :         }
      65                 :         else
      66               0 :             elog(ERROR, "internal error in RS_isRegis: state %d", state);
      67 CBC        2034 :         c += pg_mblen(c);
      68                 :     }
      69                 : 
      70             336 :     return (state == RS_IN_WAIT);
      71                 : }
      72                 : 
      73                 : static RegisNode *
      74             384 : newRegisNode(RegisNode *prev, int len)
      75                 : {
      76                 :     RegisNode  *ptr;
      77                 : 
      78             384 :     ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
      79             384 :     if (prev)
      80              48 :         prev->next = ptr;
      81             384 :     return ptr;
      82                 : }
      83                 : 
      84                 : void
      85             336 : RS_compile(Regis *r, bool issuffix, const char *str)
      86                 : {
      87             336 :     int         len = strlen(str);
      88             336 :     int         state = RS_IN_WAIT;
      89             336 :     const char *c = str;
      90             336 :     RegisNode  *ptr = NULL;
      91                 : 
      92             336 :     memset(r, 0, sizeof(Regis));
      93             336 :     r->issuffix = (issuffix) ? 1 : 0;
      94                 : 
      95            2176 :     while (*c)
      96                 :     {
      97            1840 :         if (state == RS_IN_WAIT)
      98                 :         {
      99             384 :             if (t_isalpha(c))
     100                 :             {
     101              48 :                 if (ptr)
     102              48 :                     ptr = newRegisNode(ptr, len);
     103                 :                 else
     104 UBC           0 :                     ptr = r->node = newRegisNode(NULL, len);
     105 CBC          48 :                 COPYCHAR(ptr->data, c);
     106              48 :                 ptr->type = RSF_ONEOF;
     107              48 :                 ptr->len = pg_mblen(c);
     108                 :             }
     109             336 :             else if (t_iseq(c, '['))
     110                 :             {
     111             336 :                 if (ptr)
     112 UBC           0 :                     ptr = newRegisNode(ptr, len);
     113                 :                 else
     114 CBC         336 :                     ptr = r->node = newRegisNode(NULL, len);
     115             336 :                 ptr->type = RSF_ONEOF;
     116             336 :                 state = RS_IN_ONEOF;
     117                 :             }
     118                 :             else                /* shouldn't get here */
     119 UBC           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     120                 :         }
     121 CBC        1456 :         else if (state == RS_IN_ONEOF)
     122                 :         {
     123             336 :             if (t_iseq(c, '^'))
     124                 :             {
     125             336 :                 ptr->type = RSF_NONEOF;
     126             336 :                 state = RS_IN_NONEOF;
     127                 :             }
     128 UBC           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                 :             }
     134                 :             else                /* shouldn't get here */
     135               0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     136                 :         }
     137 CBC        1120 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
     138                 :         {
     139            1120 :             if (t_isalpha(c))
     140                 :             {
     141             784 :                 COPYCHAR(ptr->data + ptr->len, c);
     142             784 :                 ptr->len += pg_mblen(c);
     143                 :             }
     144             336 :             else if (t_iseq(c, ']'))
     145             336 :                 state = RS_IN_WAIT;
     146                 :             else                /* shouldn't get here */
     147 UBC           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     148                 :         }
     149                 :         else
     150               0 :             elog(ERROR, "internal error in RS_compile: state %d", state);
     151 CBC        1840 :         c += pg_mblen(c);
     152                 :     }
     153                 : 
     154             336 :     if (state != RS_IN_WAIT)    /* shouldn't get here */
     155 UBC           0 :         elog(ERROR, "invalid regis pattern: \"%s\"", str);
     156                 : 
     157 CBC         336 :     ptr = r->node;
     158             720 :     while (ptr)
     159                 :     {
     160             384 :         r->nchar++;
     161             384 :         ptr = ptr->next;
     162                 :     }
     163             336 : }
     164                 : 
     165                 : void
     166 UBC           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 CBC         354 : mb_strchr(char *str, char *c)
     183                 : {
     184                 :     int         clen,
     185                 :                 plen,
     186                 :                 i;
     187             354 :     char       *ptr = str;
     188             354 :     bool        res = false;
     189                 : 
     190             354 :     clen = pg_mblen(c);
     191            1164 :     while (*ptr && !res)
     192                 :     {
     193             810 :         plen = pg_mblen(ptr);
     194             810 :         if (plen == clen)
     195                 :         {
     196             810 :             i = plen;
     197             810 :             res = true;
     198             828 :             while (i--)
     199             810 :                 if (*(ptr + i) != *(c + i))
     200                 :                 {
     201             792 :                     res = false;
     202             792 :                     break;
     203                 :                 }
     204                 :         }
     205                 : 
     206             810 :         ptr += plen;
     207                 :     }
     208                 : 
     209             354 :     return res;
     210                 : }
     211                 : 
     212                 : bool
     213             354 : RS_execute(Regis *r, char *str)
     214                 : {
     215             354 :     RegisNode  *ptr = r->node;
     216             354 :     char       *c = str;
     217             354 :     int         len = 0;
     218                 : 
     219            2340 :     while (*c)
     220                 :     {
     221            1986 :         len++;
     222            1986 :         c += pg_mblen(c);
     223                 :     }
     224                 : 
     225             354 :     if (len < r->nchar)
     226              18 :         return 0;
     227                 : 
     228             336 :     c = str;
     229             336 :     if (r->issuffix)
     230                 :     {
     231             336 :         len -= r->nchar;
     232            1968 :         while (len-- > 0)
     233            1632 :             c += pg_mblen(c);
     234                 :     }
     235                 : 
     236                 : 
     237             690 :     while (ptr)
     238                 :     {
     239             354 :         switch (ptr->type)
     240                 :         {
     241              18 :             case RSF_ONEOF:
     242              18 :                 if (!mb_strchr((char *) ptr->data, c))
     243 UBC           0 :                     return false;
     244 CBC          18 :                 break;
     245             336 :             case RSF_NONEOF:
     246             336 :                 if (mb_strchr((char *) ptr->data, c))
     247 UBC           0 :                     return false;
     248 CBC         336 :                 break;
     249 UBC           0 :             default:
     250               0 :                 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
     251                 :         }
     252 CBC         354 :         ptr = ptr->next;
     253             354 :         c += pg_mblen(c);
     254                 :     }
     255                 : 
     256             336 :     return true;
     257                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a