LCOV - code coverage report
Current view: top level - src/backend/tsearch - to_tsany.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 274 284 96.5 %
Date: 2024-04-23 17:11:50 Functions: 24 26 92.3 %
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-2024, 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       12458 : compareWORD(const void *a, const void *b)
      58             : {
      59             :     int         res;
      60             : 
      61       12458 :     res = tsCompareString(((const ParsedWord *) a)->word, ((const ParsedWord *) a)->len,
      62       12458 :                           ((const ParsedWord *) b)->word, ((const ParsedWord *) b)->len,
      63             :                           false);
      64             : 
      65       12458 :     if (res == 0)
      66             :     {
      67        1050 :         if (((const ParsedWord *) a)->pos.pos == ((const ParsedWord *) b)->pos.pos)
      68          24 :             return 0;
      69             : 
      70        1026 :         res = (((const ParsedWord *) a)->pos.pos > ((const ParsedWord *) b)->pos.pos) ? 1 : -1;
      71             :     }
      72             : 
      73       12434 :     return res;
      74             : }
      75             : 
      76             : static int
      77         676 : uniqueWORD(ParsedWord *a, int32 l)
      78             : {
      79             :     ParsedWord *ptr,
      80             :                *res;
      81             :     int         tmppos;
      82             : 
      83         676 :     if (l == 1)
      84             :     {
      85          26 :         tmppos = LIMITPOS(a->pos.pos);
      86          26 :         a->alen = 2;
      87          26 :         a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
      88          26 :         a->pos.apos[0] = 1;
      89          26 :         a->pos.apos[1] = tmppos;
      90          26 :         return l;
      91             :     }
      92             : 
      93         650 :     res = a;
      94         650 :     ptr = a + 1;
      95             : 
      96             :     /*
      97             :      * Sort words with its positions
      98             :      */
      99         650 :     qsort(a, l, sizeof(ParsedWord), compareWORD);
     100             : 
     101             :     /*
     102             :      * Initialize first word and its first position
     103             :      */
     104         650 :     tmppos = LIMITPOS(a->pos.pos);
     105         650 :     a->alen = 2;
     106         650 :     a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
     107         650 :     a->pos.apos[0] = 1;
     108         650 :     a->pos.apos[1] = tmppos;
     109             : 
     110             :     /*
     111             :      * Summarize position information for each word
     112             :      */
     113        4192 :     while (ptr - a < l)
     114             :     {
     115        3542 :         if (!(ptr->len == res->len &&
     116        2030 :               strncmp(ptr->word, res->word, res->len) == 0))
     117             :         {
     118             :             /*
     119             :              * Got a new word, so put it in result
     120             :              */
     121        2888 :             res++;
     122        2888 :             res->len = ptr->len;
     123        2888 :             res->word = ptr->word;
     124        2888 :             tmppos = LIMITPOS(ptr->pos.pos);
     125        2888 :             res->alen = 2;
     126        2888 :             res->pos.apos = (uint16 *) palloc(sizeof(uint16) * res->alen);
     127        2888 :             res->pos.apos[0] = 1;
     128        2888 :             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         654 :             pfree(ptr->word);
     138         654 :             if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1 &&
     139         654 :                 res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
     140             :             {
     141         630 :                 if (res->pos.apos[0] + 1 >= res->alen)
     142             :                 {
     143         504 :                     res->alen *= 2;
     144         504 :                     res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
     145             :                 }
     146         630 :                 if (res->pos.apos[0] == 0 || res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
     147             :                 {
     148         630 :                     res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
     149         630 :                     res->pos.apos[0]++;
     150             :                 }
     151             :             }
     152             :         }
     153        3542 :         ptr++;
     154             :     }
     155             : 
     156         650 :     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         796 : make_tsvector(ParsedText *prs)
     166             : {
     167             :     int         i,
     168             :                 j,
     169         796 :                 lenstr = 0,
     170             :                 totallen;
     171             :     TSVector    in;
     172             :     WordEntry  *ptr;
     173             :     char       *str;
     174             :     int         stroff;
     175             : 
     176             :     /* Merge duplicate words */
     177         796 :     if (prs->curwords > 0)
     178         676 :         prs->curwords = uniqueWORD(prs->words, prs->curwords);
     179             : 
     180             :     /* Determine space needed */
     181        4360 :     for (i = 0; i < prs->curwords; i++)
     182             :     {
     183        3564 :         lenstr += prs->words[i].len;
     184        3564 :         if (prs->words[i].alen)
     185             :         {
     186        3564 :             lenstr = SHORTALIGN(lenstr);
     187        3564 :             lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
     188             :         }
     189             :     }
     190             : 
     191         796 :     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         796 :     totallen = CALCDATASIZE(prs->curwords, lenstr);
     197         796 :     in = (TSVector) palloc0(totallen);
     198         796 :     SET_VARSIZE(in, totallen);
     199         796 :     in->size = prs->curwords;
     200             : 
     201         796 :     ptr = ARRPTR(in);
     202         796 :     str = STRPTR(in);
     203         796 :     stroff = 0;
     204        4360 :     for (i = 0; i < prs->curwords; i++)
     205             :     {
     206        3564 :         ptr->len = prs->words[i].len;
     207        3564 :         ptr->pos = stroff;
     208        3564 :         memcpy(str + stroff, prs->words[i].word, prs->words[i].len);
     209        3564 :         stroff += prs->words[i].len;
     210        3564 :         pfree(prs->words[i].word);
     211        3564 :         if (prs->words[i].alen)
     212             :         {
     213        3564 :             int         k = prs->words[i].pos.apos[0];
     214             :             WordEntryPos *wptr;
     215             : 
     216        3564 :             if (k > 0xFFFF)
     217           0 :                 elog(ERROR, "positions array too long");
     218             : 
     219        3564 :             ptr->haspos = 1;
     220        3564 :             stroff = SHORTALIGN(stroff);
     221        3564 :             *(uint16 *) (str + stroff) = (uint16) k;
     222        3564 :             wptr = POSDATAPTR(in, ptr);
     223        7758 :             for (j = 0; j < k; j++)
     224             :             {
     225        4194 :                 WEP_SETWEIGHT(wptr[j], 0);
     226        4194 :                 WEP_SETPOS(wptr[j], prs->words[i].pos.apos[j + 1]);
     227             :             }
     228        3564 :             stroff += sizeof(uint16) + k * sizeof(WordEntryPos);
     229        3564 :             pfree(prs->words[i].pos.apos);
     230             :         }
     231             :         else
     232           0 :             ptr->haspos = 0;
     233        3564 :         ptr++;
     234             :     }
     235             : 
     236         796 :     if (prs->words)
     237         712 :         pfree(prs->words);
     238             : 
     239         796 :     return in;
     240             : }
     241             : 
     242             : Datum
     243         478 : to_tsvector_byid(PG_FUNCTION_ARGS)
     244             : {
     245         478 :     Oid         cfgId = PG_GETARG_OID(0);
     246         478 :     text       *in = PG_GETARG_TEXT_PP(1);
     247             :     ParsedText  prs;
     248             :     TSVector    out;
     249             : 
     250         478 :     prs.lenwords = VARSIZE_ANY_EXHDR(in) / 6;   /* just estimation of word's
     251             :                                                  * number */
     252         478 :     if (prs.lenwords < 2)
     253         338 :         prs.lenwords = 2;
     254         140 :     else if (prs.lenwords > MaxAllocSize / sizeof(ParsedWord))
     255           0 :         prs.lenwords = MaxAllocSize / sizeof(ParsedWord);
     256         478 :     prs.curwords = 0;
     257         478 :     prs.pos = 0;
     258         478 :     prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
     259             : 
     260         478 :     parsetext(cfgId, &prs, VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
     261             : 
     262         478 :     PG_FREE_IF_COPY(in, 1);
     263             : 
     264         478 :     out = make_tsvector(&prs);
     265             : 
     266         478 :     PG_RETURN_TSVECTOR(out);
     267             : }
     268             : 
     269             : Datum
     270          54 : to_tsvector(PG_FUNCTION_ARGS)
     271             : {
     272          54 :     text       *in = PG_GETARG_TEXT_PP(0);
     273             :     Oid         cfgId;
     274             : 
     275          54 :     cfgId = getTSCurrentConfig(true);
     276          54 :     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         150 : jsonb_to_tsvector_worker(Oid cfgId, Jsonb *jb, uint32 flags)
     286             : {
     287             :     TSVectorBuildState state;
     288             :     ParsedText  prs;
     289             : 
     290         150 :     prs.words = NULL;
     291         150 :     prs.curwords = 0;
     292         150 :     state.prs = &prs;
     293         150 :     state.cfgId = cfgId;
     294             : 
     295         150 :     iterate_jsonb_values(jb, flags, &state, add_to_tsvector);
     296             : 
     297         150 :     return make_tsvector(&prs);
     298             : }
     299             : 
     300             : Datum
     301          18 : jsonb_string_to_tsvector_byid(PG_FUNCTION_ARGS)
     302             : {
     303          18 :     Oid         cfgId = PG_GETARG_OID(0);
     304          18 :     Jsonb      *jb = PG_GETARG_JSONB_P(1);
     305             :     TSVector    result;
     306             : 
     307          18 :     result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
     308          18 :     PG_FREE_IF_COPY(jb, 1);
     309             : 
     310          18 :     PG_RETURN_TSVECTOR(result);
     311             : }
     312             : 
     313             : Datum
     314          30 : jsonb_string_to_tsvector(PG_FUNCTION_ARGS)
     315             : {
     316          30 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     317             :     Oid         cfgId;
     318             :     TSVector    result;
     319             : 
     320          30 :     cfgId = getTSCurrentConfig(true);
     321          30 :     result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
     322          30 :     PG_FREE_IF_COPY(jb, 0);
     323             : 
     324          30 :     PG_RETURN_TSVECTOR(result);
     325             : }
     326             : 
     327             : Datum
     328         102 : jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
     329             : {
     330         102 :     Oid         cfgId = PG_GETARG_OID(0);
     331         102 :     Jsonb      *jb = PG_GETARG_JSONB_P(1);
     332         102 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(2);
     333             :     TSVector    result;
     334         102 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     335             : 
     336          78 :     result = jsonb_to_tsvector_worker(cfgId, jb, flags);
     337          78 :     PG_FREE_IF_COPY(jb, 1);
     338          78 :     PG_FREE_IF_COPY(jbFlags, 2);
     339             : 
     340          78 :     PG_RETURN_TSVECTOR(result);
     341             : }
     342             : 
     343             : Datum
     344          24 : jsonb_to_tsvector(PG_FUNCTION_ARGS)
     345             : {
     346          24 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     347          24 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(1);
     348             :     Oid         cfgId;
     349             :     TSVector    result;
     350          24 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     351             : 
     352          24 :     cfgId = getTSCurrentConfig(true);
     353          24 :     result = jsonb_to_tsvector_worker(cfgId, jb, flags);
     354          24 :     PG_FREE_IF_COPY(jb, 0);
     355          24 :     PG_FREE_IF_COPY(jbFlags, 1);
     356             : 
     357          24 :     PG_RETURN_TSVECTOR(result);
     358             : }
     359             : 
     360             : /*
     361             :  * Worker function for json(_string)_to_tsvector(_byid)
     362             :  */
     363             : static TSVector
     364         150 : json_to_tsvector_worker(Oid cfgId, text *json, uint32 flags)
     365             : {
     366             :     TSVectorBuildState state;
     367             :     ParsedText  prs;
     368             : 
     369         150 :     prs.words = NULL;
     370         150 :     prs.curwords = 0;
     371         150 :     state.prs = &prs;
     372         150 :     state.cfgId = cfgId;
     373             : 
     374         150 :     iterate_json_values(json, flags, &state, add_to_tsvector);
     375             : 
     376         150 :     return make_tsvector(&prs);
     377             : }
     378             : 
     379             : Datum
     380          18 : json_string_to_tsvector_byid(PG_FUNCTION_ARGS)
     381             : {
     382          18 :     Oid         cfgId = PG_GETARG_OID(0);
     383          18 :     text       *json = PG_GETARG_TEXT_P(1);
     384             :     TSVector    result;
     385             : 
     386          18 :     result = json_to_tsvector_worker(cfgId, json, jtiString);
     387          18 :     PG_FREE_IF_COPY(json, 1);
     388             : 
     389          18 :     PG_RETURN_TSVECTOR(result);
     390             : }
     391             : 
     392             : Datum
     393          30 : json_string_to_tsvector(PG_FUNCTION_ARGS)
     394             : {
     395          30 :     text       *json = PG_GETARG_TEXT_P(0);
     396             :     Oid         cfgId;
     397             :     TSVector    result;
     398             : 
     399          30 :     cfgId = getTSCurrentConfig(true);
     400          30 :     result = json_to_tsvector_worker(cfgId, json, jtiString);
     401          30 :     PG_FREE_IF_COPY(json, 0);
     402             : 
     403          30 :     PG_RETURN_TSVECTOR(result);
     404             : }
     405             : 
     406             : Datum
     407         102 : json_to_tsvector_byid(PG_FUNCTION_ARGS)
     408             : {
     409         102 :     Oid         cfgId = PG_GETARG_OID(0);
     410         102 :     text       *json = PG_GETARG_TEXT_P(1);
     411         102 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(2);
     412             :     TSVector    result;
     413         102 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     414             : 
     415          78 :     result = json_to_tsvector_worker(cfgId, json, flags);
     416          78 :     PG_FREE_IF_COPY(json, 1);
     417          78 :     PG_FREE_IF_COPY(jbFlags, 2);
     418             : 
     419          78 :     PG_RETURN_TSVECTOR(result);
     420             : }
     421             : 
     422             : Datum
     423          24 : json_to_tsvector(PG_FUNCTION_ARGS)
     424             : {
     425          24 :     text       *json = PG_GETARG_TEXT_P(0);
     426          24 :     Jsonb      *jbFlags = PG_GETARG_JSONB_P(1);
     427             :     Oid         cfgId;
     428             :     TSVector    result;
     429          24 :     uint32      flags = parse_jsonb_index_flags(jbFlags);
     430             : 
     431          24 :     cfgId = getTSCurrentConfig(true);
     432          24 :     result = json_to_tsvector_worker(cfgId, json, flags);
     433          24 :     PG_FREE_IF_COPY(json, 0);
     434          24 :     PG_FREE_IF_COPY(jbFlags, 1);
     435             : 
     436          24 :     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         744 : add_to_tsvector(void *_state, char *elem_value, int elem_len)
     444             : {
     445         744 :     TSVectorBuildState *state = (TSVectorBuildState *) _state;
     446         744 :     ParsedText *prs = state->prs;
     447             :     int32       prevwords;
     448             : 
     449         744 :     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         216 :         prs->lenwords = 16;
     456         216 :         prs->words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs->lenwords);
     457         216 :         prs->curwords = 0;
     458         216 :         prs->pos = 0;
     459             :     }
     460             : 
     461         744 :     prevwords = prs->curwords;
     462             : 
     463         744 :     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         744 :     if (prs->curwords > prevwords)
     472         672 :         prs->pos += 1;
     473         744 : }
     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        3088 : pushval_morph(Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
     493             : {
     494        3088 :     int32       count = 0;
     495             :     ParsedText  prs;
     496             :     uint32      variant,
     497        3088 :                 pos = 0,
     498        3088 :                 cntvar = 0,
     499        3088 :                 cntpos = 0,
     500        3088 :                 cnt = 0;
     501        3088 :     MorphOpaque *data = (MorphOpaque *) DatumGetPointer(opaque);
     502             : 
     503        3088 :     prs.lenwords = 4;
     504        3088 :     prs.curwords = 0;
     505        3088 :     prs.pos = 0;
     506        3088 :     prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
     507             : 
     508        3088 :     parsetext(data->cfg_id, &prs, strval, lenval);
     509             : 
     510        3088 :     if (prs.curwords > 0)
     511             :     {
     512        5348 :         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        2878 :             if (pos > 0 && pos + 1 < prs.words[count].pos.pos)
     519             :             {
     520          78 :                 while (pos + 1 < prs.words[count].pos.pos)
     521             :                 {
     522             :                     /* put placeholders for each missing stop word */
     523          48 :                     pushStop(state);
     524          48 :                     if (cntpos)
     525          48 :                         pushOperator(state, data->qoperator, 1);
     526          48 :                     cntpos++;
     527          48 :                     pos++;
     528             :                 }
     529             :             }
     530             : 
     531             :             /* save current word's position */
     532        2878 :             pos = prs.words[count].pos.pos;
     533             : 
     534             :             /* Go through all variants obtained from this token */
     535        2878 :             cntvar = 0;
     536        5828 :             while (count < prs.curwords && pos == prs.words[count].pos.pos)
     537             :             {
     538        2950 :                 variant = prs.words[count].nvariant;
     539             : 
     540             :                 /* Push all words belonging to the same variant */
     541        2950 :                 cnt = 0;
     542        6044 :                 while (count < prs.curwords &&
     543        3574 :                        pos == prs.words[count].pos.pos &&
     544        3166 :                        variant == prs.words[count].nvariant)
     545             :                 {
     546        3094 :                     pushValue(state,
     547        3094 :                               prs.words[count].word,
     548        3094 :                               prs.words[count].len,
     549             :                               weight,
     550        3094 :                               ((prs.words[count].flags & TSL_PREFIX) || prefix));
     551        3094 :                     pfree(prs.words[count].word);
     552        3094 :                     if (cnt)
     553         144 :                         pushOperator(state, OP_AND, 0);
     554        3094 :                     cnt++;
     555        3094 :                     count++;
     556             :                 }
     557             : 
     558        2950 :                 if (cntvar)
     559          72 :                     pushOperator(state, OP_OR, 0);
     560        2950 :                 cntvar++;
     561             :             }
     562             : 
     563        2878 :             if (cntpos)
     564             :             {
     565             :                 /* distance may be useful */
     566         408 :                 pushOperator(state, data->qoperator, 1);
     567             :             }
     568             : 
     569        2878 :             cntpos++;
     570             :         }
     571             : 
     572        2470 :         pfree(prs.words);
     573             :     }
     574             :     else
     575         618 :         pushStop(state);
     576        3088 : }
     577             : 
     578             : Datum
     579         754 : to_tsquery_byid(PG_FUNCTION_ARGS)
     580             : {
     581         754 :     text       *in = PG_GETARG_TEXT_PP(1);
     582             :     TSQuery     query;
     583             :     MorphOpaque data;
     584             : 
     585         754 :     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         754 :     data.qoperator = OP_PHRASE;
     594             : 
     595         754 :     query = parse_tsquery(text_to_cstring(in),
     596             :                           pushval_morph,
     597             :                           PointerGetDatum(&data),
     598             :                           0,
     599             :                           NULL);
     600             : 
     601         754 :     PG_RETURN_TSQUERY(query);
     602             : }
     603             : 
     604             : Datum
     605         132 : to_tsquery(PG_FUNCTION_ARGS)
     606             : {
     607         132 :     text       *in = PG_GETARG_TEXT_PP(0);
     608             :     Oid         cfgId;
     609             : 
     610         132 :     cfgId = getTSCurrentConfig(true);
     611         132 :     PG_RETURN_DATUM(DirectFunctionCall2(to_tsquery_byid,
     612             :                                         ObjectIdGetDatum(cfgId),
     613             :                                         PointerGetDatum(in)));
     614             : }
     615             : 
     616             : Datum
     617          60 : plainto_tsquery_byid(PG_FUNCTION_ARGS)
     618             : {
     619          60 :     text       *in = PG_GETARG_TEXT_PP(1);
     620             :     TSQuery     query;
     621             :     MorphOpaque data;
     622             : 
     623          60 :     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          60 :     data.qoperator = OP_AND;
     631             : 
     632          60 :     query = parse_tsquery(text_to_cstring(in),
     633             :                           pushval_morph,
     634             :                           PointerGetDatum(&data),
     635             :                           P_TSQ_PLAIN,
     636             :                           NULL);
     637             : 
     638          60 :     PG_RETURN_POINTER(query);
     639             : }
     640             : 
     641             : Datum
     642          12 : plainto_tsquery(PG_FUNCTION_ARGS)
     643             : {
     644          12 :     text       *in = PG_GETARG_TEXT_PP(0);
     645             :     Oid         cfgId;
     646             : 
     647          12 :     cfgId = getTSCurrentConfig(true);
     648          12 :     PG_RETURN_DATUM(DirectFunctionCall2(plainto_tsquery_byid,
     649             :                                         ObjectIdGetDatum(cfgId),
     650             :                                         PointerGetDatum(in)));
     651             : }
     652             : 
     653             : 
     654             : Datum
     655          48 : phraseto_tsquery_byid(PG_FUNCTION_ARGS)
     656             : {
     657          48 :     text       *in = PG_GETARG_TEXT_PP(1);
     658             :     TSQuery     query;
     659             :     MorphOpaque data;
     660             : 
     661          48 :     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          48 :     data.qoperator = OP_PHRASE;
     669             : 
     670          48 :     query = parse_tsquery(text_to_cstring(in),
     671             :                           pushval_morph,
     672             :                           PointerGetDatum(&data),
     673             :                           P_TSQ_PLAIN,
     674             :                           NULL);
     675             : 
     676          48 :     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         408 : websearch_to_tsquery_byid(PG_FUNCTION_ARGS)
     693             : {
     694         408 :     text       *in = PG_GETARG_TEXT_PP(1);
     695             :     MorphOpaque data;
     696         408 :     TSQuery     query = NULL;
     697             : 
     698         408 :     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         408 :     data.qoperator = OP_PHRASE;
     707             : 
     708         408 :     query = parse_tsquery(text_to_cstring(in),
     709             :                           pushval_morph,
     710             :                           PointerGetDatum(&data),
     711             :                           P_TSQ_WEB,
     712             :                           NULL);
     713             : 
     714         408 :     PG_RETURN_TSQUERY(query);
     715             : }
     716             : 
     717             : Datum
     718          24 : websearch_to_tsquery(PG_FUNCTION_ARGS)
     719             : {
     720          24 :     text       *in = PG_GETARG_TEXT_PP(0);
     721             :     Oid         cfgId;
     722             : 
     723          24 :     cfgId = getTSCurrentConfig(true);
     724          24 :     PG_RETURN_DATUM(DirectFunctionCall2(websearch_to_tsquery_byid,
     725             :                                         ObjectIdGetDatum(cfgId),
     726             :                                         PointerGetDatum(in)));
     727             : }

Generated by: LCOV version 1.14