LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - tsquery.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 78.0 % 600 468 132 468
Current Date: 2024-04-14 14:21:10 Functions: 87.0 % 23 20 3 20
Baseline: 16@8cea358b128 Branches: 62.5 % 395 247 148 247
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 78.0 % 600 468 132 468
Function coverage date bins:
(240..) days: 87.0 % 23 20 3 20
Branch coverage date bins:
(240..) days: 62.5 % 395 247 148 247

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * tsquery.c
                                  4                 :                :  *    I/O functions for tsquery
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  *
                                  9                 :                :  * IDENTIFICATION
                                 10                 :                :  *    src/backend/utils/adt/tsquery.c
                                 11                 :                :  *
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : 
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "libpq/pqformat.h"
                                 18                 :                : #include "miscadmin.h"
                                 19                 :                : #include "nodes/miscnodes.h"
                                 20                 :                : #include "tsearch/ts_locale.h"
                                 21                 :                : #include "tsearch/ts_type.h"
                                 22                 :                : #include "tsearch/ts_utils.h"
                                 23                 :                : #include "utils/builtins.h"
                                 24                 :                : #include "utils/memutils.h"
                                 25                 :                : #include "utils/pg_crc.h"
                                 26                 :                : #include "varatt.h"
                                 27                 :                : 
                                 28                 :                : /* FTS operator priorities, see ts_type.h */
                                 29                 :                : const int   tsearch_op_priority[OP_COUNT] =
                                 30                 :                : {
                                 31                 :                :     4,                          /* OP_NOT */
                                 32                 :                :     2,                          /* OP_AND */
                                 33                 :                :     1,                          /* OP_OR */
                                 34                 :                :     3                           /* OP_PHRASE */
                                 35                 :                : };
                                 36                 :                : 
                                 37                 :                : /*
                                 38                 :                :  * parser's states
                                 39                 :                :  */
                                 40                 :                : typedef enum
                                 41                 :                : {
                                 42                 :                :     WAITOPERAND = 1,
                                 43                 :                :     WAITOPERATOR = 2,
                                 44                 :                :     WAITFIRSTOPERAND = 3,
                                 45                 :                : } ts_parserstate;
                                 46                 :                : 
                                 47                 :                : /*
                                 48                 :                :  * token types for parsing
                                 49                 :                :  */
                                 50                 :                : typedef enum
                                 51                 :                : {
                                 52                 :                :     PT_END = 0,
                                 53                 :                :     PT_ERR = 1,
                                 54                 :                :     PT_VAL = 2,
                                 55                 :                :     PT_OPR = 3,
                                 56                 :                :     PT_OPEN = 4,
                                 57                 :                :     PT_CLOSE = 5,
                                 58                 :                : } ts_tokentype;
                                 59                 :                : 
                                 60                 :                : /*
                                 61                 :                :  * get token from query string
                                 62                 :                :  *
                                 63                 :                :  * All arguments except "state" are output arguments.
                                 64                 :                :  *
                                 65                 :                :  * If return value is PT_OPR, then *operator is filled with an OP_* code
                                 66                 :                :  * and *weight will contain a distance value in case of phrase operator.
                                 67                 :                :  *
                                 68                 :                :  * If return value is PT_VAL, then *lenval, *strval, *weight, and *prefix
                                 69                 :                :  * are filled.
                                 70                 :                :  *
                                 71                 :                :  * If PT_ERR is returned then a soft error has occurred.  If state->escontext
                                 72                 :                :  * isn't already filled then this should be reported as a generic parse error.
                                 73                 :                :  */
                                 74                 :                : typedef ts_tokentype (*ts_tokenizer) (TSQueryParserState state, int8 *operator,
                                 75                 :                :                                       int *lenval, char **strval,
                                 76                 :                :                                       int16 *weight, bool *prefix);
                                 77                 :                : 
                                 78                 :                : struct TSQueryParserStateData
                                 79                 :                : {
                                 80                 :                :     /* Tokenizer used for parsing tsquery */
                                 81                 :                :     ts_tokenizer gettoken;
                                 82                 :                : 
                                 83                 :                :     /* State of tokenizer function */
                                 84                 :                :     char       *buffer;         /* entire string we are scanning */
                                 85                 :                :     char       *buf;            /* current scan point */
                                 86                 :                :     int         count;          /* nesting count, incremented by (,
                                 87                 :                :                                  * decremented by ) */
                                 88                 :                :     ts_parserstate state;
                                 89                 :                : 
                                 90                 :                :     /* polish (prefix) notation in list, filled in by push* functions */
                                 91                 :                :     List       *polstr;
                                 92                 :                : 
                                 93                 :                :     /*
                                 94                 :                :      * Strings from operands are collected in op. curop is a pointer to the
                                 95                 :                :      * end of used space of op.
                                 96                 :                :      */
                                 97                 :                :     char       *op;
                                 98                 :                :     char       *curop;
                                 99                 :                :     int         lenop;          /* allocated size of op */
                                100                 :                :     int         sumlen;         /* used size of op */
                                101                 :                : 
                                102                 :                :     /* state for value's parser */
                                103                 :                :     TSVectorParseState valstate;
                                104                 :                : 
                                105                 :                :     /* context object for soft errors - must match valstate's escontext */
                                106                 :                :     Node       *escontext;
                                107                 :                : };
                                108                 :                : 
                                109                 :                : /*
                                110                 :                :  * subroutine to parse the modifiers (weight and prefix flag currently)
                                111                 :                :  * part, like ':AB*' of a query.
                                112                 :                :  */
                                113                 :                : static char *
 5812 tgl@sss.pgh.pa.us         114                 :CBC        3603 : get_modifiers(char *buf, int16 *weight, bool *prefix)
                                115                 :                : {
 6081                           116                 :           3603 :     *weight = 0;
 5812                           117                 :           3603 :     *prefix = false;
                                118                 :                : 
 6081                           119         [ +  + ]:           3603 :     if (!t_iseq(buf, ':'))
                                120                 :           3285 :         return buf;
                                121                 :                : 
                                122                 :            318 :     buf++;
                                123   [ +  +  +  - ]:            744 :     while (*buf && pg_mblen(buf) == 1)
                                124                 :                :     {
                                125   [ +  +  +  +  :            534 :         switch (*buf)
                                              +  + ]
                                126                 :                :         {
                                127                 :            117 :             case 'a':
                                128                 :                :             case 'A':
                                129                 :            117 :                 *weight |= 1 << 3;
                                130                 :            117 :                 break;
                                131                 :             33 :             case 'b':
                                132                 :                :             case 'B':
                                133                 :             33 :                 *weight |= 1 << 2;
                                134                 :             33 :                 break;
                                135                 :             57 :             case 'c':
                                136                 :                :             case 'C':
                                137                 :             57 :                 *weight |= 1 << 1;
                                138                 :             57 :                 break;
                                139                 :             60 :             case 'd':
                                140                 :                :             case 'D':
                                141                 :             60 :                 *weight |= 1;
                                142                 :             60 :                 break;
 5812                           143                 :            159 :             case '*':
                                144                 :            159 :                 *prefix = true;
                                145                 :            159 :                 break;
 6081                           146                 :            108 :             default:
                                147                 :            108 :                 return buf;
                                148                 :                :         }
                                149                 :            426 :         buf++;
                                150                 :                :     }
                                151                 :                : 
                                152                 :            210 :     return buf;
                                153                 :                : }
                                154                 :                : 
                                155                 :                : /*
                                156                 :                :  * Parse phrase operator. The operator
                                157                 :                :  * may take the following forms:
                                158                 :                :  *
                                159                 :                :  *      a <N> b (distance is exactly N lexemes)
                                160                 :                :  *      a <-> b (default distance = 1)
                                161                 :                :  *
                                162                 :                :  * The buffer should begin with '<' char
                                163                 :                :  */
                                164                 :                : static bool
 2201 teodor@sigaev.ru          165                 :           4539 : parse_phrase_operator(TSQueryParserState pstate, int16 *distance)
                                166                 :                : {
                                167                 :                :     enum
                                168                 :                :     {
                                169                 :                :         PHRASE_OPEN = 0,
                                170                 :                :         PHRASE_DIST,
                                171                 :                :         PHRASE_CLOSE,
                                172                 :                :         PHRASE_FINISH
 2866 rhaas@postgresql.org      173                 :           4539 :     }           state = PHRASE_OPEN;
 2201 teodor@sigaev.ru          174                 :           4539 :     char       *ptr = pstate->buf;
                                175                 :                :     char       *endptr;
 2484 tgl@sss.pgh.pa.us         176                 :           4539 :     long        l = 1;          /* default distance */
                                177                 :                : 
 2929 teodor@sigaev.ru          178         [ +  + ]:          11682 :     while (*ptr)
                                179                 :                :     {
 2866 rhaas@postgresql.org      180   [ +  +  +  +  :           5492 :         switch (state)
                                                 - ]
                                181                 :                :         {
 2929 teodor@sigaev.ru          182                 :           2888 :             case PHRASE_OPEN:
 2201                           183         [ +  + ]:           2888 :                 if (t_iseq(ptr, '<'))
                                184                 :                :                 {
                                185                 :            870 :                     state = PHRASE_DIST;
                                186                 :            870 :                     ptr++;
                                187                 :                :                 }
                                188                 :                :                 else
                                189                 :           2018 :                     return false;
 2929                           190                 :            870 :                 break;
                                191                 :                : 
                                192                 :            870 :             case PHRASE_DIST:
                                193         [ +  + ]:            870 :                 if (t_iseq(ptr, '-'))
                                194                 :                :                 {
                                195                 :            723 :                     state = PHRASE_CLOSE;
                                196                 :            723 :                     ptr++;
 2201                           197                 :            723 :                     continue;
                                198                 :                :                 }
                                199                 :                : 
 2484 tgl@sss.pgh.pa.us         200         [ -  + ]:            147 :                 if (!t_isdigit(ptr))
 2201 teodor@sigaev.ru          201                 :UBC           0 :                     return false;
                                202                 :                : 
 2484 tgl@sss.pgh.pa.us         203                 :CBC         147 :                 errno = 0;
 2929 teodor@sigaev.ru          204                 :            147 :                 l = strtol(ptr, &endptr, 10);
                                205         [ -  + ]:            147 :                 if (ptr == endptr)
 2201 teodor@sigaev.ru          206                 :UBC           0 :                     return false;
 2484 tgl@sss.pgh.pa.us         207   [ +  -  +  -  :CBC         147 :                 else if (errno == ERANGE || l < 0 || l > MAXENTRYPOS)
                                              +  + ]
  474                           208         [ +  - ]:              3 :                     ereturn(pstate->escontext, false,
                                209                 :                :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                210                 :                :                              errmsg("distance in phrase operator must be an integer value between zero and %d inclusive",
                                211                 :                :                                     MAXENTRYPOS)));
                                212                 :                :                 else
                                213                 :                :                 {
 2929 teodor@sigaev.ru          214                 :            144 :                     state = PHRASE_CLOSE;
                                215                 :            144 :                     ptr = endptr;
                                216                 :                :                 }
                                217                 :            144 :                 break;
                                218                 :                : 
                                219                 :            867 :             case PHRASE_CLOSE:
                                220         [ +  - ]:            867 :                 if (t_iseq(ptr, '>'))
                                221                 :                :                 {
                                222                 :            867 :                     state = PHRASE_FINISH;
                                223                 :            867 :                     ptr++;
                                224                 :                :                 }
                                225                 :                :                 else
 2201 teodor@sigaev.ru          226                 :UBC           0 :                     return false;
 2929 teodor@sigaev.ru          227                 :CBC         867 :                 break;
                                228                 :                : 
                                229                 :            867 :             case PHRASE_FINISH:
                                230                 :            867 :                 *distance = (int16) l;
 2201                           231                 :            867 :                 pstate->buf = ptr;
                                232                 :            867 :                 return true;
                                233                 :                :         }
                                234                 :                :     }
                                235                 :                : 
                                236                 :           1651 :     return false;
                                237                 :                : }
                                238                 :                : 
                                239                 :                : /*
                                240                 :                :  * Parse OR operator used in websearch_to_tsquery(), returns true if we
                                241                 :                :  * believe that "OR" literal could be an operator OR
                                242                 :                :  */
                                243                 :                : static bool
                                244                 :            771 : parse_or_operator(TSQueryParserState pstate)
                                245                 :                : {
 2180 tgl@sss.pgh.pa.us         246                 :            771 :     char       *ptr = pstate->buf;
                                247                 :                : 
                                248                 :                :     /* it should begin with "OR" literal */
 2201 teodor@sigaev.ru          249         [ +  + ]:            771 :     if (pg_strncasecmp(ptr, "or", 2) != 0)
                                250                 :            699 :         return false;
                                251                 :                : 
                                252                 :             72 :     ptr += 2;
                                253                 :                : 
                                254                 :                :     /*
                                255                 :                :      * it shouldn't be a part of any word but somewhere later it should be
                                256                 :                :      * some operand
                                257                 :                :      */
 2180 tgl@sss.pgh.pa.us         258         [ +  + ]:             72 :     if (*ptr == '\0')           /* no operand */
 2201 teodor@sigaev.ru          259                 :              3 :         return false;
                                260                 :                : 
                                261                 :                :     /* it shouldn't be a part of any word */
  556 tgl@sss.pgh.pa.us         262   [ +  +  +  +  :             69 :     if (t_iseq(ptr, '-') || t_iseq(ptr, '_') || t_isalnum(ptr))
                                              +  + ]
 2201 teodor@sigaev.ru          263                 :             12 :         return false;
                                264                 :                : 
                                265                 :                :     for (;;)
                                266                 :                :     {
 2201 teodor@sigaev.ru          267                 :UBC           0 :         ptr += pg_mblen(ptr);
                                268                 :                : 
 2180 tgl@sss.pgh.pa.us         269         [ +  + ]:CBC          57 :         if (*ptr == '\0')       /* got end of string without operand */
 2201 teodor@sigaev.ru          270                 :              6 :             return false;
                                271                 :                : 
                                272                 :                :         /*
                                273                 :                :          * Suppose, we found an operand, but could be a not correct operand.
                                274                 :                :          * So we still treat OR literal as operation with possibly incorrect
                                275                 :                :          * operand and will not search it as lexeme
                                276                 :                :          */
                                277         [ +  - ]:             51 :         if (!t_isspace(ptr))
                                278                 :             51 :             break;
                                279                 :                :     }
                                280                 :                : 
                                281                 :             51 :     pstate->buf += 2;
                                282                 :             51 :     return true;
                                283                 :                : }
                                284                 :                : 
                                285                 :                : static ts_tokentype
                                286                 :           8745 : gettoken_query_standard(TSQueryParserState state, int8 *operator,
                                287                 :                :                         int *lenval, char **strval,
                                288                 :                :                         int16 *weight, bool *prefix)
                                289                 :                : {
 5812 tgl@sss.pgh.pa.us         290                 :           8745 :     *weight = 0;
                                291                 :           8745 :     *prefix = false;
                                292                 :                : 
                                293                 :                :     while (true)
                                294                 :                :     {
 6081                           295      [ +  +  - ]:          11692 :         switch (state->state)
                                296                 :                :         {
                                297                 :           6077 :             case WAITFIRSTOPERAND:
                                298                 :                :             case WAITOPERAND:
                                299         [ +  + ]:           6077 :                 if (t_iseq(state->buf, '!'))
                                300                 :                :                 {
 2201 teodor@sigaev.ru          301                 :            465 :                     state->buf++;
 6081 tgl@sss.pgh.pa.us         302                 :            465 :                     state->state = WAITOPERAND;
 2201 teodor@sigaev.ru          303                 :            465 :                     *operator = OP_NOT;
 6064                           304                 :            465 :                     return PT_OPR;
                                305                 :                :                 }
 6081 tgl@sss.pgh.pa.us         306         [ +  + ]:           5612 :                 else if (t_iseq(state->buf, '('))
                                307                 :                :                 {
 2201 teodor@sigaev.ru          308                 :            531 :                     state->buf++;
 6081 tgl@sss.pgh.pa.us         309                 :            531 :                     state->state = WAITOPERAND;
 2201 teodor@sigaev.ru          310                 :            531 :                     state->count++;
 6064                           311                 :            531 :                     return PT_OPEN;
                                312                 :                :                 }
 6081 tgl@sss.pgh.pa.us         313         [ -  + ]:           5081 :                 else if (t_iseq(state->buf, ':'))
                                314                 :                :                 {
                                315                 :                :                     /* generic syntax error message is fine */
  474 tgl@sss.pgh.pa.us         316                 :UBC           0 :                     return PT_ERR;
                                317                 :                :                 }
 6081 tgl@sss.pgh.pa.us         318         [ +  + ]:CBC        5081 :                 else if (!t_isspace(state->buf))
                                319                 :                :                 {
                                320                 :                :                     /*
                                321                 :                :                      * We rely on the tsvector parser to parse the value for
                                322                 :                :                      * us
                                323                 :                :                      */
 6064 teodor@sigaev.ru          324                 :           3615 :                     reset_tsvector_parser(state->valstate, state->buf);
 2201                           325         [ +  + ]:           3615 :                     if (gettoken_tsvector(state->valstate, strval, lenval,
                                326                 :                :                                           NULL, NULL, &state->buf))
                                327                 :                :                     {
 5812 tgl@sss.pgh.pa.us         328                 :           3603 :                         state->buf = get_modifiers(state->buf, weight, prefix);
 6081                           329                 :           3603 :                         state->state = WAITOPERATOR;
 6064 teodor@sigaev.ru          330                 :           3603 :                         return PT_VAL;
                                331                 :                :                     }
  474 tgl@sss.pgh.pa.us         332   [ -  +  -  -  :             12 :                     else if (SOFT_ERROR_OCCURRED(state->escontext))
                                              -  - ]
                                333                 :                :                     {
                                334                 :                :                         /* gettoken_tsvector reported a soft error */
  474 tgl@sss.pgh.pa.us         335                 :UBC           0 :                         return PT_ERR;
                                336                 :                :                     }
 6081 tgl@sss.pgh.pa.us         337         [ +  - ]:CBC          12 :                     else if (state->state == WAITFIRSTOPERAND)
                                338                 :                :                     {
 6064 teodor@sigaev.ru          339                 :             12 :                         return PT_END;
                                340                 :                :                     }
                                341                 :                :                     else
  474 tgl@sss.pgh.pa.us         342         [ #  # ]:UBC           0 :                         ereturn(state->escontext, PT_ERR,
                                343                 :                :                                 (errcode(ERRCODE_SYNTAX_ERROR),
                                344                 :                :                                  errmsg("no operand in tsquery: \"%s\"",
                                345                 :                :                                         state->buffer)));
                                346                 :                :                 }
 6081 tgl@sss.pgh.pa.us         347                 :CBC        1466 :                 break;
                                348                 :                : 
                                349                 :           5615 :             case WAITOPERATOR:
 6064 teodor@sigaev.ru          350         [ +  + ]:           5615 :                 if (t_iseq(state->buf, '&'))
                                351                 :                :                 {
 2201                           352                 :            665 :                     state->buf++;
 6064                           353                 :            665 :                     state->state = WAITOPERAND;
                                354                 :            665 :                     *operator = OP_AND;
                                355                 :            665 :                     return PT_OPR;
                                356                 :                :                 }
 2929                           357         [ +  + ]:           4950 :                 else if (t_iseq(state->buf, '|'))
                                358                 :                :                 {
 2201                           359                 :            411 :                     state->buf++;
 6081 tgl@sss.pgh.pa.us         360                 :            411 :                     state->state = WAITOPERAND;
 6064 teodor@sigaev.ru          361                 :            411 :                     *operator = OP_OR;
                                362                 :            411 :                     return PT_OPR;
                                363                 :                :                 }
 2201                           364         [ +  + ]:           4539 :                 else if (parse_phrase_operator(state, weight))
                                365                 :                :                 {
                                366                 :                :                     /* weight var is used as storage for distance */
 2929                           367                 :            867 :                     state->state = WAITOPERAND;
                                368                 :            867 :                     *operator = OP_PHRASE;
                                369                 :            867 :                     return PT_OPR;
                                370                 :                :                 }
  474 tgl@sss.pgh.pa.us         371   [ +  +  +  -  :           3672 :                 else if (SOFT_ERROR_OCCURRED(state->escontext))
                                              +  + ]
                                372                 :                :                 {
                                373                 :                :                     /* parse_phrase_operator reported a soft error */
                                374                 :              3 :                     return PT_ERR;
                                375                 :                :                 }
 6081                           376         [ +  + ]:           3669 :                 else if (t_iseq(state->buf, ')'))
                                377                 :                :                 {
 2201 teodor@sigaev.ru          378                 :            531 :                     state->buf++;
 6081 tgl@sss.pgh.pa.us         379                 :            531 :                     state->count--;
 6064 teodor@sigaev.ru          380         [ -  + ]:            531 :                     return (state->count < 0) ? PT_ERR : PT_CLOSE;
                                381                 :                :                 }
 2201                           382         [ +  + ]:           3138 :                 else if (*state->buf == '\0')
                                383                 :                :                 {
 6064                           384                 :           1651 :                     return (state->count) ? PT_ERR : PT_END;
                                385                 :                :                 }
 6081 tgl@sss.pgh.pa.us         386         [ +  + ]:           1487 :                 else if (!t_isspace(state->buf))
                                387                 :                :                 {
 6064 teodor@sigaev.ru          388                 :              6 :                     return PT_ERR;
                                389                 :                :                 }
 2201                           390                 :           1481 :                 break;
                                391                 :                :         }
                                392                 :                : 
                                393                 :           2947 :         state->buf += pg_mblen(state->buf);
                                394                 :                :     }
                                395                 :                : }
                                396                 :                : 
                                397                 :                : static ts_tokentype
                                398                 :           1116 : gettoken_query_websearch(TSQueryParserState state, int8 *operator,
                                399                 :                :                          int *lenval, char **strval,
                                400                 :                :                          int16 *weight, bool *prefix)
                                401                 :                : {
                                402                 :           1116 :     *weight = 0;
                                403                 :           1116 :     *prefix = false;
                                404                 :                : 
                                405                 :                :     while (true)
                                406                 :                :     {
                                407      [ +  +  - ]:           1539 :         switch (state->state)
                                408                 :                :         {
                                409                 :            723 :             case WAITFIRSTOPERAND:
                                410                 :                :             case WAITOPERAND:
                                411         [ +  + ]:            723 :                 if (t_iseq(state->buf, '-'))
                                412                 :                :                 {
                                413                 :             33 :                     state->buf++;
                                414                 :             33 :                     state->state = WAITOPERAND;
                                415                 :                : 
                                416                 :             33 :                     *operator = OP_NOT;
                                417                 :             33 :                     return PT_OPR;
                                418                 :                :                 }
                                419         [ +  + ]:            690 :                 else if (t_iseq(state->buf, '"'))
                                420                 :                :                 {
                                421                 :                :                     /* Everything in quotes is processed as a single token */
                                422                 :                : 
                                423                 :                :                     /* skip opening quote */
                                424                 :             96 :                     state->buf++;
 1077 akorotkov@postgresql      425                 :             96 :                     *strval = state->buf;
                                426                 :                : 
                                427                 :                :                     /* iterate to the closing quote or end of the string */
                                428   [ +  +  +  + ]:            870 :                     while (*state->buf != '\0' && !t_iseq(state->buf, '"'))
                                429                 :            774 :                         state->buf++;
                                430                 :             96 :                     *lenval = state->buf - *strval;
                                431                 :                : 
                                432                 :                :                     /* skip closing quote if not end of the string */
                                433         [ +  + ]:             96 :                     if (*state->buf != '\0')
                                434                 :             84 :                         state->buf++;
                                435                 :                : 
                                436                 :             96 :                     state->state = WAITOPERATOR;
                                437                 :             96 :                     state->count++;
                                438                 :             96 :                     return PT_VAL;
                                439                 :                :                 }
 2201 teodor@sigaev.ru          440   [ +  -  +  +  :            594 :                 else if (ISOPERATOR(state->buf))
                                     +  +  +  +  +  
                                        +  +  +  +  
                                                 + ]
                                441                 :                :                 {
                                442                 :                :                     /* or else gettoken_tsvector() will raise an error */
                                443                 :             96 :                     state->buf++;
                                444                 :             96 :                     state->state = WAITOPERAND;
                                445                 :             96 :                     continue;
                                446                 :                :                 }
                                447         [ +  + ]:            498 :                 else if (!t_isspace(state->buf))
                                448                 :                :                 {
                                449                 :                :                     /*
                                450                 :                :                      * We rely on the tsvector parser to parse the value for
                                451                 :                :                      * us
                                452                 :                :                      */
                                453                 :            450 :                     reset_tsvector_parser(state->valstate, state->buf);
                                454         [ +  + ]:            450 :                     if (gettoken_tsvector(state->valstate, strval, lenval,
                                455                 :                :                                           NULL, NULL, &state->buf))
                                456                 :                :                     {
                                457                 :            441 :                         state->state = WAITOPERATOR;
                                458                 :            441 :                         return PT_VAL;
                                459                 :                :                     }
  474 tgl@sss.pgh.pa.us         460   [ -  +  -  -  :              9 :                     else if (SOFT_ERROR_OCCURRED(state->escontext))
                                              -  - ]
                                461                 :                :                     {
                                462                 :                :                         /* gettoken_tsvector reported a soft error */
  474 tgl@sss.pgh.pa.us         463                 :UBC           0 :                         return PT_ERR;
                                464                 :                :                     }
 2201 teodor@sigaev.ru          465         [ -  + ]:CBC           9 :                     else if (state->state == WAITFIRSTOPERAND)
                                466                 :                :                     {
 2201 teodor@sigaev.ru          467                 :UBC           0 :                         return PT_END;
                                468                 :                :                     }
                                469                 :                :                     else
                                470                 :                :                     {
                                471                 :                :                         /* finally, we have to provide an operand */
 2201 teodor@sigaev.ru          472                 :CBC           9 :                         pushStop(state);
                                473                 :              9 :                         return PT_END;
                                474                 :                :                     }
                                475                 :                :                 }
 6081 tgl@sss.pgh.pa.us         476                 :             48 :                 break;
                                477                 :                : 
 2201 teodor@sigaev.ru          478                 :            816 :             case WAITOPERATOR:
                                479         [ +  + ]:            816 :                 if (t_iseq(state->buf, '"'))
                                480                 :                :                 {
                                481                 :                :                     /*
                                482                 :                :                      * put implicit AND after an operand and handle this quote
                                483                 :                :                      * in WAITOPERAND
                                484                 :                :                      */
 1077 akorotkov@postgresql      485                 :             45 :                     state->state = WAITOPERAND;
                                486                 :             45 :                     *operator = OP_AND;
                                487                 :             45 :                     return PT_OPR;
                                488                 :                :                 }
 2201 teodor@sigaev.ru          489         [ +  + ]:            771 :                 else if (parse_or_operator(state))
                                490                 :                :                 {
                                491                 :             51 :                     state->state = WAITOPERAND;
                                492                 :             51 :                     *operator = OP_OR;
                                493                 :             51 :                     return PT_OPR;
                                494                 :                :                 }
                                495         [ +  + ]:            720 :                 else if (*state->buf == '\0')
                                496                 :                :                 {
 6064                           497                 :            195 :                     return PT_END;
                                498                 :                :                 }
 2201                           499         [ +  + ]:            525 :                 else if (!t_isspace(state->buf))
                                500                 :                :                 {
                                501                 :                :                     /* put implicit AND after an operand */
 1077 akorotkov@postgresql      502                 :            246 :                     *operator = OP_AND;
 2201 teodor@sigaev.ru          503                 :            246 :                     state->state = WAITOPERAND;
                                504                 :            246 :                     return PT_OPR;
                                505                 :                :                 }
 6081 tgl@sss.pgh.pa.us         506                 :            279 :                 break;
                                507                 :                :         }
                                508                 :                : 
                                509                 :            327 :         state->buf += pg_mblen(state->buf);
                                510                 :                :     }
                                511                 :                : }
                                512                 :                : 
                                513                 :                : static ts_tokentype
 2201 teodor@sigaev.ru          514                 :            108 : gettoken_query_plain(TSQueryParserState state, int8 *operator,
                                515                 :                :                      int *lenval, char **strval,
                                516                 :                :                      int16 *weight, bool *prefix)
                                517                 :                : {
                                518                 :            108 :     *weight = 0;
                                519                 :            108 :     *prefix = false;
                                520                 :                : 
                                521         [ +  + ]:            108 :     if (*state->buf == '\0')
                                522                 :             54 :         return PT_END;
                                523                 :                : 
                                524                 :             54 :     *strval = state->buf;
                                525                 :             54 :     *lenval = strlen(state->buf);
                                526                 :             54 :     state->buf += *lenval;
                                527                 :             54 :     state->count++;
                                528                 :             54 :     return PT_VAL;
                                529                 :                : }
                                530                 :                : 
                                531                 :                : /*
                                532                 :                :  * Push an operator to state->polstr
                                533                 :                :  */
                                534                 :                : void
 2929                           535                 :           3119 : pushOperator(TSQueryParserState state, int8 oper, int16 distance)
                                536                 :                : {
                                537                 :                :     QueryOperator *tmp;
                                538                 :                : 
                                539   [ +  +  +  +  :           3119 :     Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
                                        +  +  -  + ]
                                540                 :                : 
 5847 tgl@sss.pgh.pa.us         541                 :           3119 :     tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
 6064 teodor@sigaev.ru          542                 :           3119 :     tmp->type = QI_OPR;
                                543                 :           3119 :     tmp->oper = oper;
 2929                           544         [ +  + ]:           3119 :     tmp->distance = (oper == OP_PHRASE) ? distance : 0;
                                545                 :                :     /* left is filled in later with findoprnd */
                                546                 :                : 
 6064                           547                 :           3119 :     state->polstr = lcons(tmp, state->polstr);
                                548                 :           3119 : }
                                549                 :                : 
                                550                 :                : static void
 5812 tgl@sss.pgh.pa.us         551                 :           4197 : pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
                                552                 :                : {
                                553                 :                :     QueryOperand *tmp;
                                554                 :                : 
 6081                           555         [ -  + ]:           4197 :     if (distance >= MAXSTRPOS)
  474 tgl@sss.pgh.pa.us         556         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                557                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                558                 :                :                  errmsg("value is too big in tsquery: \"%s\"",
                                559                 :                :                         state->buffer)));
 6081 tgl@sss.pgh.pa.us         560         [ -  + ]:CBC        4197 :     if (lenval >= MAXSTRLEN)
  474 tgl@sss.pgh.pa.us         561         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                562                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                563                 :                :                  errmsg("operand is too long in tsquery: \"%s\"",
                                564                 :                :                         state->buffer)));
                                565                 :                : 
 5847 tgl@sss.pgh.pa.us         566                 :CBC        4197 :     tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
 6064 teodor@sigaev.ru          567                 :           4197 :     tmp->type = QI_VAL;
                                568                 :           4197 :     tmp->weight = weight;
 5812 tgl@sss.pgh.pa.us         569                 :           4197 :     tmp->prefix = prefix;
 6064 teodor@sigaev.ru          570                 :           4197 :     tmp->valcrc = (int32) valcrc;
 6081 tgl@sss.pgh.pa.us         571                 :           4197 :     tmp->length = lenval;
 6064 teodor@sigaev.ru          572                 :           4197 :     tmp->distance = distance;
                                573                 :                : 
                                574                 :           4197 :     state->polstr = lcons(tmp, state->polstr);
                                575                 :                : }
                                576                 :                : 
                                577                 :                : /*
                                578                 :                :  * Push an operand to state->polstr.
                                579                 :                :  *
                                580                 :                :  * strval must point to a string equal to state->curop. lenval is the length
                                581                 :                :  * of the string.
                                582                 :                :  */
                                583                 :                : void
 4311 peter_e@gmx.net           584                 :           4197 : pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
                                585                 :                : {
                                586                 :                :     pg_crc32    valcrc;
                                587                 :                : 
 6081 tgl@sss.pgh.pa.us         588         [ -  + ]:           4197 :     if (lenval >= MAXSTRLEN)
  474 tgl@sss.pgh.pa.us         589         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                590                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                591                 :                :                  errmsg("word is too long in tsquery: \"%s\"",
                                592                 :                :                         state->buffer)));
                                593                 :                : 
 3449 heikki.linnakangas@i      594                 :CBC        4197 :     INIT_LEGACY_CRC32(valcrc);
                                595         [ +  + ]:          14802 :     COMP_LEGACY_CRC32(valcrc, strval, lenval);
                                596                 :           4197 :     FIN_LEGACY_CRC32(valcrc);
 5812 tgl@sss.pgh.pa.us         597                 :           4197 :     pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
                                598                 :                : 
                                599                 :                :     /* append the value string to state.op, enlarging buffer if needed first */
 6081                           600         [ -  + ]:           4197 :     while (state->curop - state->op + lenval + 1 >= state->lenop)
                                601                 :                :     {
 5995 bruce@momjian.us          602                 :UBC           0 :         int         used = state->curop - state->op;
                                603                 :                : 
 6081 tgl@sss.pgh.pa.us         604                 :              0 :         state->lenop *= 2;
  432 peter@eisentraut.org      605                 :              0 :         state->op = (char *) repalloc(state->op, state->lenop);
 6064 teodor@sigaev.ru          606                 :              0 :         state->curop = state->op + used;
                                607                 :                :     }
  432 peter@eisentraut.org      608                 :CBC        4197 :     memcpy(state->curop, strval, lenval);
 6081 tgl@sss.pgh.pa.us         609                 :           4197 :     state->curop += lenval;
                                610                 :           4197 :     *(state->curop) = '\0';
                                611                 :           4197 :     state->curop++;
                                612                 :           4197 :     state->sumlen += lenval + 1 /* \0 */ ;
                                613                 :                : }
                                614                 :                : 
                                615                 :                : 
                                616                 :                : /*
                                617                 :                :  * Push a stopword placeholder to state->polstr
                                618                 :                :  */
                                619                 :                : void
 6064 teodor@sigaev.ru          620                 :            342 : pushStop(TSQueryParserState state)
                                621                 :                : {
                                622                 :                :     QueryOperand *tmp;
                                623                 :                : 
 5847 tgl@sss.pgh.pa.us         624                 :            342 :     tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
 6064 teodor@sigaev.ru          625                 :            342 :     tmp->type = QI_VALSTOP;
                                626                 :                : 
                                627                 :            342 :     state->polstr = lcons(tmp, state->polstr);
                                628                 :            342 : }
                                629                 :                : 
                                630                 :                : 
                                631                 :                : #define STACKDEPTH  32
                                632                 :                : 
                                633                 :                : typedef struct OperatorElement
                                634                 :                : {
                                635                 :                :     int8        op;
                                636                 :                :     int16       distance;
                                637                 :                : } OperatorElement;
                                638                 :                : 
                                639                 :                : static void
 2848                           640                 :           2783 : pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
                                641                 :                : {
 2799 tgl@sss.pgh.pa.us         642         [ -  + ]:           2783 :     if (*lenstack == STACKDEPTH)    /* internal error */
 2848 teodor@sigaev.ru          643         [ #  # ]:UBC           0 :         elog(ERROR, "tsquery stack too small");
                                644                 :                : 
 2848 teodor@sigaev.ru          645                 :CBC        2783 :     stack[*lenstack].op = op;
                                646                 :           2783 :     stack[*lenstack].distance = distance;
                                647                 :                : 
                                648                 :           2783 :     (*lenstack)++;
                                649                 :           2783 : }
                                650                 :                : 
                                651                 :                : static void
                                652                 :           5235 : cleanOpStack(TSQueryParserState state,
                                653                 :                :              OperatorElement *stack, int *lenstack, int8 op)
                                654                 :                : {
 2799 tgl@sss.pgh.pa.us         655                 :           5235 :     int         opPriority = OP_PRIORITY(op);
                                656                 :                : 
                                657         [ +  + ]:           8018 :     while (*lenstack)
                                658                 :                :     {
                                659                 :                :         /* NOT is right associative unlike to others */
 2830 teodor@sigaev.ru          660   [ +  +  +  +  :           3029 :         if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
                                              +  + ]
 2489 tgl@sss.pgh.pa.us         661         [ -  + ]:            159 :             (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
                                662                 :                :             break;
                                663                 :                : 
 2848 teodor@sigaev.ru          664                 :           2783 :         (*lenstack)--;
                                665                 :           2783 :         pushOperator(state, stack[*lenstack].op,
 2799 tgl@sss.pgh.pa.us         666                 :           2783 :                      stack[*lenstack].distance);
                                667                 :                :     }
 2848 teodor@sigaev.ru          668                 :           5235 : }
                                669                 :                : 
                                670                 :                : /*
                                671                 :                :  * Make polish (prefix) notation of query.
                                672                 :                :  *
                                673                 :                :  * See parse_tsquery for explanation of pushval.
                                674                 :                :  */
                                675                 :                : static void
 5995 bruce@momjian.us          676                 :           2461 : makepol(TSQueryParserState state,
                                677                 :                :         PushFunction pushval,
                                678                 :                :         Datum opaque)
                                679                 :                : {
 2866 rhaas@postgresql.org      680                 :           2461 :     int8        operator = 0;
                                681                 :                :     ts_tokentype type;
                                682                 :           2461 :     int         lenval = 0;
                                683                 :           2461 :     char       *strval = NULL;
                                684                 :                :     OperatorElement opstack[STACKDEPTH];
                                685                 :           2461 :     int         lenstack = 0;
                                686                 :           2461 :     int16       weight = 0;
                                687                 :                :     bool        prefix;
                                688                 :                : 
                                689                 :                :     /* since this function recurses, it could be driven to stack overflow */
 6071 tgl@sss.pgh.pa.us         690                 :           2461 :     check_stack_depth();
                                691                 :                : 
 2201 teodor@sigaev.ru          692                 :           9969 :     while ((type = state->gettoken(state, &operator,
                                693                 :                :                                    &lenval, &strval,
                                694         [ +  + ]:           9969 :                                    &weight, &prefix)) != PT_END)
                                695                 :                :     {
 6081 tgl@sss.pgh.pa.us         696   [ +  +  +  +  :           8048 :         switch (type)
                                                 + ]
                                697                 :                :         {
 6064 teodor@sigaev.ru          698                 :           4194 :             case PT_VAL:
 5812 tgl@sss.pgh.pa.us         699                 :           4194 :                 pushval(opaque, state, strval, lenval, weight, prefix);
 6081                           700                 :           4194 :                 break;
 6064 teodor@sigaev.ru          701                 :           2783 :             case PT_OPR:
 2848                           702                 :           2783 :                 cleanOpStack(state, opstack, &lenstack, operator);
                                703                 :           2783 :                 pushOpStack(opstack, &lenstack, operator, weight);
 6081 tgl@sss.pgh.pa.us         704                 :           2783 :                 break;
 6064 teodor@sigaev.ru          705                 :            531 :             case PT_OPEN:
                                706                 :            531 :                 makepol(state, pushval, opaque);
 6081 tgl@sss.pgh.pa.us         707                 :            531 :                 break;
 6064 teodor@sigaev.ru          708                 :            531 :             case PT_CLOSE:
 2799 tgl@sss.pgh.pa.us         709                 :            531 :                 cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
 6064 teodor@sigaev.ru          710                 :            540 :                 return;
                                711                 :              9 :             case PT_ERR:
                                712                 :                :             default:
                                713                 :                :                 /* don't overwrite a soft error saved by gettoken function */
  474 tgl@sss.pgh.pa.us         714   [ +  -  +  -  :              9 :                 if (!SOFT_ERROR_OCCURRED(state->escontext))
                                              +  + ]
                                715         [ +  + ]:              6 :                     errsave(state->escontext,
                                716                 :                :                             (errcode(ERRCODE_SYNTAX_ERROR),
                                717                 :                :                              errmsg("syntax error in tsquery: \"%s\"",
                                718                 :                :                                     state->buffer)));
                                719                 :              9 :                 return;
                                720                 :                :         }
                                721                 :                :         /* detect soft error in pushval or recursion */
                                722   [ +  +  +  -  :           7508 :         if (SOFT_ERROR_OCCURRED(state->escontext))
                                              -  + ]
  474 tgl@sss.pgh.pa.us         723                 :UBC           0 :             return;
                                724                 :                :     }
                                725                 :                : 
 2799 tgl@sss.pgh.pa.us         726                 :CBC        1921 :     cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
                                727                 :                : }
                                728                 :                : 
                                729                 :                : static void
 2929 teodor@sigaev.ru          730                 :           7649 : findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
                                731                 :                : {
                                732                 :                :     /* since this function recurses, it could be driven to stack overflow. */
 6064                           733                 :           7649 :     check_stack_depth();
                                734                 :                : 
                                735         [ -  + ]:           7649 :     if (*pos >= nnodes)
 5982 tgl@sss.pgh.pa.us         736         [ #  # ]:UBC           0 :         elog(ERROR, "malformed tsquery: operand not found");
                                737                 :                : 
 2929 teodor@sigaev.ru          738         [ +  + ]:CBC        7649 :     if (ptr[*pos].type == QI_VAL)
                                739                 :                :     {
                                740                 :           4188 :         (*pos)++;
                                741                 :                :     }
                                742         [ +  + ]:           3461 :     else if (ptr[*pos].type == QI_VALSTOP)
                                743                 :                :     {
 2866 rhaas@postgresql.org      744                 :            342 :         *needcleanup = true;    /* we'll have to remove stop words */
 6081 tgl@sss.pgh.pa.us         745                 :            342 :         (*pos)++;
                                746                 :                :     }
                                747                 :                :     else
                                748                 :                :     {
 6064 teodor@sigaev.ru          749         [ -  + ]:           3119 :         Assert(ptr[*pos].type == QI_OPR);
                                750                 :                : 
 5386 peter_e@gmx.net           751         [ +  + ]:           3119 :         if (ptr[*pos].qoperator.oper == OP_NOT)
                                752                 :                :         {
 2489 tgl@sss.pgh.pa.us         753                 :            498 :             ptr[*pos].qoperator.left = 1;   /* fixed offset */
 6064 teodor@sigaev.ru          754                 :            498 :             (*pos)++;
                                755                 :                : 
                                756                 :                :             /* process the only argument */
 2929                           757                 :            498 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                758                 :                :         }
                                759                 :                :         else
                                760                 :                :         {
 2866 rhaas@postgresql.org      761                 :           2621 :             QueryOperator *curitem = &ptr[*pos].qoperator;
 2489 tgl@sss.pgh.pa.us         762                 :           2621 :             int         tmp = *pos; /* save current position */
                                763                 :                : 
 2929 teodor@sigaev.ru          764   [ +  +  +  +  :           2621 :             Assert(curitem->oper == OP_AND ||
                                              -  + ]
                                765                 :                :                    curitem->oper == OP_OR ||
                                766                 :                :                    curitem->oper == OP_PHRASE);
                                767                 :                : 
 6064                           768                 :           2621 :             (*pos)++;
                                769                 :                : 
                                770                 :                :             /* process RIGHT argument */
 2929                           771                 :           2621 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                772                 :                : 
                                773                 :           2621 :             curitem->left = *pos - tmp; /* set LEFT arg's offset */
                                774                 :                : 
                                775                 :                :             /* process LEFT argument */
                                776                 :           2621 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                777                 :                :         }
                                778                 :                :     }
 6081 tgl@sss.pgh.pa.us         779                 :           7649 : }
                                780                 :                : 
                                781                 :                : 
                                782                 :                : /*
                                783                 :                :  * Fill in the left-fields previously left unfilled.
                                784                 :                :  * The input QueryItems must be in polish (prefix) notation.
                                785                 :                :  * Also, set *needcleanup to true if there are any QI_VALSTOP nodes.
                                786                 :                :  */
                                787                 :                : static void
 2929 teodor@sigaev.ru          788                 :           1909 : findoprnd(QueryItem *ptr, int size, bool *needcleanup)
                                789                 :                : {
                                790                 :                :     uint32      pos;
                                791                 :                : 
                                792                 :           1909 :     *needcleanup = false;
 6064                           793                 :           1909 :     pos = 0;
 2929                           794                 :           1909 :     findoprnd_recurse(ptr, &pos, size, needcleanup);
                                795                 :                : 
 6064                           796         [ -  + ]:           1909 :     if (pos != size)
 5982 tgl@sss.pgh.pa.us         797         [ #  # ]:UBC           0 :         elog(ERROR, "malformed tsquery: extra nodes");
 6064 teodor@sigaev.ru          798                 :CBC        1909 : }
                                799                 :                : 
                                800                 :                : 
                                801                 :                : /*
                                802                 :                :  * Parse the tsquery stored in "buf".
                                803                 :                :  *
                                804                 :                :  * Each value (operand) in the query is passed to pushval. pushval can
                                805                 :                :  * transform the simple value to an arbitrarily complex expression using
                                806                 :                :  * pushValue and pushOperator. It must push a single value with pushValue,
                                807                 :                :  * a complete expression with all operands, or a stopword placeholder
                                808                 :                :  * with pushStop, otherwise the prefix notation representation will be broken,
                                809                 :                :  * having an operator with no operand.
                                810                 :                :  *
                                811                 :                :  * opaque is passed on to pushval as is, pushval can use it to store its
                                812                 :                :  * private state.
                                813                 :                :  *
                                814                 :                :  * The pushval function can record soft errors via escontext.
                                815                 :                :  * Callers must check SOFT_ERROR_OCCURRED to detect that.
                                816                 :                :  *
                                817                 :                :  * A bitmask of flags (see ts_utils.h) and an error context object
                                818                 :                :  * can be provided as well.  If a soft error occurs, NULL is returned.
                                819                 :                :  */
                                820                 :                : TSQuery
 5995 bruce@momjian.us          821                 :           1930 : parse_tsquery(char *buf,
                                822                 :                :               PushFunction pushval,
                                823                 :                :               Datum opaque,
                                824                 :                :               int flags,
                                825                 :                :               Node *escontext)
                                826                 :                : {
                                827                 :                :     struct TSQueryParserStateData state;
                                828                 :                :     int         i;
                                829                 :                :     TSQuery     query;
                                830                 :                :     int         commonlen;
                                831                 :                :     QueryItem  *ptr;
                                832                 :                :     ListCell   *cell;
                                833                 :                :     bool        noisy;
                                834                 :                :     bool        needcleanup;
 2201 teodor@sigaev.ru          835                 :           1930 :     int         tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
                                836                 :                : 
                                837                 :                :     /* plain should not be used with web */
                                838         [ -  + ]:           1930 :     Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
                                839                 :                : 
                                840                 :                :     /* select suitable tokenizer */
                                841         [ +  + ]:           1930 :     if (flags & P_TSQ_PLAIN)
                                842                 :             54 :         state.gettoken = gettoken_query_plain;
                                843         [ +  + ]:           1876 :     else if (flags & P_TSQ_WEB)
                                844                 :                :     {
                                845                 :            204 :         state.gettoken = gettoken_query_websearch;
                                846                 :            204 :         tsv_flags |= P_TSV_IS_WEB;
                                847                 :                :     }
                                848                 :                :     else
                                849                 :           1672 :         state.gettoken = gettoken_query_standard;
                                850                 :                : 
                                851                 :                :     /* emit nuisance NOTICEs only if not doing soft errors */
  474 tgl@sss.pgh.pa.us         852   [ +  +  -  + ]:           1930 :     noisy = !(escontext && IsA(escontext, ErrorSaveContext));
                                853                 :                : 
                                854                 :                :     /* init state */
 6081                           855                 :           1930 :     state.buffer = buf;
                                856                 :           1930 :     state.buf = buf;
                                857                 :           1930 :     state.count = 0;
 2201 teodor@sigaev.ru          858                 :           1930 :     state.state = WAITFIRSTOPERAND;
 6064                           859                 :           1930 :     state.polstr = NIL;
  474 tgl@sss.pgh.pa.us         860                 :           1930 :     state.escontext = escontext;
                                861                 :                : 
                                862                 :                :     /* init value parser's state */
                                863                 :           1930 :     state.valstate = init_tsvector_parser(state.buffer, tsv_flags, escontext);
                                864                 :                : 
                                865                 :                :     /* init list of operand */
 6081                           866                 :           1930 :     state.sumlen = 0;
                                867                 :           1930 :     state.lenop = 64;
                                868                 :           1930 :     state.curop = state.op = (char *) palloc(state.lenop);
                                869                 :           1930 :     *(state.curop) = '\0';
                                870                 :                : 
                                871                 :                :     /* parse query & make polish notation (postfix, but in reverse order) */
 6064 teodor@sigaev.ru          872                 :           1930 :     makepol(&state, pushval, opaque);
                                873                 :                : 
                                874                 :           1930 :     close_tsvector_parser(state.valstate);
                                875                 :                : 
  474 tgl@sss.pgh.pa.us         876   [ +  +  +  -  :           1930 :     if (SOFT_ERROR_OCCURRED(escontext))
                                              +  + ]
                                877                 :              9 :         return NULL;
                                878                 :                : 
  606                           879         [ +  + ]:           1921 :     if (state.polstr == NIL)
                                880                 :                :     {
  474                           881         [ +  - ]:             12 :         if (noisy)
                                882         [ +  - ]:             12 :             ereport(NOTICE,
                                883                 :                :                     (errmsg("text-search query doesn't contain lexemes: \"%s\"",
                                884                 :                :                             state.buffer)));
 6081                           885                 :             12 :         query = (TSQuery) palloc(HDRSIZETQ);
                                886                 :             12 :         SET_VARSIZE(query, HDRSIZETQ);
                                887                 :             12 :         query->size = 0;
                                888                 :             12 :         return query;
                                889                 :                :     }
                                890                 :                : 
 3709 noah@leadboat.com         891         [ -  + ]:           1909 :     if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
  474 tgl@sss.pgh.pa.us         892         [ #  # ]:UBC           0 :         ereturn(escontext, NULL,
                                893                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                894                 :                :                  errmsg("tsquery is too large")));
 6064 teodor@sigaev.ru          895                 :CBC        1909 :     commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
                                896                 :                : 
                                897                 :                :     /* Pack the QueryItems in the final TSQuery struct to return to caller */
                                898                 :           1909 :     query = (TSQuery) palloc0(commonlen);
 6081 tgl@sss.pgh.pa.us         899                 :           1909 :     SET_VARSIZE(query, commonlen);
 6064 teodor@sigaev.ru          900                 :           1909 :     query->size = list_length(state.polstr);
 6081 tgl@sss.pgh.pa.us         901                 :           1909 :     ptr = GETQUERY(query);
                                902                 :                : 
                                903                 :                :     /* Copy QueryItems to TSQuery */
 6064 teodor@sigaev.ru          904                 :           1909 :     i = 0;
                                905   [ +  -  +  +  :           9558 :     foreach(cell, state.polstr)
                                              +  + ]
                                906                 :                :     {
 2866 rhaas@postgresql.org      907                 :           7649 :         QueryItem  *item = (QueryItem *) lfirst(cell);
                                908                 :                : 
 5995 bruce@momjian.us          909   [ +  +  +  - ]:           7649 :         switch (item->type)
                                910                 :                :         {
 6064 teodor@sigaev.ru          911                 :           4188 :             case QI_VAL:
                                912                 :           4188 :                 memcpy(&ptr[i], item, sizeof(QueryOperand));
                                913                 :           4188 :                 break;
                                914                 :            342 :             case QI_VALSTOP:
                                915                 :            342 :                 ptr[i].type = QI_VALSTOP;
                                916                 :            342 :                 break;
                                917                 :           3119 :             case QI_OPR:
                                918                 :           3119 :                 memcpy(&ptr[i], item, sizeof(QueryOperator));
                                919                 :           3119 :                 break;
 6064 teodor@sigaev.ru          920                 :UBC           0 :             default:
 5982 tgl@sss.pgh.pa.us         921         [ #  # ]:              0 :                 elog(ERROR, "unrecognized QueryItem type: %d", item->type);
                                922                 :                :         }
 6064 teodor@sigaev.ru          923                 :CBC        7649 :         i++;
                                924                 :                :     }
                                925                 :                : 
                                926                 :                :     /* Copy all the operand strings to TSQuery */
  432 peter@eisentraut.org      927                 :           1909 :     memcpy(GETOPERAND(query), state.op, state.sumlen);
 6081 tgl@sss.pgh.pa.us         928                 :           1909 :     pfree(state.op);
                                929                 :                : 
                                930                 :                :     /*
                                931                 :                :      * Set left operand pointers for every operator.  While we're at it,
                                932                 :                :      * detect whether there are any QI_VALSTOP nodes.
                                933                 :                :      */
 2929 teodor@sigaev.ru          934                 :           1909 :     findoprnd(ptr, query->size, &needcleanup);
                                935                 :                : 
                                936                 :                :     /*
                                937                 :                :      * If there are QI_VALSTOP nodes, delete them and simplify the tree.
                                938                 :                :      */
                                939         [ +  + ]:           1909 :     if (needcleanup)
  474 tgl@sss.pgh.pa.us         940                 :            222 :         query = cleanup_tsquery_stopwords(query, noisy);
                                941                 :                : 
 6081                           942                 :           1909 :     return query;
                                943                 :                : }
                                944                 :                : 
                                945                 :                : static void
 6061 teodor@sigaev.ru          946                 :           2650 : pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval,
                                947                 :                :              int16 weight, bool prefix)
                                948                 :                : {
 5812 tgl@sss.pgh.pa.us         949                 :           2650 :     pushValue(state, strval, lenval, weight, prefix);
 6064 teodor@sigaev.ru          950                 :           2650 : }
                                951                 :                : 
                                952                 :                : /*
                                953                 :                :  * in without morphology
                                954                 :                :  */
                                955                 :                : Datum
 6081 tgl@sss.pgh.pa.us         956                 :           1295 : tsqueryin(PG_FUNCTION_ARGS)
                                957                 :                : {
                                958                 :           1295 :     char       *in = PG_GETARG_CSTRING(0);
  474                           959                 :           1295 :     Node       *escontext = fcinfo->context;
                                960                 :                : 
                                961                 :           1295 :     PG_RETURN_TSQUERY(parse_tsquery(in,
                                962                 :                :                                     pushval_asis,
                                963                 :                :                                     PointerGetDatum(NULL),
                                964                 :                :                                     0,
                                965                 :                :                                     escontext));
                                966                 :                : }
                                967                 :                : 
                                968                 :                : /*
                                969                 :                :  * out function
                                970                 :                :  */
                                971                 :                : typedef struct
                                972                 :                : {
                                973                 :                :     QueryItem  *curpol;
                                974                 :                :     char       *buf;
                                975                 :                :     char       *cur;
                                976                 :                :     char       *op;
                                977                 :                :     int         buflen;
                                978                 :                : } INFIX;
                                979                 :                : 
                                980                 :                : /* Makes sure inf->buf is large enough for adding 'addsize' bytes */
                                981                 :                : #define RESIZEBUF(inf, addsize) \
                                982                 :                : while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
                                983                 :                : { \
                                984                 :                :     int len = (inf)->cur - (inf)->buf; \
                                985                 :                :     (inf)->buflen *= 2; \
                                986                 :                :     (inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
                                987                 :                :     (inf)->cur = (inf)->buf + len; \
                                988                 :                : }
                                989                 :                : 
                                990                 :                : /*
                                991                 :                :  * recursively traverse the tree and
                                992                 :                :  * print it in infix (human-readable) form
                                993                 :                :  */
                                994                 :                : static void
 2848 teodor@sigaev.ru          995                 :           3623 : infix(INFIX *in, int parentPriority, bool rightPhraseOp)
                                996                 :                : {
                                997                 :                :     /* since this function recurses, it could be driven to stack overflow. */
 6064                           998                 :           3623 :     check_stack_depth();
                                999                 :                : 
                               1000         [ +  + ]:           3623 :     if (in->curpol->type == QI_VAL)
                               1001                 :                :     {
 5386 peter_e@gmx.net          1002                 :           2096 :         QueryOperand *curpol = &in->curpol->qoperand;
 6064 teodor@sigaev.ru         1003                 :           2096 :         char       *op = in->op + curpol->distance;
                               1004                 :                :         int         clen;
                               1005                 :                : 
 5812 tgl@sss.pgh.pa.us        1006         [ +  + ]:           3420 :         RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
 6081                          1007                 :           2096 :         *(in->cur) = '\'';
                               1008                 :           2096 :         in->cur++;
                               1009         [ +  + ]:           8128 :         while (*op)
                               1010                 :                :         {
                               1011         [ +  + ]:           6032 :             if (t_iseq(op, '\''))
                               1012                 :                :             {
                               1013                 :              6 :                 *(in->cur) = '\'';
                               1014                 :              6 :                 in->cur++;
                               1015                 :                :             }
 5994 teodor@sigaev.ru         1016         [ +  + ]:           6026 :             else if (t_iseq(op, '\\'))
                               1017                 :                :             {
                               1018                 :              3 :                 *(in->cur) = '\\';
                               1019                 :              3 :                 in->cur++;
                               1020                 :                :             }
 6081 tgl@sss.pgh.pa.us        1021                 :           6032 :             COPYCHAR(in->cur, op);
                               1022                 :                : 
                               1023                 :           6032 :             clen = pg_mblen(op);
                               1024                 :           6032 :             op += clen;
                               1025                 :           6032 :             in->cur += clen;
                               1026                 :                :         }
                               1027                 :           2096 :         *(in->cur) = '\'';
                               1028                 :           2096 :         in->cur++;
 5812                          1029   [ +  +  +  + ]:           2096 :         if (curpol->weight || curpol->prefix)
                               1030                 :                :         {
 6081                          1031                 :             87 :             *(in->cur) = ':';
                               1032                 :             87 :             in->cur++;
 5421 bruce@momjian.us         1033         [ +  + ]:             87 :             if (curpol->prefix)
                               1034                 :                :             {
 5812 tgl@sss.pgh.pa.us        1035                 :             12 :                 *(in->cur) = '*';
                               1036                 :             12 :                 in->cur++;
                               1037                 :                :             }
 6064 teodor@sigaev.ru         1038         [ +  + ]:             87 :             if (curpol->weight & (1 << 3))
                               1039                 :                :             {
 6081 tgl@sss.pgh.pa.us        1040                 :             30 :                 *(in->cur) = 'A';
                               1041                 :             30 :                 in->cur++;
                               1042                 :                :             }
 6064 teodor@sigaev.ru         1043         [ +  + ]:             87 :             if (curpol->weight & (1 << 2))
                               1044                 :                :             {
 6081 tgl@sss.pgh.pa.us        1045                 :             48 :                 *(in->cur) = 'B';
                               1046                 :             48 :                 in->cur++;
                               1047                 :                :             }
 6064 teodor@sigaev.ru         1048         [ +  + ]:             87 :             if (curpol->weight & (1 << 1))
                               1049                 :                :             {
 6081 tgl@sss.pgh.pa.us        1050                 :              9 :                 *(in->cur) = 'C';
                               1051                 :              9 :                 in->cur++;
                               1052                 :                :             }
 6064 teodor@sigaev.ru         1053         [ +  + ]:             87 :             if (curpol->weight & 1)
                               1054                 :                :             {
 6081 tgl@sss.pgh.pa.us        1055                 :              3 :                 *(in->cur) = 'D';
                               1056                 :              3 :                 in->cur++;
                               1057                 :                :             }
                               1058                 :                :         }
                               1059                 :           2096 :         *(in->cur) = '\0';
                               1060                 :           2096 :         in->curpol++;
                               1061                 :                :     }
 5386 peter_e@gmx.net          1062         [ +  + ]:           1527 :     else if (in->curpol->qoperator.oper == OP_NOT)
                               1063                 :                :     {
 2848 teodor@sigaev.ru         1064                 :            186 :         int         priority = QO_PRIORITY(in->curpol);
                               1065                 :                : 
 2929                          1066         [ -  + ]:            186 :         if (priority < parentPriority)
                               1067                 :                :         {
 6081 tgl@sss.pgh.pa.us        1068         [ #  # ]:UBC           0 :             RESIZEBUF(in, 2);
                               1069                 :              0 :             sprintf(in->cur, "( ");
                               1070                 :              0 :             in->cur = strchr(in->cur, '\0');
                               1071                 :                :         }
 2929 teodor@sigaev.ru         1072         [ -  + ]:CBC         186 :         RESIZEBUF(in, 1);
                               1073                 :            186 :         *(in->cur) = '!';
                               1074                 :            186 :         in->cur++;
                               1075                 :            186 :         *(in->cur) = '\0';
                               1076                 :            186 :         in->curpol++;
                               1077                 :                : 
 2848                          1078                 :            186 :         infix(in, priority, false);
 2929                          1079         [ -  + ]:            186 :         if (priority < parentPriority)
                               1080                 :                :         {
 6081 tgl@sss.pgh.pa.us        1081         [ #  # ]:UBC           0 :             RESIZEBUF(in, 2);
                               1082                 :              0 :             sprintf(in->cur, " )");
                               1083                 :              0 :             in->cur = strchr(in->cur, '\0');
                               1084                 :                :         }
                               1085                 :                :     }
                               1086                 :                :     else
                               1087                 :                :     {
 5386 peter_e@gmx.net          1088                 :CBC        1341 :         int8        op = in->curpol->qoperator.oper;
 2848 teodor@sigaev.ru         1089                 :           1341 :         int         priority = QO_PRIORITY(in->curpol);
 2929                          1090                 :           1341 :         int16       distance = in->curpol->qoperator.distance;
                               1091                 :                :         INFIX       nrm;
                               1092                 :           1341 :         bool        needParenthesis = false;
                               1093                 :                : 
 6081 tgl@sss.pgh.pa.us        1094                 :           1341 :         in->curpol++;
 2929 teodor@sigaev.ru         1095   [ +  +  +  + ]:           1341 :         if (priority < parentPriority ||
                               1096                 :                :         /* phrase operator depends on order */
 2799 tgl@sss.pgh.pa.us        1097         [ +  + ]:            360 :             (op == OP_PHRASE && rightPhraseOp))
                               1098                 :                :         {
 2929 teodor@sigaev.ru         1099                 :            166 :             needParenthesis = true;
 6081 tgl@sss.pgh.pa.us        1100         [ -  + ]:            166 :             RESIZEBUF(in, 2);
                               1101                 :            166 :             sprintf(in->cur, "( ");
                               1102                 :            166 :             in->cur = strchr(in->cur, '\0');
                               1103                 :                :         }
                               1104                 :                : 
                               1105                 :           1341 :         nrm.curpol = in->curpol;
                               1106                 :           1341 :         nrm.op = in->op;
                               1107                 :           1341 :         nrm.buflen = 16;
                               1108                 :           1341 :         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1109                 :                : 
                               1110                 :                :         /* get right operand */
 2848 teodor@sigaev.ru         1111                 :           1341 :         infix(&nrm, priority, (op == OP_PHRASE));
                               1112                 :                : 
                               1113                 :                :         /* get & print left operand */
 6081 tgl@sss.pgh.pa.us        1114                 :           1341 :         in->curpol = nrm.curpol;
 2848 teodor@sigaev.ru         1115                 :           1341 :         infix(in, priority, false);
                               1116                 :                : 
                               1117                 :                :         /* print operator & right operand */
 2866 rhaas@postgresql.org     1118         [ +  + ]:           1828 :         RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
 5995 bruce@momjian.us         1119   [ +  +  +  - ]:           1341 :         switch (op)
                               1120                 :                :         {
 6064 teodor@sigaev.ru         1121                 :            363 :             case OP_OR:
                               1122                 :            363 :                 sprintf(in->cur, " | %s", nrm.buf);
                               1123                 :            363 :                 break;
                               1124                 :            612 :             case OP_AND:
                               1125                 :            612 :                 sprintf(in->cur, " & %s", nrm.buf);
                               1126                 :            612 :                 break;
 2929                          1127                 :            366 :             case OP_PHRASE:
                               1128         [ +  + ]:            366 :                 if (distance != 1)
                               1129                 :             87 :                     sprintf(in->cur, " <%d> %s", distance, nrm.buf);
                               1130                 :                :                 else
                               1131                 :            279 :                     sprintf(in->cur, " <-> %s", nrm.buf);
                               1132                 :            366 :                 break;
 6064 teodor@sigaev.ru         1133                 :UBC           0 :             default:
                               1134                 :                :                 /* OP_NOT is handled in above if-branch */
 5982 tgl@sss.pgh.pa.us        1135         [ #  # ]:              0 :                 elog(ERROR, "unrecognized operator type: %d", op);
                               1136                 :                :         }
 6081 tgl@sss.pgh.pa.us        1137                 :CBC        1341 :         in->cur = strchr(in->cur, '\0');
                               1138                 :           1341 :         pfree(nrm.buf);
                               1139                 :                : 
 2929 teodor@sigaev.ru         1140         [ +  + ]:           1341 :         if (needParenthesis)
                               1141                 :                :         {
 6081 tgl@sss.pgh.pa.us        1142         [ -  + ]:            166 :             RESIZEBUF(in, 2);
                               1143                 :            166 :             sprintf(in->cur, " )");
                               1144                 :            166 :             in->cur = strchr(in->cur, '\0');
                               1145                 :                :         }
                               1146                 :                :     }
                               1147                 :           3623 : }
                               1148                 :                : 
                               1149                 :                : Datum
                               1150                 :            770 : tsqueryout(PG_FUNCTION_ARGS)
                               1151                 :                : {
                               1152                 :            770 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1153                 :                :     INFIX       nrm;
                               1154                 :                : 
                               1155         [ +  + ]:            770 :     if (query->size == 0)
                               1156                 :                :     {
                               1157                 :             15 :         char       *b = palloc(1);
                               1158                 :                : 
                               1159                 :             15 :         *b = '\0';
                               1160                 :             15 :         PG_RETURN_POINTER(b);
                               1161                 :                :     }
                               1162                 :            755 :     nrm.curpol = GETQUERY(query);
                               1163                 :            755 :     nrm.buflen = 32;
                               1164                 :            755 :     nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1165                 :            755 :     *(nrm.cur) = '\0';
                               1166                 :            755 :     nrm.op = GETOPERAND(query);
 2799                          1167                 :            755 :     infix(&nrm, -1 /* lowest priority */ , false);
                               1168                 :                : 
 6081                          1169         [ -  + ]:            755 :     PG_FREE_IF_COPY(query, 0);
                               1170                 :            755 :     PG_RETURN_CSTRING(nrm.buf);
                               1171                 :                : }
                               1172                 :                : 
                               1173                 :                : /*
                               1174                 :                :  * Binary Input / Output functions. The binary format is as follows:
                               1175                 :                :  *
                               1176                 :                :  * uint32    number of operators/operands in the query
                               1177                 :                :  *
                               1178                 :                :  * Followed by the operators and operands, in prefix notation. For each
                               1179                 :                :  * operand:
                               1180                 :                :  *
                               1181                 :                :  * uint8    type, QI_VAL
                               1182                 :                :  * uint8    weight
                               1183                 :                :  *          operand text in client encoding, null-terminated
                               1184                 :                :  * uint8    prefix
                               1185                 :                :  *
                               1186                 :                :  * For each operator:
                               1187                 :                :  * uint8    type, QI_OPR
                               1188                 :                :  * uint8    operator, one of OP_AND, OP_PHRASE OP_OR, OP_NOT.
                               1189                 :                :  * uint16   distance (only for OP_PHRASE)
                               1190                 :                :  */
                               1191                 :                : Datum
 6081 tgl@sss.pgh.pa.us        1192                 :UBC           0 : tsquerysend(PG_FUNCTION_ARGS)
                               1193                 :                : {
                               1194                 :              0 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1195                 :                :     StringInfoData buf;
                               1196                 :                :     int         i;
                               1197                 :              0 :     QueryItem  *item = GETQUERY(query);
                               1198                 :                : 
                               1199                 :              0 :     pq_begintypsend(&buf);
                               1200                 :                : 
 2377 andres@anarazel.de       1201                 :              0 :     pq_sendint32(&buf, query->size);
 6081 tgl@sss.pgh.pa.us        1202         [ #  # ]:              0 :     for (i = 0; i < query->size; i++)
                               1203                 :                :     {
 2377 andres@anarazel.de       1204                 :              0 :         pq_sendint8(&buf, item->type);
                               1205                 :                : 
 5995 bruce@momjian.us         1206      [ #  #  # ]:              0 :         switch (item->type)
                               1207                 :                :         {
 6064 teodor@sigaev.ru         1208                 :              0 :             case QI_VAL:
 2377 andres@anarazel.de       1209                 :              0 :                 pq_sendint8(&buf, item->qoperand.weight);
                               1210                 :              0 :                 pq_sendint8(&buf, item->qoperand.prefix);
 5386 peter_e@gmx.net          1211                 :              0 :                 pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
 6064 teodor@sigaev.ru         1212                 :              0 :                 break;
                               1213                 :              0 :             case QI_OPR:
 2377 andres@anarazel.de       1214                 :              0 :                 pq_sendint8(&buf, item->qoperator.oper);
 2929 teodor@sigaev.ru         1215         [ #  # ]:              0 :                 if (item->qoperator.oper == OP_PHRASE)
 2377 andres@anarazel.de       1216                 :              0 :                     pq_sendint16(&buf, item->qoperator.distance);
 6064 teodor@sigaev.ru         1217                 :              0 :                 break;
                               1218                 :              0 :             default:
 5982 tgl@sss.pgh.pa.us        1219         [ #  # ]:              0 :                 elog(ERROR, "unrecognized tsquery node type: %d", item->type);
                               1220                 :                :         }
 6081                          1221                 :              0 :         item++;
                               1222                 :                :     }
                               1223                 :                : 
                               1224         [ #  # ]:              0 :     PG_FREE_IF_COPY(query, 0);
                               1225                 :                : 
                               1226                 :              0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                               1227                 :                : }
                               1228                 :                : 
                               1229                 :                : Datum
                               1230                 :              0 : tsqueryrecv(PG_FUNCTION_ARGS)
                               1231                 :                : {
 2866 rhaas@postgresql.org     1232                 :              0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                               1233                 :                :     TSQuery     query;
                               1234                 :                :     int         i,
                               1235                 :                :                 len;
                               1236                 :                :     QueryItem  *item;
                               1237                 :                :     int         datalen;
                               1238                 :                :     char       *ptr;
                               1239                 :                :     uint32      size;
                               1240                 :                :     const char **operands;
                               1241                 :                :     bool        needcleanup;
                               1242                 :                : 
 6081 tgl@sss.pgh.pa.us        1243                 :              0 :     size = pq_getmsgint(buf, sizeof(uint32));
 6064 teodor@sigaev.ru         1244         [ #  # ]:              0 :     if (size > (MaxAllocSize / sizeof(QueryItem)))
 6081 tgl@sss.pgh.pa.us        1245         [ #  # ]:              0 :         elog(ERROR, "invalid size of tsquery");
                               1246                 :                : 
                               1247                 :                :     /* Allocate space to temporarily hold operand strings */
 6064 teodor@sigaev.ru         1248                 :              0 :     operands = palloc(size * sizeof(char *));
                               1249                 :                : 
                               1250                 :                :     /* Allocate space for all the QueryItems. */
                               1251                 :              0 :     len = HDRSIZETQ + sizeof(QueryItem) * size;
                               1252                 :              0 :     query = (TSQuery) palloc0(len);
 6081 tgl@sss.pgh.pa.us        1253                 :              0 :     query->size = size;
                               1254                 :              0 :     item = GETQUERY(query);
                               1255                 :                : 
 6064 teodor@sigaev.ru         1256                 :              0 :     datalen = 0;
 6081 tgl@sss.pgh.pa.us        1257         [ #  # ]:              0 :     for (i = 0; i < size; i++)
                               1258                 :                :     {
                               1259                 :              0 :         item->type = (int8) pq_getmsgint(buf, sizeof(int8));
                               1260                 :                : 
 6064 teodor@sigaev.ru         1261         [ #  # ]:              0 :         if (item->type == QI_VAL)
                               1262                 :                :         {
                               1263                 :                :             size_t      val_len;    /* length after recoding to server
                               1264                 :                :                                      * encoding */
                               1265                 :                :             uint8       weight;
                               1266                 :                :             uint8       prefix;
                               1267                 :                :             const char *val;
                               1268                 :                :             pg_crc32    valcrc;
                               1269                 :                : 
 5995 bruce@momjian.us         1270                 :              0 :             weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
 5812 tgl@sss.pgh.pa.us        1271                 :              0 :             prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
 6064 teodor@sigaev.ru         1272                 :              0 :             val = pq_getmsgstring(buf);
                               1273                 :              0 :             val_len = strlen(val);
                               1274                 :                : 
                               1275                 :                :             /* Sanity checks */
                               1276                 :                : 
                               1277         [ #  # ]:              0 :             if (weight > 0xF)
 5982 tgl@sss.pgh.pa.us        1278         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: invalid weight bitmap");
                               1279                 :                : 
 6064 teodor@sigaev.ru         1280         [ #  # ]:              0 :             if (val_len > MAXSTRLEN)
 5982 tgl@sss.pgh.pa.us        1281         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: operand too long");
                               1282                 :                : 
 6064 teodor@sigaev.ru         1283         [ #  # ]:              0 :             if (datalen > MAXSTRPOS)
 5982 tgl@sss.pgh.pa.us        1284         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: total operand length exceeded");
                               1285                 :                : 
                               1286                 :                :             /* Looks valid. */
                               1287                 :                : 
 3449 heikki.linnakangas@i     1288                 :              0 :             INIT_LEGACY_CRC32(valcrc);
                               1289         [ #  # ]:              0 :             COMP_LEGACY_CRC32(valcrc, val, val_len);
                               1290                 :              0 :             FIN_LEGACY_CRC32(valcrc);
                               1291                 :                : 
 5386 peter_e@gmx.net          1292                 :              0 :             item->qoperand.weight = weight;
                               1293                 :              0 :             item->qoperand.prefix = (prefix) ? true : false;
                               1294                 :              0 :             item->qoperand.valcrc = (int32) valcrc;
                               1295                 :              0 :             item->qoperand.length = val_len;
                               1296                 :              0 :             item->qoperand.distance = datalen;
                               1297                 :                : 
                               1298                 :                :             /*
                               1299                 :                :              * Operand strings are copied to the final struct after this loop;
                               1300                 :                :              * here we just collect them to an array
                               1301                 :                :              */
 6064 teodor@sigaev.ru         1302                 :              0 :             operands[i] = val;
                               1303                 :                : 
 2489 tgl@sss.pgh.pa.us        1304                 :              0 :             datalen += val_len + 1; /* + 1 for the '\0' terminator */
                               1305                 :                :         }
 6064 teodor@sigaev.ru         1306         [ #  # ]:              0 :         else if (item->type == QI_OPR)
                               1307                 :                :         {
                               1308                 :                :             int8        oper;
                               1309                 :                : 
                               1310                 :              0 :             oper = (int8) pq_getmsgint(buf, sizeof(int8));
 2929                          1311   [ #  #  #  #  :              0 :             if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
                                        #  #  #  # ]
 5982 tgl@sss.pgh.pa.us        1312         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: unrecognized operator type %d",
                               1313                 :                :                      (int) oper);
 6064 teodor@sigaev.ru         1314         [ #  # ]:              0 :             if (i == size - 1)
                               1315         [ #  # ]:              0 :                 elog(ERROR, "invalid pointer to right operand");
                               1316                 :                : 
 5386 peter_e@gmx.net          1317                 :              0 :             item->qoperator.oper = oper;
 2929 teodor@sigaev.ru         1318         [ #  # ]:              0 :             if (oper == OP_PHRASE)
                               1319                 :              0 :                 item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
                               1320                 :                :         }
                               1321                 :                :         else
 5982 tgl@sss.pgh.pa.us        1322         [ #  # ]:              0 :             elog(ERROR, "unrecognized tsquery node type: %d", item->type);
                               1323                 :                : 
 6081                          1324                 :              0 :         item++;
                               1325                 :                :     }
                               1326                 :                : 
                               1327                 :                :     /* Enlarge buffer to make room for the operand values. */
                               1328                 :              0 :     query = (TSQuery) repalloc(query, len + datalen);
                               1329                 :              0 :     item = GETQUERY(query);
                               1330                 :              0 :     ptr = GETOPERAND(query);
                               1331                 :                : 
                               1332                 :                :     /*
                               1333                 :                :      * Fill in the left-pointers. Checks that the tree is well-formed as a
                               1334                 :                :      * side-effect.
                               1335                 :                :      */
 2929 teodor@sigaev.ru         1336                 :              0 :     findoprnd(item, size, &needcleanup);
                               1337                 :                : 
                               1338                 :                :     /* Can't have found any QI_VALSTOP nodes */
 2671 tgl@sss.pgh.pa.us        1339         [ #  # ]:              0 :     Assert(!needcleanup);
                               1340                 :                : 
                               1341                 :                :     /* Copy operands to output struct */
 6081                          1342         [ #  # ]:              0 :     for (i = 0; i < size; i++)
                               1343                 :                :     {
 6064 teodor@sigaev.ru         1344         [ #  # ]:              0 :         if (item->type == QI_VAL)
                               1345                 :                :         {
 5386 peter_e@gmx.net          1346                 :              0 :             memcpy(ptr, operands[i], item->qoperand.length + 1);
                               1347                 :              0 :             ptr += item->qoperand.length + 1;
                               1348                 :                :         }
 6081 tgl@sss.pgh.pa.us        1349                 :              0 :         item++;
                               1350                 :                :     }
                               1351                 :                : 
 6064 teodor@sigaev.ru         1352                 :              0 :     pfree(operands);
                               1353                 :                : 
 6081 tgl@sss.pgh.pa.us        1354         [ #  # ]:              0 :     Assert(ptr - GETOPERAND(query) == datalen);
                               1355                 :                : 
                               1356                 :              0 :     SET_VARSIZE(query, len + datalen);
                               1357                 :                : 
 2929 teodor@sigaev.ru         1358                 :              0 :     PG_RETURN_TSQUERY(query);
                               1359                 :                : }
                               1360                 :                : 
                               1361                 :                : /*
                               1362                 :                :  * debug function, used only for view query
                               1363                 :                :  * which will be executed in non-leaf pages in index
                               1364                 :                :  */
                               1365                 :                : Datum
 6081 tgl@sss.pgh.pa.us        1366                 :              0 : tsquerytree(PG_FUNCTION_ARGS)
                               1367                 :                : {
                               1368                 :              0 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1369                 :                :     INFIX       nrm;
                               1370                 :                :     text       *res;
                               1371                 :                :     QueryItem  *q;
                               1372                 :                :     int         len;
                               1373                 :                : 
                               1374         [ #  # ]:              0 :     if (query->size == 0)
                               1375                 :                :     {
                               1376                 :              0 :         res = (text *) palloc(VARHDRSZ);
                               1377                 :              0 :         SET_VARSIZE(res, VARHDRSZ);
                               1378                 :              0 :         PG_RETURN_POINTER(res);
                               1379                 :                :     }
                               1380                 :                : 
                               1381                 :              0 :     q = clean_NOT(GETQUERY(query), &len);
                               1382                 :                : 
                               1383         [ #  # ]:              0 :     if (!q)
                               1384                 :                :     {
 5864                          1385                 :              0 :         res = cstring_to_text("T");
                               1386                 :                :     }
                               1387                 :                :     else
                               1388                 :                :     {
 6081                          1389                 :              0 :         nrm.curpol = q;
                               1390                 :              0 :         nrm.buflen = 32;
                               1391                 :              0 :         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1392                 :              0 :         *(nrm.cur) = '\0';
                               1393                 :              0 :         nrm.op = GETOPERAND(query);
 2848 teodor@sigaev.ru         1394                 :              0 :         infix(&nrm, -1, false);
 5864 tgl@sss.pgh.pa.us        1395                 :              0 :         res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
 6081                          1396                 :              0 :         pfree(q);
                               1397                 :                :     }
                               1398                 :                : 
                               1399         [ #  # ]:              0 :     PG_FREE_IF_COPY(query, 0);
                               1400                 :                : 
 5864                          1401                 :              0 :     PG_RETURN_TEXT_P(res);
                               1402                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622