LCOV - code coverage report
Current view: top level - src/backend/tsearch - to_tsany.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 96.5 % 284 274
Test Date: 2026-03-01 22:14:38 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * to_tsany.c
       4              :  *      to_ts* function definitions
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  *
       9              :  * IDENTIFICATION
      10              :  *    src/backend/tsearch/to_tsany.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : #include "postgres.h"
      15              : 
      16              : #include "tsearch/ts_cache.h"
      17              : #include "tsearch/ts_utils.h"
      18              : #include "utils/builtins.h"
      19              : #include "utils/jsonfuncs.h"
      20              : 
      21              : 
      22              : /*
      23              :  * Opaque data structure, which is passed by parse_tsquery() to pushval_morph().
      24              :  */
      25              : typedef struct MorphOpaque
      26              : {
      27              :     Oid         cfg_id;
      28              : 
      29              :     /*
      30              :      * Single tsquery morph could be parsed into multiple words.  When these
      31              :      * words reside in adjacent positions, they are connected using this
      32              :      * operator.  Usually, that is OP_PHRASE, which requires word positions of
      33              :      * a complex morph to exactly match the tsvector.
      34              :      */
      35              :     int         qoperator;
      36              : } MorphOpaque;
      37              : 
      38              : typedef struct TSVectorBuildState
      39              : {
      40              :     ParsedText *prs;
      41              :     Oid         cfgId;
      42              : } TSVectorBuildState;
      43              : 
      44              : static void add_to_tsvector(void *_state, char *elem_value, int elem_len);
      45              : 
      46              : 
      47              : Datum
      48            0 : get_current_ts_config(PG_FUNCTION_ARGS)
      49              : {
      50            0 :     PG_RETURN_OID(getTSCurrentConfig(true));
      51              : }
      52              : 
      53              : /*
      54              :  * to_tsvector
      55              :  */
      56              : static int
      57         6229 : compareWORD(const void *a, const void *b)
      58              : {
      59              :     int         res;
      60              : 
      61         6229 :     res = tsCompareString(((const ParsedWord *) a)->word, ((const ParsedWord *) a)->len,
      62         6229 :                           ((const ParsedWord *) b)->word, ((const ParsedWord *) b)->len,
      63              :                           false);
      64              : 
      65         6229 :     if (res == 0)
      66              :     {
      67          525 :         if (((const ParsedWord *) a)->pos.pos == ((const ParsedWord *) b)->pos.pos)
      68           12 :             return 0;
      69              : 
      70          513 :         res = (((const ParsedWord *) a)->pos.pos > ((const ParsedWord *) b)->pos.pos) ? 1 : -1;
      71              :     }
      72              : 
      73         6217 :     return res;
      74              : }
      75              : 
      76              : static int
      77          338 : uniqueWORD(ParsedWord *a, int32 l)
      78              : {
      79              :     ParsedWord *ptr,
      80              :                *res;
      81              :     int         tmppos;
      82              : 
      83          338 :     if (l == 1)
      84              :     {
      85           13 :         tmppos = LIMITPOS(a->pos.pos);
      86           13 :         a->alen = 2;
      87           13 :         a->pos.apos = palloc_array(uint16, a->alen);
      88           13 :         a->pos.apos[0] = 1;
      89           13 :         a->pos.apos[1] = tmppos;
      90           13 :         return l;
      91              :     }
      92              : 
      93          325 :     res = a;
      94          325 :     ptr = a + 1;
      95              : 
      96              :     /*
      97              :      * Sort words with its positions
      98              :      */
      99          325 :     qsort(a, l, sizeof(ParsedWord), compareWORD);
     100              : 
     101              :     /*
     102              :      * Initialize first word and its first position
     103              :      */
     104          325 :     tmppos = LIMITPOS(a->pos.pos);
     105          325 :     a->alen = 2;
     106          325 :     a->pos.apos = palloc_array(uint16, a->alen);
     107          325 :     a->pos.apos[0] = 1;
     108          325 :     a->pos.apos[1] = tmppos;
     109              : 
     110              :     /*
     111              :      * Summarize position information for each word
     112              :      */
     113         2096 :     while (ptr - a < l)
     114              :     {
     115         1771 :         if (!(ptr->len == res->len &&
     116         1015 :               strncmp(ptr->word, res->word, res->len) == 0))
     117              :         {
     118              :             /*
     119              :              * Got a new word, so put it in result
     120              :              */
     121         1444 :             res++;
     122         1444 :             res->len = ptr->len;
     123         1444 :             res->word = ptr->word;
     124         1444 :             tmppos = LIMITPOS(ptr->pos.pos);
     125         1444 :             res->alen = 2;
     126         1444 :             res->pos.apos = palloc_array(uint16, res->alen);
     127         1444 :             res->pos.apos[0] = 1;
     128         1444 :             res->pos.apos[1] = tmppos;
     129              :         }
     130              :         else
     131              :         {
     132              :             /*
     133              :              * The word already exists, so adjust position information. But
     134              :              * before we should check size of position's array, max allowed
     135              :              * value for position and uniqueness of position
     136              :              */
     137          327 :             pfree(ptr->word);
     138          327 :             if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1 &&
     139          327 :                 res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
     140              :             {
     141          315 :                 if (res->pos.apos[0] + 1 >= res->alen)
     142              :                 {
     143          252 :                     res->alen *= 2;
     144          252 :                     res->pos.apos = repalloc_array(res->pos.apos, uint16, res->alen);
     145              :                 }
     146          315 :                 if (res->pos.apos[0] == 0 || res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
     147              :                 {
     148          315 :                     res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
     149          315 :                     res->pos.apos[0]++;
     150              :                 }
     151              :             }
     152              :         }
     153         1771 :         ptr++;
     154              :     }
     155              : 
     156          325 :     return res + 1 - a;
     157              : }
     158              : 
     159              : /*
     160              :  * make value of tsvector, given parsed text
     161              :  *
     162              :  * Note: frees prs->words and subsidiary data.
     163              :  */
     164              : TSVector
     165          398 : make_tsvector(ParsedText *prs)
     166              : {
     167              :     int         i,
     168              :                 j,
     169          398 :                 lenstr = 0,
     170              :                 totallen;
     171              :     TSVector    in;
     172              :     WordEntry  *ptr;
     173              :     char       *str;
     174              :     int         stroff;
     175              : 
     176              :     /* Merge duplicate words */
     177          398 :     if (prs->curwords > 0)
     178          338 :         prs->curwords = uniqueWORD(prs->words, prs->curwords);
     179              : 
     180              :     /* Determine space needed */
     181         2180 :     for (i = 0; i < prs->curwords; i++)
     182              :     {
     183         1782 :         lenstr += prs->words[i].len;
     184         1782 :         if (prs->words[i].alen)
     185              :         {
     186         1782 :             lenstr = SHORTALIGN(lenstr);
     187         1782 :             lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
     188              :         }
     189              :     }
     190              : 
     191          398 :     if (lenstr > MAXSTRPOS)
     192            0 :         ereport(ERROR,
     193              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     194              :                  errmsg("string is too long for tsvector (%d bytes, max %d bytes)", lenstr, MAXSTRPOS)));
     195              : 
     196          398 :     totallen = CALCDATASIZE(prs->curwords, lenstr);
     197          398 :     in = (TSVector) palloc0(totallen);
     198          398 :     SET_VARSIZE(in, totallen);
     199          398 :     in->size = prs->curwords;
     200              : 
     201          398 :     ptr = ARRPTR(in);
     202          398 :     str = STRPTR(in);
     203          398 :     stroff = 0;
     204         2180 :     for (i = 0; i < prs->curwords; i++)
     205              :     {
     206         1782 :         ptr->len = prs->words[i].len;
     207         1782 :         ptr->pos = stroff;
     208         1782 :         memcpy(str + stroff, prs->words[i].word, prs->words[i].len);
     209         1782 :         stroff += prs->words[i].len;
     210         1782 :         pfree(prs->words[i].word);
     211         1782 :         if (prs->words[i].alen)
     212              :         {
     213         1782 :             int         k = prs->words[i].pos.apos[0];
     214              :             WordEntryPos *wptr;
     215              : 
     216         1782 :             if (k > 0xFFFF)
     217            0 :                 elog(ERROR, "positions array too long");
     218              : 
     219         1782 :             ptr->haspos = 1;
     220         1782 :             stroff = SHORTALIGN(stroff);
     221         1782 :             *(uint16 *) (str + stroff) = (uint16) k;
     222         1782 :             wptr = POSDATAPTR(in, ptr);
     223         3879 :             for (j = 0; j < k; j++)
     224              :             {
     225         2097 :                 WEP_SETWEIGHT(wptr[j], 0);
     226         2097 :                 WEP_SETPOS(wptr[j], prs->words[i].pos.apos[j + 1]);
     227              :             }
     228         1782 :             stroff += sizeof(uint16) + k * sizeof(WordEntryPos);
     229         1782 :             pfree(prs->words[i].pos.apos);
     230              :         }
     231              :         else
     232            0 :             ptr->haspos = 0;
     233         1782 :         ptr++;
     234              :     }
     235              : 
     236          398 :     if (prs->words)
     237          356 :         pfree(prs->words);
     238              : 
     239          398 :     return in;
     240              : }
     241              : 
     242              : Datum
     243          239 : to_tsvector_byid(PG_FUNCTION_ARGS)
     244              : {
     245          239 :     Oid         cfgId = PG_GETARG_OID(0);
     246          239 :     text       *in = PG_GETARG_TEXT_PP(1);
     247              :     ParsedText  prs;
     248              :     TSVector    out;
     249              : 
     250          239 :     prs.lenwords = VARSIZE_ANY_EXHDR(in) / 6;   /* just estimation of word's
     251              :                                                  * number */
     252          239 :     if (prs.lenwords < 2)
     253          169 :         prs.lenwords = 2;
     254           70 :     else if (prs.lenwords > MaxAllocSize / sizeof(ParsedWord))
     255            0 :         prs.lenwords = MaxAllocSize / sizeof(ParsedWord);
     256          239 :     prs.curwords = 0;
     257          239 :     prs.pos = 0;
     258          239 :     prs.words = palloc_array(ParsedWord, prs.lenwords);
     259              : 
     260          239 :     parsetext(cfgId, &prs, VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
     261              : 
     262          239 :     PG_FREE_IF_COPY(in, 1);
     263              : 
     264          239 :     out = make_tsvector(&prs);
     265              : 
     266          239 :     PG_RETURN_TSVECTOR(out);
     267              : }
     268              : 
     269              : Datum
     270           27 : to_tsvector(PG_FUNCTION_ARGS)
     271              : {
     272           27 :     text       *in = PG_GETARG_TEXT_PP(0);
     273              :     Oid         cfgId;
     274              : 
     275           27 :     cfgId = getTSCurrentConfig(true);
     276           27 :     PG_RETURN_DATUM(DirectFunctionCall2(to_tsvector_byid,
     277              :                                         ObjectIdGetDatum(cfgId),
     278              :                                         PointerGetDatum(in)));
     279              : }
     280              : 
     281              : /*
     282              :  * Worker function for jsonb(_string)_to_tsvector(_byid)
     283              :  */
     284              : static TSVector
     285           75 : jsonb_to_tsvector_worker(Oid cfgId, Jsonb *jb, uint32 flags)
     286              : {
     287              :     TSVectorBuildState state;
     288              :     ParsedText  prs;
     289              : 
     290           75 :     prs.words = NULL;
     291           75 :     prs.curwords = 0;
     292           75 :     state.prs = &prs;
     293           75 :     state.cfgId = cfgId;
     294              : 
     295           75 :     iterate_jsonb_values(jb, flags, &state, add_to_tsvector);
     296              : 
     297           75 :     return make_tsvector(&prs);
     298              : }
     299              : 
     300              : Datum
     301            9 : jsonb_string_to_tsvector_byid(PG_FUNCTION_ARGS)
     302              : {
     303            9 :     Oid         cfgId = PG_GETARG_OID(0);
     304            9 :     Jsonb      *jb = PG_GETARG_JSONB_P(1);
     305              :     TSVector    result;
     306              : 
     307            9 :     result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
     308            9 :     PG_FREE_IF_COPY(jb, 1);
     309              : 
     310            9 :     PG_RETURN_TSVECTOR(result);
     311              : }
     312              : 
     313              : Datum
     314           15 : jsonb_string_to_tsvector(PG_FUNCTION_ARGS)
     315              : {
     316           15 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     317              :     Oid         cfgId;
     318              :     TSVector    result;
     319              : 
     320           15 :     cfgId = getTSCurrentConfig(true);
     321           15 :     result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
     322           15 :     PG_FREE_IF_COPY(jb, 0);
     323              : 
     324           15 :     PG_RETURN_TSVECTOR(result);
     325              : }
     326              : 
     327              : Datum
     328           51 : jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
     329              : {
     330           51 :     Oid         cfgId = PG_GETARG_OID(0);
     331           51 :     Jsonb      *jb = PG_GETARG_JSONB_P(1);
     332           51 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(2);
     333              :     TSVector    result;
     334           51 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     335              : 
     336           39 :     result = jsonb_to_tsvector_worker(cfgId, jb, flags);
     337           39 :     PG_FREE_IF_COPY(jb, 1);
     338           39 :     PG_FREE_IF_COPY(jbFlags, 2);
     339              : 
     340           39 :     PG_RETURN_TSVECTOR(result);
     341              : }
     342              : 
     343              : Datum
     344           12 : jsonb_to_tsvector(PG_FUNCTION_ARGS)
     345              : {
     346           12 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     347           12 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(1);
     348              :     Oid         cfgId;
     349              :     TSVector    result;
     350           12 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     351              : 
     352           12 :     cfgId = getTSCurrentConfig(true);
     353           12 :     result = jsonb_to_tsvector_worker(cfgId, jb, flags);
     354           12 :     PG_FREE_IF_COPY(jb, 0);
     355           12 :     PG_FREE_IF_COPY(jbFlags, 1);
     356              : 
     357           12 :     PG_RETURN_TSVECTOR(result);
     358              : }
     359              : 
     360              : /*
     361              :  * Worker function for json(_string)_to_tsvector(_byid)
     362              :  */
     363              : static TSVector
     364           75 : json_to_tsvector_worker(Oid cfgId, text *json, uint32 flags)
     365              : {
     366              :     TSVectorBuildState state;
     367              :     ParsedText  prs;
     368              : 
     369           75 :     prs.words = NULL;
     370           75 :     prs.curwords = 0;
     371           75 :     state.prs = &prs;
     372           75 :     state.cfgId = cfgId;
     373              : 
     374           75 :     iterate_json_values(json, flags, &state, add_to_tsvector);
     375              : 
     376           75 :     return make_tsvector(&prs);
     377              : }
     378              : 
     379              : Datum
     380            9 : json_string_to_tsvector_byid(PG_FUNCTION_ARGS)
     381              : {
     382            9 :     Oid         cfgId = PG_GETARG_OID(0);
     383            9 :     text       *json = PG_GETARG_TEXT_P(1);
     384              :     TSVector    result;
     385              : 
     386            9 :     result = json_to_tsvector_worker(cfgId, json, jtiString);
     387            9 :     PG_FREE_IF_COPY(json, 1);
     388              : 
     389            9 :     PG_RETURN_TSVECTOR(result);
     390              : }
     391              : 
     392              : Datum
     393           15 : json_string_to_tsvector(PG_FUNCTION_ARGS)
     394              : {
     395           15 :     text       *json = PG_GETARG_TEXT_P(0);
     396              :     Oid         cfgId;
     397              :     TSVector    result;
     398              : 
     399           15 :     cfgId = getTSCurrentConfig(true);
     400           15 :     result = json_to_tsvector_worker(cfgId, json, jtiString);
     401           15 :     PG_FREE_IF_COPY(json, 0);
     402              : 
     403           15 :     PG_RETURN_TSVECTOR(result);
     404              : }
     405              : 
     406              : Datum
     407           51 : json_to_tsvector_byid(PG_FUNCTION_ARGS)
     408              : {
     409           51 :     Oid         cfgId = PG_GETARG_OID(0);
     410           51 :     text       *json = PG_GETARG_TEXT_P(1);
     411           51 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(2);
     412              :     TSVector    result;
     413           51 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     414              : 
     415           39 :     result = json_to_tsvector_worker(cfgId, json, flags);
     416           39 :     PG_FREE_IF_COPY(json, 1);
     417           39 :     PG_FREE_IF_COPY(jbFlags, 2);
     418              : 
     419           39 :     PG_RETURN_TSVECTOR(result);
     420              : }
     421              : 
     422              : Datum
     423           12 : json_to_tsvector(PG_FUNCTION_ARGS)
     424              : {
     425           12 :     text       *json = PG_GETARG_TEXT_P(0);
     426           12 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(1);
     427              :     Oid         cfgId;
     428              :     TSVector    result;
     429           12 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     430              : 
     431           12 :     cfgId = getTSCurrentConfig(true);
     432           12 :     result = json_to_tsvector_worker(cfgId, json, flags);
     433           12 :     PG_FREE_IF_COPY(json, 0);
     434           12 :     PG_FREE_IF_COPY(jbFlags, 1);
     435              : 
     436           12 :     PG_RETURN_TSVECTOR(result);
     437              : }
     438              : 
     439              : /*
     440              :  * Parse lexemes in an element of a json(b) value, add to TSVectorBuildState.
     441              :  */
     442              : static void
     443          372 : add_to_tsvector(void *_state, char *elem_value, int elem_len)
     444              : {
     445          372 :     TSVectorBuildState *state = (TSVectorBuildState *) _state;
     446          372 :     ParsedText *prs = state->prs;
     447              :     int32       prevwords;
     448              : 
     449          372 :     if (prs->words == NULL)
     450              :     {
     451              :         /*
     452              :          * First time through: initialize words array to a reasonable size.
     453              :          * (parsetext() will realloc it bigger as needed.)
     454              :          */
     455          108 :         prs->lenwords = 16;
     456          108 :         prs->words = palloc_array(ParsedWord, prs->lenwords);
     457          108 :         prs->curwords = 0;
     458          108 :         prs->pos = 0;
     459              :     }
     460              : 
     461          372 :     prevwords = prs->curwords;
     462              : 
     463          372 :     parsetext(state->cfgId, prs, elem_value, elem_len);
     464              : 
     465              :     /*
     466              :      * If we extracted any words from this JSON element, advance pos to create
     467              :      * an artificial break between elements.  This is because we don't want
     468              :      * phrase searches to think that the last word in this element is adjacent
     469              :      * to the first word in the next one.
     470              :      */
     471          372 :     if (prs->curwords > prevwords)
     472          336 :         prs->pos += 1;
     473          372 : }
     474              : 
     475              : 
     476              : /*
     477              :  * to_tsquery
     478              :  */
     479              : 
     480              : 
     481              : /*
     482              :  * This function is used for morph parsing.
     483              :  *
     484              :  * The value is passed to parsetext which will call the right dictionary to
     485              :  * lexize the word. If it turns out to be a stopword, we push a QI_VALSTOP
     486              :  * to the stack.
     487              :  *
     488              :  * All words belonging to the same variant are pushed as an ANDed list,
     489              :  * and different variants are ORed together.
     490              :  */
     491              : static void
     492         1556 : pushval_morph(void *opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
     493              : {
     494         1556 :     int32       count = 0;
     495              :     ParsedText  prs;
     496              :     uint32      variant,
     497         1556 :                 pos = 0,
     498         1556 :                 cntvar = 0,
     499         1556 :                 cntpos = 0,
     500         1556 :                 cnt = 0;
     501         1556 :     MorphOpaque *data = opaque;
     502              : 
     503         1556 :     prs.lenwords = 4;
     504         1556 :     prs.curwords = 0;
     505         1556 :     prs.pos = 0;
     506         1556 :     prs.words = palloc_array(ParsedWord, prs.lenwords);
     507              : 
     508         1556 :     parsetext(data->cfg_id, &prs, strval, lenval);
     509              : 
     510         1556 :     if (prs.curwords > 0)
     511              :     {
     512         2698 :         while (count < prs.curwords)
     513              :         {
     514              :             /*
     515              :              * Were any stop words removed? If so, fill empty positions with
     516              :              * placeholders linked by an appropriate operator.
     517              :              */
     518         1451 :             if (pos > 0 && pos + 1 < prs.words[count].pos.pos)
     519              :             {
     520           39 :                 while (pos + 1 < prs.words[count].pos.pos)
     521              :                 {
     522              :                     /* put placeholders for each missing stop word */
     523           24 :                     pushStop(state);
     524           24 :                     if (cntpos)
     525           24 :                         pushOperator(state, data->qoperator, 1);
     526           24 :                     cntpos++;
     527           24 :                     pos++;
     528              :                 }
     529              :             }
     530              : 
     531              :             /* save current word's position */
     532         1451 :             pos = prs.words[count].pos.pos;
     533              : 
     534              :             /* Go through all variants obtained from this token */
     535         1451 :             cntvar = 0;
     536         2938 :             while (count < prs.curwords && pos == prs.words[count].pos.pos)
     537              :             {
     538         1487 :                 variant = prs.words[count].nvariant;
     539              : 
     540              :                 /* Push all words belonging to the same variant */
     541         1487 :                 cnt = 0;
     542         1487 :                 while (count < prs.curwords &&
     543         3046 :                        pos == prs.words[count].pos.pos &&
     544         1595 :                        variant == prs.words[count].nvariant)
     545              :                 {
     546         1559 :                     pushValue(state,
     547         1559 :                               prs.words[count].word,
     548         1559 :                               prs.words[count].len,
     549              :                               weight,
     550         1559 :                               ((prs.words[count].flags & TSL_PREFIX) || prefix));
     551         1559 :                     pfree(prs.words[count].word);
     552         1559 :                     if (cnt)
     553           72 :                         pushOperator(state, OP_AND, 0);
     554         1559 :                     cnt++;
     555         1559 :                     count++;
     556              :                 }
     557              : 
     558         1487 :                 if (cntvar)
     559           36 :                     pushOperator(state, OP_OR, 0);
     560         1487 :                 cntvar++;
     561              :             }
     562              : 
     563         1451 :             if (cntpos)
     564              :             {
     565              :                 /* distance may be useful */
     566          204 :                 pushOperator(state, data->qoperator, 1);
     567              :             }
     568              : 
     569         1451 :             cntpos++;
     570              :         }
     571              : 
     572         1247 :         pfree(prs.words);
     573              :     }
     574              :     else
     575          309 :         pushStop(state);
     576         1556 : }
     577              : 
     578              : Datum
     579          377 : to_tsquery_byid(PG_FUNCTION_ARGS)
     580              : {
     581          377 :     text       *in = PG_GETARG_TEXT_PP(1);
     582              :     TSQuery     query;
     583              :     MorphOpaque data;
     584              : 
     585          377 :     data.cfg_id = PG_GETARG_OID(0);
     586              : 
     587              :     /*
     588              :      * Passing OP_PHRASE as a qoperator makes tsquery require matching of word
     589              :      * positions of a complex morph exactly match the tsvector.  Also, when
     590              :      * the complex morphs are connected with OP_PHRASE operator, we connect
     591              :      * all their words into the OP_PHRASE sequence.
     592              :      */
     593          377 :     data.qoperator = OP_PHRASE;
     594              : 
     595          377 :     query = parse_tsquery(text_to_cstring(in),
     596              :                           pushval_morph,
     597              :                           &data,
     598              :                           0,
     599              :                           NULL);
     600              : 
     601          377 :     PG_RETURN_TSQUERY(query);
     602              : }
     603              : 
     604              : Datum
     605           66 : to_tsquery(PG_FUNCTION_ARGS)
     606              : {
     607           66 :     text       *in = PG_GETARG_TEXT_PP(0);
     608              :     Oid         cfgId;
     609              : 
     610           66 :     cfgId = getTSCurrentConfig(true);
     611           66 :     PG_RETURN_DATUM(DirectFunctionCall2(to_tsquery_byid,
     612              :                                         ObjectIdGetDatum(cfgId),
     613              :                                         PointerGetDatum(in)));
     614              : }
     615              : 
     616              : Datum
     617           30 : plainto_tsquery_byid(PG_FUNCTION_ARGS)
     618              : {
     619           30 :     text       *in = PG_GETARG_TEXT_PP(1);
     620              :     TSQuery     query;
     621              :     MorphOpaque data;
     622              : 
     623           30 :     data.cfg_id = PG_GETARG_OID(0);
     624              : 
     625              :     /*
     626              :      * parse_tsquery() with P_TSQ_PLAIN flag takes the whole input text as a
     627              :      * single morph.  Passing OP_PHRASE as a qoperator makes tsquery require
     628              :      * matching of all words independently on their positions.
     629              :      */
     630           30 :     data.qoperator = OP_AND;
     631              : 
     632           30 :     query = parse_tsquery(text_to_cstring(in),
     633              :                           pushval_morph,
     634              :                           &data,
     635              :                           P_TSQ_PLAIN,
     636              :                           NULL);
     637              : 
     638           30 :     PG_RETURN_POINTER(query);
     639              : }
     640              : 
     641              : Datum
     642            6 : plainto_tsquery(PG_FUNCTION_ARGS)
     643              : {
     644            6 :     text       *in = PG_GETARG_TEXT_PP(0);
     645              :     Oid         cfgId;
     646              : 
     647            6 :     cfgId = getTSCurrentConfig(true);
     648            6 :     PG_RETURN_DATUM(DirectFunctionCall2(plainto_tsquery_byid,
     649              :                                         ObjectIdGetDatum(cfgId),
     650              :                                         PointerGetDatum(in)));
     651              : }
     652              : 
     653              : 
     654              : Datum
     655           24 : phraseto_tsquery_byid(PG_FUNCTION_ARGS)
     656              : {
     657           24 :     text       *in = PG_GETARG_TEXT_PP(1);
     658              :     TSQuery     query;
     659              :     MorphOpaque data;
     660              : 
     661           24 :     data.cfg_id = PG_GETARG_OID(0);
     662              : 
     663              :     /*
     664              :      * parse_tsquery() with P_TSQ_PLAIN flag takes the whole input text as a
     665              :      * single morph.  Passing OP_PHRASE as a qoperator makes tsquery require
     666              :      * matching of word positions.
     667              :      */
     668           24 :     data.qoperator = OP_PHRASE;
     669              : 
     670           24 :     query = parse_tsquery(text_to_cstring(in),
     671              :                           pushval_morph,
     672              :                           &data,
     673              :                           P_TSQ_PLAIN,
     674              :                           NULL);
     675              : 
     676           24 :     PG_RETURN_TSQUERY(query);
     677              : }
     678              : 
     679              : Datum
     680            0 : phraseto_tsquery(PG_FUNCTION_ARGS)
     681              : {
     682            0 :     text       *in = PG_GETARG_TEXT_PP(0);
     683              :     Oid         cfgId;
     684              : 
     685            0 :     cfgId = getTSCurrentConfig(true);
     686            0 :     PG_RETURN_DATUM(DirectFunctionCall2(phraseto_tsquery_byid,
     687              :                                         ObjectIdGetDatum(cfgId),
     688              :                                         PointerGetDatum(in)));
     689              : }
     690              : 
     691              : Datum
     692          207 : websearch_to_tsquery_byid(PG_FUNCTION_ARGS)
     693              : {
     694          207 :     text       *in = PG_GETARG_TEXT_PP(1);
     695              :     MorphOpaque data;
     696          207 :     TSQuery     query = NULL;
     697              : 
     698          207 :     data.cfg_id = PG_GETARG_OID(0);
     699              : 
     700              :     /*
     701              :      * Passing OP_PHRASE as a qoperator makes tsquery require matching of word
     702              :      * positions of a complex morph exactly match the tsvector.  Also, when
     703              :      * the complex morphs are given in quotes, we connect all their words into
     704              :      * the OP_PHRASE sequence.
     705              :      */
     706          207 :     data.qoperator = OP_PHRASE;
     707              : 
     708          207 :     query = parse_tsquery(text_to_cstring(in),
     709              :                           pushval_morph,
     710              :                           &data,
     711              :                           P_TSQ_WEB,
     712              :                           NULL);
     713              : 
     714          207 :     PG_RETURN_TSQUERY(query);
     715              : }
     716              : 
     717              : Datum
     718           12 : websearch_to_tsquery(PG_FUNCTION_ARGS)
     719              : {
     720           12 :     text       *in = PG_GETARG_TEXT_PP(0);
     721              :     Oid         cfgId;
     722              : 
     723           12 :     cfgId = getTSCurrentConfig(true);
     724           12 :     PG_RETURN_DATUM(DirectFunctionCall2(websearch_to_tsquery_byid,
     725              :                                         ObjectIdGetDatum(cfgId),
     726              :                                         PointerGetDatum(in)));
     727              : }
        

Generated by: LCOV version 2.0-1