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

Generated by: LCOV version 1.14