LCOV - differential code coverage report
Current view: top level - src/backend/tsearch - to_tsany.c (source / functions) Coverage Total Hit UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.8 % 282 273 3 6 26 1 246 3 25 2
Current Date: 2023-04-08 15:15:32 Functions: 92.3 % 26 24 1 1 6 2 16 1 6
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a