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

Generated by: LCOV version 1.14