LCOV - differential code coverage report
Current view: top level - src/backend/tsearch - dict_synonym.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 86.7 % 90 78 12 78
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 4 4 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * dict_synonym.c
       4                 :  *      Synonym dictionary: replace word by its synonym
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  *
       9                 :  * IDENTIFICATION
      10                 :  *    src/backend/tsearch/dict_synonym.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres.h"
      15                 : 
      16                 : #include "commands/defrem.h"
      17                 : #include "tsearch/ts_locale.h"
      18                 : #include "tsearch/ts_utils.h"
      19                 : #include "utils/builtins.h"
      20                 : 
      21                 : typedef struct
      22                 : {
      23                 :     char       *in;
      24                 :     char       *out;
      25                 :     int         outlen;
      26                 :     uint16      flags;
      27                 : } Syn;
      28                 : 
      29                 : typedef struct
      30                 : {
      31                 :     int         len;            /* length of syn array */
      32                 :     Syn        *syn;
      33                 :     bool        case_sensitive;
      34                 : } DictSyn;
      35                 : 
      36                 : /*
      37                 :  * Finds the next whitespace-delimited word within the 'in' string.
      38                 :  * Returns a pointer to the first character of the word, and a pointer
      39                 :  * to the next byte after the last character in the word (in *end).
      40                 :  * Character '*' at the end of word will not be treated as word
      41                 :  * character if flags is not null.
      42                 :  */
      43                 : static char *
      44 CBC         220 : findwrd(char *in, char **end, uint16 *flags)
      45                 : {
      46                 :     char       *start;
      47                 :     char       *lastchar;
      48                 : 
      49                 :     /* Skip leading spaces */
      50             220 :     while (*in && t_isspace(in))
      51 UBC           0 :         in += pg_mblen(in);
      52                 : 
      53                 :     /* Return NULL on empty lines */
      54 CBC         220 :     if (*in == '\0')
      55                 :     {
      56 UBC           0 :         *end = NULL;
      57               0 :         return NULL;
      58                 :     }
      59                 : 
      60 CBC         220 :     lastchar = start = in;
      61                 : 
      62                 :     /* Find end of word */
      63            1606 :     while (*in && !t_isspace(in))
      64                 :     {
      65            1386 :         lastchar = in;
      66            1386 :         in += pg_mblen(in);
      67                 :     }
      68                 : 
      69             220 :     if (in - lastchar == 1 && t_iseq(lastchar, '*') && flags)
      70                 :     {
      71              22 :         *flags = TSL_PREFIX;
      72              22 :         *end = lastchar;
      73                 :     }
      74                 :     else
      75                 :     {
      76             198 :         if (flags)
      77              88 :             *flags = 0;
      78             198 :         *end = in;
      79                 :     }
      80                 : 
      81             220 :     return start;
      82                 : }
      83                 : 
      84                 : static int
      85             652 : compareSyn(const void *a, const void *b)
      86                 : {
      87             652 :     return strcmp(((const Syn *) a)->in, ((const Syn *) b)->in);
      88                 : }
      89                 : 
      90                 : 
      91                 : Datum
      92              25 : dsynonym_init(PG_FUNCTION_ARGS)
      93                 : {
      94              25 :     List       *dictoptions = (List *) PG_GETARG_POINTER(0);
      95                 :     DictSyn    *d;
      96                 :     ListCell   *l;
      97              25 :     char       *filename = NULL;
      98              25 :     bool        case_sensitive = false;
      99                 :     tsearch_readline_state trst;
     100                 :     char       *starti,
     101                 :                *starto,
     102              25 :                *end = NULL;
     103              25 :     int         cur = 0;
     104              25 :     char       *line = NULL;
     105              25 :     uint16      flags = 0;
     106                 : 
     107              66 :     foreach(l, dictoptions)
     108                 :     {
     109              44 :         DefElem    *defel = (DefElem *) lfirst(l);
     110                 : 
     111              44 :         if (strcmp(defel->defname, "synonyms") == 0)
     112              25 :             filename = defGetString(defel);
     113              19 :         else if (strcmp(defel->defname, "casesensitive") == 0)
     114              19 :             case_sensitive = defGetBoolean(defel);
     115                 :         else
     116 UBC           0 :             ereport(ERROR,
     117                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     118                 :                      errmsg("unrecognized synonym parameter: \"%s\"",
     119                 :                             defel->defname)));
     120                 :     }
     121                 : 
     122 CBC          22 :     if (!filename)
     123 UBC           0 :         ereport(ERROR,
     124                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     125                 :                  errmsg("missing Synonyms parameter")));
     126                 : 
     127 CBC          22 :     filename = get_tsearch_config_filename(filename, "syn");
     128                 : 
     129              22 :     if (!tsearch_readline_begin(&trst, filename))
     130 UBC           0 :         ereport(ERROR,
     131                 :                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
     132                 :                  errmsg("could not open synonym file \"%s\": %m",
     133                 :                         filename)));
     134                 : 
     135 CBC          22 :     d = (DictSyn *) palloc0(sizeof(DictSyn));
     136                 : 
     137             132 :     while ((line = tsearch_readline(&trst)) != NULL)
     138                 :     {
     139             110 :         starti = findwrd(line, &end, NULL);
     140             110 :         if (!starti)
     141                 :         {
     142                 :             /* Empty line */
     143 UBC           0 :             goto skipline;
     144                 :         }
     145 CBC         110 :         if (*end == '\0')
     146                 :         {
     147                 :             /* A line with only one word. Ignore silently. */
     148 UBC           0 :             goto skipline;
     149                 :         }
     150 CBC         110 :         *end = '\0';
     151                 : 
     152             110 :         starto = findwrd(end + 1, &end, &flags);
     153             110 :         if (!starto)
     154                 :         {
     155                 :             /* A line with only one word (+whitespace). Ignore silently. */
     156 UBC           0 :             goto skipline;
     157                 :         }
     158 CBC         110 :         *end = '\0';
     159                 : 
     160                 :         /*
     161                 :          * starti now points to the first word, and starto to the second word
     162                 :          * on the line, with a \0 terminator at the end of both words.
     163                 :          */
     164                 : 
     165             110 :         if (cur >= d->len)
     166                 :         {
     167              22 :             if (d->len == 0)
     168                 :             {
     169              22 :                 d->len = 64;
     170              22 :                 d->syn = (Syn *) palloc(sizeof(Syn) * d->len);
     171                 :             }
     172                 :             else
     173                 :             {
     174 UBC           0 :                 d->len *= 2;
     175               0 :                 d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len);
     176                 :             }
     177                 :         }
     178                 : 
     179 CBC         110 :         if (case_sensitive)
     180                 :         {
     181              30 :             d->syn[cur].in = pstrdup(starti);
     182              30 :             d->syn[cur].out = pstrdup(starto);
     183                 :         }
     184                 :         else
     185                 :         {
     186              80 :             d->syn[cur].in = lowerstr(starti);
     187              80 :             d->syn[cur].out = lowerstr(starto);
     188                 :         }
     189                 : 
     190             110 :         d->syn[cur].outlen = strlen(starto);
     191             110 :         d->syn[cur].flags = flags;
     192                 : 
     193             110 :         cur++;
     194                 : 
     195             110 : skipline:
     196             110 :         pfree(line);
     197                 :     }
     198                 : 
     199              22 :     tsearch_readline_end(&trst);
     200                 : 
     201              22 :     d->len = cur;
     202              22 :     qsort(d->syn, d->len, sizeof(Syn), compareSyn);
     203                 : 
     204              22 :     d->case_sensitive = case_sensitive;
     205                 : 
     206              22 :     PG_RETURN_POINTER(d);
     207                 : }
     208                 : 
     209                 : Datum
     210             183 : dsynonym_lexize(PG_FUNCTION_ARGS)
     211                 : {
     212             183 :     DictSyn    *d = (DictSyn *) PG_GETARG_POINTER(0);
     213             183 :     char       *in = (char *) PG_GETARG_POINTER(1);
     214             183 :     int32       len = PG_GETARG_INT32(2);
     215                 :     Syn         key,
     216                 :                *found;
     217                 :     TSLexeme   *res;
     218                 : 
     219                 :     /* note: d->len test protects against Solaris bsearch-of-no-items bug */
     220             183 :     if (len <= 0 || d->len <= 0)
     221 UBC           0 :         PG_RETURN_POINTER(NULL);
     222                 : 
     223 CBC         183 :     if (d->case_sensitive)
     224               3 :         key.in = pnstrdup(in, len);
     225                 :     else
     226             180 :         key.in = lowerstr_with_len(in, len);
     227                 : 
     228             183 :     key.out = NULL;
     229                 : 
     230             183 :     found = (Syn *) bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn);
     231             183 :     pfree(key.in);
     232                 : 
     233             183 :     if (!found)
     234             150 :         PG_RETURN_POINTER(NULL);
     235                 : 
     236              33 :     res = palloc0(sizeof(TSLexeme) * 2);
     237              33 :     res[0].lexeme = pnstrdup(found->out, found->outlen);
     238              33 :     res[0].flags = found->flags;
     239                 : 
     240              33 :     PG_RETURN_POINTER(res);
     241                 : }
        

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