LCOV - code coverage report
Current view: top level - src/backend/tsearch - dict_ispell.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 44 57 77.2 %
Date: 2025-08-31 11:18:25 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * dict_ispell.c
       4             :  *      Ispell dictionary interface
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/tsearch/dict_ispell.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "catalog/pg_collation_d.h"
      17             : #include "commands/defrem.h"
      18             : #include "tsearch/dicts/spell.h"
      19             : #include "tsearch/ts_public.h"
      20             : #include "utils/fmgrprotos.h"
      21             : #include "utils/formatting.h"
      22             : 
      23             : 
      24             : typedef struct
      25             : {
      26             :     StopList    stoplist;
      27             :     IspellDict  obj;
      28             : } DictISpell;
      29             : 
      30             : Datum
      31         134 : dispell_init(PG_FUNCTION_ARGS)
      32             : {
      33         134 :     List       *dictoptions = (List *) PG_GETARG_POINTER(0);
      34             :     DictISpell *d;
      35         134 :     bool        affloaded = false,
      36         134 :                 dictloaded = false,
      37         134 :                 stoploaded = false;
      38             :     ListCell   *l;
      39             : 
      40         134 :     d = (DictISpell *) palloc0(sizeof(DictISpell));
      41             : 
      42         134 :     NIStartBuild(&(d->obj));
      43             : 
      44         390 :     foreach(l, dictoptions)
      45             :     {
      46         262 :         DefElem    *defel = (DefElem *) lfirst(l);
      47             : 
      48         262 :         if (strcmp(defel->defname, "dictfile") == 0)
      49             :         {
      50             :             char       *filename;
      51             : 
      52         128 :             if (dictloaded)
      53           0 :                 ereport(ERROR,
      54             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      55             :                          errmsg("multiple DictFile parameters")));
      56         128 :             filename = get_tsearch_config_filename(defGetString(defel),
      57             :                                                    "dict");
      58         128 :             NIImportDictionary(&(d->obj), filename);
      59         128 :             pfree(filename);
      60         128 :             dictloaded = true;
      61             :         }
      62         134 :         else if (strcmp(defel->defname, "afffile") == 0)
      63             :         {
      64             :             char       *filename;
      65             : 
      66         128 :             if (affloaded)
      67           0 :                 ereport(ERROR,
      68             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      69             :                          errmsg("multiple AffFile parameters")));
      70         128 :             filename = get_tsearch_config_filename(defGetString(defel),
      71             :                                                    "affix");
      72         128 :             NIImportAffixes(&(d->obj), filename);
      73         128 :             pfree(filename);
      74         128 :             affloaded = true;
      75             :         }
      76           6 :         else if (strcmp(defel->defname, "stopwords") == 0)
      77             :         {
      78           0 :             if (stoploaded)
      79           0 :                 ereport(ERROR,
      80             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      81             :                          errmsg("multiple StopWords parameters")));
      82           0 :             readstoplist(defGetString(defel), &(d->stoplist), str_tolower);
      83           0 :             stoploaded = true;
      84             :         }
      85             :         else
      86             :         {
      87           6 :             ereport(ERROR,
      88             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      89             :                      errmsg("unrecognized Ispell parameter: \"%s\"",
      90             :                             defel->defname)));
      91             :         }
      92             :     }
      93             : 
      94         128 :     if (affloaded && dictloaded)
      95             :     {
      96         128 :         NISortDictionary(&(d->obj));
      97         110 :         NISortAffixes(&(d->obj));
      98             :     }
      99           0 :     else if (!affloaded)
     100             :     {
     101           0 :         ereport(ERROR,
     102             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     103             :                  errmsg("missing AffFile parameter")));
     104             :     }
     105             :     else
     106             :     {
     107           0 :         ereport(ERROR,
     108             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     109             :                  errmsg("missing DictFile parameter")));
     110             :     }
     111             : 
     112         110 :     NIFinishBuild(&(d->obj));
     113             : 
     114         110 :     PG_RETURN_POINTER(d);
     115             : }
     116             : 
     117             : Datum
     118         750 : dispell_lexize(PG_FUNCTION_ARGS)
     119             : {
     120         750 :     DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
     121         750 :     char       *in = (char *) PG_GETARG_POINTER(1);
     122         750 :     int32       len = PG_GETARG_INT32(2);
     123             :     char       *txt;
     124             :     TSLexeme   *res;
     125             :     TSLexeme   *ptr,
     126             :                *cptr;
     127             : 
     128         750 :     if (len <= 0)
     129           0 :         PG_RETURN_POINTER(NULL);
     130             : 
     131         750 :     txt = str_tolower(in, len, DEFAULT_COLLATION_OID);
     132         750 :     res = NINormalizeWord(&(d->obj), txt);
     133             : 
     134         750 :     if (res == NULL)
     135         144 :         PG_RETURN_POINTER(NULL);
     136             : 
     137         606 :     cptr = res;
     138        1920 :     for (ptr = cptr; ptr->lexeme; ptr++)
     139             :     {
     140        1314 :         if (searchstoplist(&(d->stoplist), ptr->lexeme))
     141             :         {
     142           0 :             pfree(ptr->lexeme);
     143           0 :             ptr->lexeme = NULL;
     144             :         }
     145             :         else
     146             :         {
     147        1314 :             if (cptr != ptr)
     148           0 :                 memcpy(cptr, ptr, sizeof(TSLexeme));
     149        1314 :             cptr++;
     150             :         }
     151             :     }
     152         606 :     cptr->lexeme = NULL;
     153             : 
     154         606 :     PG_RETURN_POINTER(res);
     155             : }

Generated by: LCOV version 1.16