LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - tsquery.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 77.5 % 599 464 135 464
Current Date: 2025-09-06 07:49:51 +0900 Functions: 87.0 % 23 20 3 20
Baseline: lcov-20250906-005545-baseline Branches: 62.7 % 407 255 152 255
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 6 6 6
(360..) days: 77.2 % 593 458 135 458
Function coverage date bins:
(360..) days: 87.0 % 23 20 3 20
Branch coverage date bins:
(30,360] days: 83.3 % 12 10 2 10
(360..) days: 62.0 % 395 245 150 245

 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-2025, 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 *
 6322 tgl@sss.pgh.pa.us         114                 :CBC        3603 : get_modifiers(char *buf, int16 *weight, bool *prefix)
                                115                 :                : {
 6591                           116                 :           3603 :     *weight = 0;
 6322                           117                 :           3603 :     *prefix = false;
                                118                 :                : 
 6591                           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;
 6322                           143                 :            159 :             case '*':
                                144                 :            159 :                 *prefix = true;
                                145                 :            159 :                 break;
 6591                           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
 2711 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
 3376 rhaas@postgresql.org      173                 :           4539 :     }           state = PHRASE_OPEN;
 2711 teodor@sigaev.ru          174                 :           4539 :     char       *ptr = pstate->buf;
                                175                 :                :     char       *endptr;
 2994 tgl@sss.pgh.pa.us         176                 :           4539 :     long        l = 1;          /* default distance */
                                177                 :                : 
 3439 teodor@sigaev.ru          178         [ +  + ]:          11682 :     while (*ptr)
                                179                 :                :     {
 3376 rhaas@postgresql.org      180   [ +  +  +  +  :           5492 :         switch (state)
                                                 - ]
                                181                 :                :         {
 3439 teodor@sigaev.ru          182                 :           2888 :             case PHRASE_OPEN:
 2711                           183         [ +  + ]:           2888 :                 if (t_iseq(ptr, '<'))
                                184                 :                :                 {
                                185                 :            870 :                     state = PHRASE_DIST;
                                186                 :            870 :                     ptr++;
                                187                 :                :                 }
                                188                 :                :                 else
                                189                 :           2018 :                     return false;
 3439                           190                 :            870 :                 break;
                                191                 :                : 
                                192                 :            870 :             case PHRASE_DIST:
                                193         [ +  + ]:            870 :                 if (t_iseq(ptr, '-'))
                                194                 :                :                 {
                                195                 :            723 :                     state = PHRASE_CLOSE;
                                196                 :            723 :                     ptr++;
 2711                           197                 :            723 :                     continue;
                                198                 :                :                 }
                                199                 :                : 
  263 peter@eisentraut.org      200         [ -  + ]:            147 :                 if (!isdigit((unsigned char) *ptr))
 2711 teodor@sigaev.ru          201                 :UBC           0 :                     return false;
                                202                 :                : 
 2994 tgl@sss.pgh.pa.us         203                 :CBC         147 :                 errno = 0;
 3439 teodor@sigaev.ru          204                 :            147 :                 l = strtol(ptr, &endptr, 10);
                                205         [ -  + ]:            147 :                 if (ptr == endptr)
 2711 teodor@sigaev.ru          206                 :UBC           0 :                     return false;
 2994 tgl@sss.pgh.pa.us         207   [ +  -  +  -  :CBC         147 :                 else if (errno == ERANGE || l < 0 || l > MAXENTRYPOS)
                                              +  + ]
  984                           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                 :                :                 {
 3439 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
 2711 teodor@sigaev.ru          226                 :UBC           0 :                     return false;
 3439 teodor@sigaev.ru          227                 :CBC         867 :                 break;
                                228                 :                : 
                                229                 :            867 :             case PHRASE_FINISH:
                                230                 :            867 :                 *distance = (int16) l;
 2711                           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                 :            699 : parse_or_operator(TSQueryParserState pstate)
                                245                 :                : {
 2690 tgl@sss.pgh.pa.us         246                 :            699 :     char       *ptr = pstate->buf;
                                247                 :                : 
                                248                 :                :     /* it should begin with "OR" literal */
 2711 teodor@sigaev.ru          249         [ +  + ]:            699 :     if (pg_strncasecmp(ptr, "or", 2) != 0)
                                250                 :            624 :         return false;
                                251                 :                : 
                                252                 :             75 :     ptr += 2;
                                253                 :                : 
                                254                 :                :     /*
                                255                 :                :      * it shouldn't be a part of any word but somewhere later it should be
                                256                 :                :      * some operand
                                257                 :                :      */
 2690 tgl@sss.pgh.pa.us         258         [ +  + ]:             75 :     if (*ptr == '\0')           /* no operand */
 2711 teodor@sigaev.ru          259                 :              3 :         return false;
                                260                 :                : 
                                261                 :                :     /* it shouldn't be a part of any word */
 1066 tgl@sss.pgh.pa.us         262   [ +  +  +  +  :             72 :     if (t_iseq(ptr, '-') || t_iseq(ptr, '_') || t_isalnum(ptr))
                                              +  + ]
 2711 teodor@sigaev.ru          263                 :             12 :         return false;
                                264                 :                : 
                                265                 :                :     for (;;)
                                266                 :                :     {
                                267                 :             60 :         ptr += pg_mblen(ptr);
                                268                 :                : 
 2690 tgl@sss.pgh.pa.us         269         [ +  + ]:             60 :         if (*ptr == '\0')       /* got end of string without operand */
 2711 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                 :                :          */
  263 peter@eisentraut.org      277         [ +  - ]:             54 :         if (!isspace((unsigned char) *ptr))
 2711 teodor@sigaev.ru          278                 :             54 :             break;
                                279                 :                :     }
                                280                 :                : 
                                281                 :             54 :     pstate->buf += 2;
                                282                 :             54 :     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                 :                : {
 6322 tgl@sss.pgh.pa.us         290                 :           8745 :     *weight = 0;
                                291                 :           8745 :     *prefix = false;
                                292                 :                : 
                                293                 :                :     while (true)
                                294                 :                :     {
 6591                           295      [ +  +  - ]:          11692 :         switch (state->state)
                                296                 :                :         {
                                297                 :           6077 :             case WAITFIRSTOPERAND:
                                298                 :                :             case WAITOPERAND:
                                299         [ +  + ]:           6077 :                 if (t_iseq(state->buf, '!'))
                                300                 :                :                 {
 2711 teodor@sigaev.ru          301                 :            465 :                     state->buf++;
 6591 tgl@sss.pgh.pa.us         302                 :            465 :                     state->state = WAITOPERAND;
 2711 teodor@sigaev.ru          303                 :            465 :                     *operator = OP_NOT;
 6574                           304                 :            465 :                     return PT_OPR;
                                305                 :                :                 }
 6591 tgl@sss.pgh.pa.us         306         [ +  + ]:           5612 :                 else if (t_iseq(state->buf, '('))
                                307                 :                :                 {
 2711 teodor@sigaev.ru          308                 :            531 :                     state->buf++;
 6591 tgl@sss.pgh.pa.us         309                 :            531 :                     state->state = WAITOPERAND;
 2711 teodor@sigaev.ru          310                 :            531 :                     state->count++;
 6574                           311                 :            531 :                     return PT_OPEN;
                                312                 :                :                 }
 6591 tgl@sss.pgh.pa.us         313         [ -  + ]:           5081 :                 else if (t_iseq(state->buf, ':'))
                                314                 :                :                 {
                                315                 :                :                     /* generic syntax error message is fine */
  984 tgl@sss.pgh.pa.us         316                 :UBC           0 :                     return PT_ERR;
                                317                 :                :                 }
  263 peter@eisentraut.org      318         [ +  + ]:CBC        5081 :                 else if (!isspace((unsigned char) *state->buf))
                                319                 :                :                 {
                                320                 :                :                     /*
                                321                 :                :                      * We rely on the tsvector parser to parse the value for
                                322                 :                :                      * us
                                323                 :                :                      */
 6574 teodor@sigaev.ru          324                 :           3615 :                     reset_tsvector_parser(state->valstate, state->buf);
 2711                           325         [ +  + ]:           3615 :                     if (gettoken_tsvector(state->valstate, strval, lenval,
                                326                 :                :                                           NULL, NULL, &state->buf))
                                327                 :                :                     {
 6322 tgl@sss.pgh.pa.us         328                 :           3603 :                         state->buf = get_modifiers(state->buf, weight, prefix);
 6591                           329                 :           3603 :                         state->state = WAITOPERATOR;
 6574 teodor@sigaev.ru          330                 :           3603 :                         return PT_VAL;
                                331                 :                :                     }
  984 tgl@sss.pgh.pa.us         332   [ -  +  -  -  :             12 :                     else if (SOFT_ERROR_OCCURRED(state->escontext))
                                              -  - ]
                                333                 :                :                     {
                                334                 :                :                         /* gettoken_tsvector reported a soft error */
  984 tgl@sss.pgh.pa.us         335                 :UBC           0 :                         return PT_ERR;
                                336                 :                :                     }
 6591 tgl@sss.pgh.pa.us         337         [ +  - ]:CBC          12 :                     else if (state->state == WAITFIRSTOPERAND)
                                338                 :                :                     {
 6574 teodor@sigaev.ru          339                 :             12 :                         return PT_END;
                                340                 :                :                     }
                                341                 :                :                     else
  984 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                 :                :                 }
 6591 tgl@sss.pgh.pa.us         347                 :CBC        1466 :                 break;
                                348                 :                : 
                                349                 :           5615 :             case WAITOPERATOR:
 6574 teodor@sigaev.ru          350         [ +  + ]:           5615 :                 if (t_iseq(state->buf, '&'))
                                351                 :                :                 {
 2711                           352                 :            665 :                     state->buf++;
 6574                           353                 :            665 :                     state->state = WAITOPERAND;
                                354                 :            665 :                     *operator = OP_AND;
                                355                 :            665 :                     return PT_OPR;
                                356                 :                :                 }
 3439                           357         [ +  + ]:           4950 :                 else if (t_iseq(state->buf, '|'))
                                358                 :                :                 {
 2711                           359                 :            411 :                     state->buf++;
 6591 tgl@sss.pgh.pa.us         360                 :            411 :                     state->state = WAITOPERAND;
 6574 teodor@sigaev.ru          361                 :            411 :                     *operator = OP_OR;
                                362                 :            411 :                     return PT_OPR;
                                363                 :                :                 }
 2711                           364         [ +  + ]:           4539 :                 else if (parse_phrase_operator(state, weight))
                                365                 :                :                 {
                                366                 :                :                     /* weight var is used as storage for distance */
 3439                           367                 :            867 :                     state->state = WAITOPERAND;
                                368                 :            867 :                     *operator = OP_PHRASE;
                                369                 :            867 :                     return PT_OPR;
                                370                 :                :                 }
  984 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                 :                :                 }
 6591                           376         [ +  + ]:           3669 :                 else if (t_iseq(state->buf, ')'))
                                377                 :                :                 {
 2711 teodor@sigaev.ru          378                 :            531 :                     state->buf++;
 6591 tgl@sss.pgh.pa.us         379                 :            531 :                     state->count--;
 6574 teodor@sigaev.ru          380         [ -  + ]:            531 :                     return (state->count < 0) ? PT_ERR : PT_CLOSE;
                                381                 :                :                 }
 2711                           382         [ +  + ]:           3138 :                 else if (*state->buf == '\0')
                                383                 :                :                 {
 6574                           384                 :           1651 :                     return (state->count) ? PT_ERR : PT_END;
                                385                 :                :                 }
  263 peter@eisentraut.org      386         [ +  + ]:           1487 :                 else if (!isspace((unsigned char) *state->buf))
                                387                 :                :                 {
 6574 teodor@sigaev.ru          388                 :              6 :                     return PT_ERR;
                                389                 :                :                 }
 2711                           390                 :           1481 :                 break;
                                391                 :                :         }
                                392                 :                : 
                                393                 :           2947 :         state->buf += pg_mblen(state->buf);
                                394                 :                :     }
                                395                 :                : }
                                396                 :                : 
                                397                 :                : static ts_tokentype
                                398                 :           1131 : gettoken_query_websearch(TSQueryParserState state, int8 *operator,
                                399                 :                :                          int *lenval, char **strval,
                                400                 :                :                          int16 *weight, bool *prefix)
                                401                 :                : {
                                402                 :           1131 :     *weight = 0;
                                403                 :           1131 :     *prefix = false;
                                404                 :                : 
                                405                 :                :     while (true)
                                406                 :                :     {
                                407      [ +  +  - ]:           1578 :         switch (state->state)
                                408                 :                :         {
                                409                 :            672 :             case WAITFIRSTOPERAND:
                                410                 :                :             case WAITOPERAND:
                                411         [ +  + ]:            672 :                 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         [ +  + ]:            639 :                 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++;
 1587 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                 :                :                 }
 2711 teodor@sigaev.ru          440   [ +  -  +  +  :            543 :                 else if (ISOPERATOR(state->buf))
                                     +  +  +  +  +  
                                        +  +  +  +  
                                                 + ]
                                441                 :                :                 {
                                442                 :                :                     /* ignore, else gettoken_tsvector() will raise an error */
                                443                 :             51 :                     state->buf++;
                                444                 :             51 :                     state->state = WAITOPERAND;
                                445                 :             51 :                     continue;
                                446                 :                :                 }
  263 peter@eisentraut.org      447         [ +  + ]:            492 :                 else if (!isspace((unsigned char) *state->buf))
                                448                 :                :                 {
                                449                 :                :                     /*
                                450                 :                :                      * We rely on the tsvector parser to parse the value for
                                451                 :                :                      * us
                                452                 :                :                      */
 2711 teodor@sigaev.ru          453                 :            453 :                     reset_tsvector_parser(state->valstate, state->buf);
                                454         [ +  - ]:            453 :                     if (gettoken_tsvector(state->valstate, strval, lenval,
                                455                 :                :                                           NULL, NULL, &state->buf))
                                456                 :                :                     {
                                457                 :            453 :                         state->state = WAITOPERATOR;
                                458                 :            453 :                         return PT_VAL;
                                459                 :                :                     }
  984 tgl@sss.pgh.pa.us         460   [ #  #  #  #  :UBC           0 :                     else if (SOFT_ERROR_OCCURRED(state->escontext))
                                              #  # ]
                                461                 :                :                     {
                                462                 :                :                         /* gettoken_tsvector reported a soft error */
                                463                 :              0 :                         return PT_ERR;
                                464                 :                :                     }
 2711 teodor@sigaev.ru          465         [ #  # ]:              0 :                     else if (state->state == WAITFIRSTOPERAND)
                                466                 :                :                     {
                                467                 :              0 :                         return PT_END;
                                468                 :                :                     }
                                469                 :                :                     else
                                470                 :                :                     {
                                471                 :                :                         /* finally, we have to provide an operand */
                                472                 :              0 :                         pushStop(state);
                                473                 :              0 :                         return PT_END;
                                474                 :                :                     }
                                475                 :                :                 }
 6591 tgl@sss.pgh.pa.us         476                 :CBC          39 :                 break;
                                477                 :                : 
 2711 teodor@sigaev.ru          478                 :            906 :             case WAITOPERATOR:
  450 tgl@sss.pgh.pa.us         479         [ +  + ]:            906 :                 if (*state->buf == '\0')
                                480                 :                :                 {
                                481                 :            207 :                     return PT_END;
                                482                 :                :                 }
 2711 teodor@sigaev.ru          483         [ +  + ]:            699 :                 else if (parse_or_operator(state))
                                484                 :                :                 {
                                485                 :             54 :                     state->state = WAITOPERAND;
                                486                 :             54 :                     *operator = OP_OR;
                                487                 :             54 :                     return PT_OPR;
                                488                 :                :                 }
  450 tgl@sss.pgh.pa.us         489   [ +  -  +  +  :            645 :                 else if (ISOPERATOR(state->buf))
                                     +  +  +  +  +  
                                        +  +  +  +  
                                                 + ]
                                490                 :                :                 {
                                491                 :                :                     /* ignore other operators in this state too */
                                492                 :             57 :                     state->buf++;
                                493                 :             57 :                     continue;
                                494                 :                :                 }
  263 peter@eisentraut.org      495         [ +  + ]:            588 :                 else if (!isspace((unsigned char) *state->buf))
                                496                 :                :                 {
                                497                 :                :                     /* insert implicit AND between operands */
 2711 teodor@sigaev.ru          498                 :            288 :                     state->state = WAITOPERAND;
  450 tgl@sss.pgh.pa.us         499                 :            288 :                     *operator = OP_AND;
 2711 teodor@sigaev.ru          500                 :            288 :                     return PT_OPR;
                                501                 :                :                 }
 6591 tgl@sss.pgh.pa.us         502                 :            300 :                 break;
                                503                 :                :         }
                                504                 :                : 
                                505                 :            339 :         state->buf += pg_mblen(state->buf);
                                506                 :                :     }
                                507                 :                : }
                                508                 :                : 
                                509                 :                : static ts_tokentype
 2711 teodor@sigaev.ru          510                 :            108 : gettoken_query_plain(TSQueryParserState state, int8 *operator,
                                511                 :                :                      int *lenval, char **strval,
                                512                 :                :                      int16 *weight, bool *prefix)
                                513                 :                : {
                                514                 :            108 :     *weight = 0;
                                515                 :            108 :     *prefix = false;
                                516                 :                : 
                                517         [ +  + ]:            108 :     if (*state->buf == '\0')
                                518                 :             54 :         return PT_END;
                                519                 :                : 
                                520                 :             54 :     *strval = state->buf;
                                521                 :             54 :     *lenval = strlen(state->buf);
                                522                 :             54 :     state->buf += *lenval;
                                523                 :             54 :     state->count++;
                                524                 :             54 :     return PT_VAL;
                                525                 :                : }
                                526                 :                : 
                                527                 :                : /*
                                528                 :                :  * Push an operator to state->polstr
                                529                 :                :  */
                                530                 :                : void
 3439                           531                 :           3119 : pushOperator(TSQueryParserState state, int8 oper, int16 distance)
                                532                 :                : {
                                533                 :                :     QueryOperator *tmp;
                                534                 :                : 
                                535   [ +  +  +  +  :           3119 :     Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
                                        +  +  -  + ]
                                536                 :                : 
 6357 tgl@sss.pgh.pa.us         537                 :           3119 :     tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
 6574 teodor@sigaev.ru          538                 :           3119 :     tmp->type = QI_OPR;
                                539                 :           3119 :     tmp->oper = oper;
 3439                           540         [ +  + ]:           3119 :     tmp->distance = (oper == OP_PHRASE) ? distance : 0;
                                541                 :                :     /* left is filled in later with findoprnd */
                                542                 :                : 
 6574                           543                 :           3119 :     state->polstr = lcons(tmp, state->polstr);
                                544                 :           3119 : }
                                545                 :                : 
                                546                 :                : static void
 6322 tgl@sss.pgh.pa.us         547                 :           4209 : pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
                                548                 :                : {
                                549                 :                :     QueryOperand *tmp;
                                550                 :                : 
 6591                           551         [ -  + ]:           4209 :     if (distance >= MAXSTRPOS)
  984 tgl@sss.pgh.pa.us         552         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                553                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                554                 :                :                  errmsg("value is too big in tsquery: \"%s\"",
                                555                 :                :                         state->buffer)));
 6591 tgl@sss.pgh.pa.us         556         [ -  + ]:CBC        4209 :     if (lenval >= MAXSTRLEN)
  984 tgl@sss.pgh.pa.us         557         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                558                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                559                 :                :                  errmsg("operand is too long in tsquery: \"%s\"",
                                560                 :                :                         state->buffer)));
                                561                 :                : 
 6357 tgl@sss.pgh.pa.us         562                 :CBC        4209 :     tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
 6574 teodor@sigaev.ru          563                 :           4209 :     tmp->type = QI_VAL;
                                564                 :           4209 :     tmp->weight = weight;
 6322 tgl@sss.pgh.pa.us         565                 :           4209 :     tmp->prefix = prefix;
 6574 teodor@sigaev.ru          566                 :           4209 :     tmp->valcrc = (int32) valcrc;
 6591 tgl@sss.pgh.pa.us         567                 :           4209 :     tmp->length = lenval;
 6574 teodor@sigaev.ru          568                 :           4209 :     tmp->distance = distance;
                                569                 :                : 
                                570                 :           4209 :     state->polstr = lcons(tmp, state->polstr);
                                571                 :                : }
                                572                 :                : 
                                573                 :                : /*
                                574                 :                :  * Push an operand to state->polstr.
                                575                 :                :  *
                                576                 :                :  * strval must point to a string equal to state->curop. lenval is the length
                                577                 :                :  * of the string.
                                578                 :                :  */
                                579                 :                : void
 4821 peter_e@gmx.net           580                 :           4209 : pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
                                581                 :                : {
                                582                 :                :     pg_crc32    valcrc;
                                583                 :                : 
 6591 tgl@sss.pgh.pa.us         584         [ -  + ]:           4209 :     if (lenval >= MAXSTRLEN)
  984 tgl@sss.pgh.pa.us         585         [ #  # ]:UBC           0 :         ereturn(state->escontext,,
                                586                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                587                 :                :                  errmsg("word is too long in tsquery: \"%s\"",
                                588                 :                :                         state->buffer)));
                                589                 :                : 
 3959 heikki.linnakangas@i      590                 :CBC        4209 :     INIT_LEGACY_CRC32(valcrc);
                                591         [ +  + ]:          14856 :     COMP_LEGACY_CRC32(valcrc, strval, lenval);
                                592                 :           4209 :     FIN_LEGACY_CRC32(valcrc);
 6322 tgl@sss.pgh.pa.us         593                 :           4209 :     pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
                                594                 :                : 
                                595                 :                :     /* append the value string to state.op, enlarging buffer if needed first */
 6591                           596         [ -  + ]:           4209 :     while (state->curop - state->op + lenval + 1 >= state->lenop)
                                597                 :                :     {
 6505 bruce@momjian.us          598                 :UBC           0 :         int         used = state->curop - state->op;
                                599                 :                : 
 6591 tgl@sss.pgh.pa.us         600                 :              0 :         state->lenop *= 2;
  942 peter@eisentraut.org      601                 :              0 :         state->op = (char *) repalloc(state->op, state->lenop);
 6574 teodor@sigaev.ru          602                 :              0 :         state->curop = state->op + used;
                                603                 :                :     }
  942 peter@eisentraut.org      604                 :CBC        4209 :     memcpy(state->curop, strval, lenval);
 6591 tgl@sss.pgh.pa.us         605                 :           4209 :     state->curop += lenval;
                                606                 :           4209 :     *(state->curop) = '\0';
                                607                 :           4209 :     state->curop++;
                                608                 :           4209 :     state->sumlen += lenval + 1 /* \0 */ ;
                                609                 :                : }
                                610                 :                : 
                                611                 :                : 
                                612                 :                : /*
                                613                 :                :  * Push a stopword placeholder to state->polstr
                                614                 :                :  */
                                615                 :                : void
 6574 teodor@sigaev.ru          616                 :            333 : pushStop(TSQueryParserState state)
                                617                 :                : {
                                618                 :                :     QueryOperand *tmp;
                                619                 :                : 
 6357 tgl@sss.pgh.pa.us         620                 :            333 :     tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
 6574 teodor@sigaev.ru          621                 :            333 :     tmp->type = QI_VALSTOP;
                                622                 :                : 
                                623                 :            333 :     state->polstr = lcons(tmp, state->polstr);
                                624                 :            333 : }
                                625                 :                : 
                                626                 :                : 
                                627                 :                : #define STACKDEPTH  32
                                628                 :                : 
                                629                 :                : typedef struct OperatorElement
                                630                 :                : {
                                631                 :                :     int8        op;
                                632                 :                :     int16       distance;
                                633                 :                : } OperatorElement;
                                634                 :                : 
                                635                 :                : static void
 3358                           636                 :           2783 : pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
                                637                 :                : {
 3309 tgl@sss.pgh.pa.us         638         [ -  + ]:           2783 :     if (*lenstack == STACKDEPTH)    /* internal error */
 3358 teodor@sigaev.ru          639         [ #  # ]:UBC           0 :         elog(ERROR, "tsquery stack too small");
                                640                 :                : 
 3358 teodor@sigaev.ru          641                 :CBC        2783 :     stack[*lenstack].op = op;
                                642                 :           2783 :     stack[*lenstack].distance = distance;
                                643                 :                : 
                                644                 :           2783 :     (*lenstack)++;
                                645                 :           2783 : }
                                646                 :                : 
                                647                 :                : static void
                                648                 :           5238 : cleanOpStack(TSQueryParserState state,
                                649                 :                :              OperatorElement *stack, int *lenstack, int8 op)
                                650                 :                : {
 3309 tgl@sss.pgh.pa.us         651                 :           5238 :     int         opPriority = OP_PRIORITY(op);
                                652                 :                : 
                                653         [ +  + ]:           8021 :     while (*lenstack)
                                654                 :                :     {
                                655                 :                :         /* NOT is right associative unlike to others */
 3340 teodor@sigaev.ru          656   [ +  +  +  +  :           3026 :         if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
                                              +  + ]
 2999 tgl@sss.pgh.pa.us         657         [ -  + ]:            159 :             (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
                                658                 :                :             break;
                                659                 :                : 
 3358 teodor@sigaev.ru          660                 :           2783 :         (*lenstack)--;
                                661                 :           2783 :         pushOperator(state, stack[*lenstack].op,
 3309 tgl@sss.pgh.pa.us         662                 :           2783 :                      stack[*lenstack].distance);
                                663                 :                :     }
 3358 teodor@sigaev.ru          664                 :           5238 : }
                                665                 :                : 
                                666                 :                : /*
                                667                 :                :  * Make polish (prefix) notation of query.
                                668                 :                :  *
                                669                 :                :  * See parse_tsquery for explanation of pushval.
                                670                 :                :  */
                                671                 :                : static void
 6505 bruce@momjian.us          672                 :           2464 : makepol(TSQueryParserState state,
                                673                 :                :         PushFunction pushval,
                                674                 :                :         Datum opaque)
                                675                 :                : {
 3376 rhaas@postgresql.org      676                 :           2464 :     int8        operator = 0;
                                677                 :                :     ts_tokentype type;
                                678                 :           2464 :     int         lenval = 0;
                                679                 :           2464 :     char       *strval = NULL;
                                680                 :                :     OperatorElement opstack[STACKDEPTH];
                                681                 :           2464 :     int         lenstack = 0;
                                682                 :           2464 :     int16       weight = 0;
                                683                 :                :     bool        prefix;
                                684                 :                : 
                                685                 :                :     /* since this function recurses, it could be driven to stack overflow */
 6581 tgl@sss.pgh.pa.us         686                 :           2464 :     check_stack_depth();
                                687                 :                : 
 2711 teodor@sigaev.ru          688                 :           9984 :     while ((type = state->gettoken(state, &operator,
                                689                 :                :                                    &lenval, &strval,
                                690         [ +  + ]:           9984 :                                    &weight, &prefix)) != PT_END)
                                691                 :                :     {
 6591 tgl@sss.pgh.pa.us         692   [ +  +  +  +  :           8060 :         switch (type)
                                                 + ]
                                693                 :                :         {
 6574 teodor@sigaev.ru          694                 :           4206 :             case PT_VAL:
 6322 tgl@sss.pgh.pa.us         695                 :           4206 :                 pushval(opaque, state, strval, lenval, weight, prefix);
 6591                           696                 :           4206 :                 break;
 6574 teodor@sigaev.ru          697                 :           2783 :             case PT_OPR:
 3358                           698                 :           2783 :                 cleanOpStack(state, opstack, &lenstack, operator);
                                699                 :           2783 :                 pushOpStack(opstack, &lenstack, operator, weight);
 6591 tgl@sss.pgh.pa.us         700                 :           2783 :                 break;
 6574 teodor@sigaev.ru          701                 :            531 :             case PT_OPEN:
                                702                 :            531 :                 makepol(state, pushval, opaque);
 6591 tgl@sss.pgh.pa.us         703                 :            531 :                 break;
 6574 teodor@sigaev.ru          704                 :            531 :             case PT_CLOSE:
 3309 tgl@sss.pgh.pa.us         705                 :            531 :                 cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
 6574 teodor@sigaev.ru          706                 :            540 :                 return;
                                707                 :              9 :             case PT_ERR:
                                708                 :                :             default:
                                709                 :                :                 /* don't overwrite a soft error saved by gettoken function */
  984 tgl@sss.pgh.pa.us         710   [ +  -  +  -  :              9 :                 if (!SOFT_ERROR_OCCURRED(state->escontext))
                                              +  + ]
                                711         [ +  + ]:              6 :                     errsave(state->escontext,
                                712                 :                :                             (errcode(ERRCODE_SYNTAX_ERROR),
                                713                 :                :                              errmsg("syntax error in tsquery: \"%s\"",
                                714                 :                :                                     state->buffer)));
                                715                 :              9 :                 return;
                                716                 :                :         }
                                717                 :                :         /* detect soft error in pushval or recursion */
                                718   [ +  +  +  -  :           7520 :         if (SOFT_ERROR_OCCURRED(state->escontext))
                                              -  + ]
  984 tgl@sss.pgh.pa.us         719                 :UBC           0 :             return;
                                720                 :                :     }
                                721                 :                : 
 3309 tgl@sss.pgh.pa.us         722                 :CBC        1924 :     cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
                                723                 :                : }
                                724                 :                : 
                                725                 :                : static void
 3439 teodor@sigaev.ru          726                 :           7652 : findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
                                727                 :                : {
                                728                 :                :     /* since this function recurses, it could be driven to stack overflow. */
 6574                           729                 :           7652 :     check_stack_depth();
                                730                 :                : 
                                731         [ -  + ]:           7652 :     if (*pos >= nnodes)
 6492 tgl@sss.pgh.pa.us         732         [ #  # ]:UBC           0 :         elog(ERROR, "malformed tsquery: operand not found");
                                733                 :                : 
 3439 teodor@sigaev.ru          734         [ +  + ]:CBC        7652 :     if (ptr[*pos].type == QI_VAL)
                                735                 :                :     {
                                736                 :           4200 :         (*pos)++;
                                737                 :                :     }
                                738         [ +  + ]:           3452 :     else if (ptr[*pos].type == QI_VALSTOP)
                                739                 :                :     {
 3376 rhaas@postgresql.org      740                 :            333 :         *needcleanup = true;    /* we'll have to remove stop words */
 6591 tgl@sss.pgh.pa.us         741                 :            333 :         (*pos)++;
                                742                 :                :     }
                                743                 :                :     else
                                744                 :                :     {
 6574 teodor@sigaev.ru          745         [ -  + ]:           3119 :         Assert(ptr[*pos].type == QI_OPR);
                                746                 :                : 
 5896 peter_e@gmx.net           747         [ +  + ]:           3119 :         if (ptr[*pos].qoperator.oper == OP_NOT)
                                748                 :                :         {
 2999 tgl@sss.pgh.pa.us         749                 :            498 :             ptr[*pos].qoperator.left = 1;   /* fixed offset */
 6574 teodor@sigaev.ru          750                 :            498 :             (*pos)++;
                                751                 :                : 
                                752                 :                :             /* process the only argument */
 3439                           753                 :            498 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                754                 :                :         }
                                755                 :                :         else
                                756                 :                :         {
 3376 rhaas@postgresql.org      757                 :           2621 :             QueryOperator *curitem = &ptr[*pos].qoperator;
 2999 tgl@sss.pgh.pa.us         758                 :           2621 :             int         tmp = *pos; /* save current position */
                                759                 :                : 
 3439 teodor@sigaev.ru          760   [ +  +  +  +  :           2621 :             Assert(curitem->oper == OP_AND ||
                                              -  + ]
                                761                 :                :                    curitem->oper == OP_OR ||
                                762                 :                :                    curitem->oper == OP_PHRASE);
                                763                 :                : 
 6574                           764                 :           2621 :             (*pos)++;
                                765                 :                : 
                                766                 :                :             /* process RIGHT argument */
 3439                           767                 :           2621 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                768                 :                : 
                                769                 :           2621 :             curitem->left = *pos - tmp; /* set LEFT arg's offset */
                                770                 :                : 
                                771                 :                :             /* process LEFT argument */
                                772                 :           2621 :             findoprnd_recurse(ptr, pos, nnodes, needcleanup);
                                773                 :                :         }
                                774                 :                :     }
 6591 tgl@sss.pgh.pa.us         775                 :           7652 : }
                                776                 :                : 
                                777                 :                : 
                                778                 :                : /*
                                779                 :                :  * Fill in the left-fields previously left unfilled.
                                780                 :                :  * The input QueryItems must be in polish (prefix) notation.
                                781                 :                :  * Also, set *needcleanup to true if there are any QI_VALSTOP nodes.
                                782                 :                :  */
                                783                 :                : static void
 3439 teodor@sigaev.ru          784                 :           1912 : findoprnd(QueryItem *ptr, int size, bool *needcleanup)
                                785                 :                : {
                                786                 :                :     uint32      pos;
                                787                 :                : 
                                788                 :           1912 :     *needcleanup = false;
 6574                           789                 :           1912 :     pos = 0;
 3439                           790                 :           1912 :     findoprnd_recurse(ptr, &pos, size, needcleanup);
                                791                 :                : 
 6574                           792         [ -  + ]:           1912 :     if (pos != size)
 6492 tgl@sss.pgh.pa.us         793         [ #  # ]:UBC           0 :         elog(ERROR, "malformed tsquery: extra nodes");
 6574 teodor@sigaev.ru          794                 :CBC        1912 : }
                                795                 :                : 
                                796                 :                : 
                                797                 :                : /*
                                798                 :                :  * Parse the tsquery stored in "buf".
                                799                 :                :  *
                                800                 :                :  * Each value (operand) in the query is passed to pushval. pushval can
                                801                 :                :  * transform the simple value to an arbitrarily complex expression using
                                802                 :                :  * pushValue and pushOperator. It must push a single value with pushValue,
                                803                 :                :  * a complete expression with all operands, or a stopword placeholder
                                804                 :                :  * with pushStop, otherwise the prefix notation representation will be broken,
                                805                 :                :  * having an operator with no operand.
                                806                 :                :  *
                                807                 :                :  * opaque is passed on to pushval as is, pushval can use it to store its
                                808                 :                :  * private state.
                                809                 :                :  *
                                810                 :                :  * The pushval function can record soft errors via escontext.
                                811                 :                :  * Callers must check SOFT_ERROR_OCCURRED to detect that.
                                812                 :                :  *
                                813                 :                :  * A bitmask of flags (see ts_utils.h) and an error context object
                                814                 :                :  * can be provided as well.  If a soft error occurs, NULL is returned.
                                815                 :                :  */
                                816                 :                : TSQuery
 6505 bruce@momjian.us          817                 :           1933 : parse_tsquery(char *buf,
                                818                 :                :               PushFunction pushval,
                                819                 :                :               Datum opaque,
                                820                 :                :               int flags,
                                821                 :                :               Node *escontext)
                                822                 :                : {
                                823                 :                :     struct TSQueryParserStateData state;
                                824                 :                :     int         i;
                                825                 :                :     TSQuery     query;
                                826                 :                :     int         commonlen;
                                827                 :                :     QueryItem  *ptr;
                                828                 :                :     ListCell   *cell;
                                829                 :                :     bool        noisy;
                                830                 :                :     bool        needcleanup;
 2711 teodor@sigaev.ru          831                 :           1933 :     int         tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
                                832                 :                : 
                                833                 :                :     /* plain should not be used with web */
                                834         [ -  + ]:           1933 :     Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
                                835                 :                : 
                                836                 :                :     /* select suitable tokenizer */
                                837         [ +  + ]:           1933 :     if (flags & P_TSQ_PLAIN)
                                838                 :             54 :         state.gettoken = gettoken_query_plain;
                                839         [ +  + ]:           1879 :     else if (flags & P_TSQ_WEB)
                                840                 :                :     {
                                841                 :            207 :         state.gettoken = gettoken_query_websearch;
                                842                 :            207 :         tsv_flags |= P_TSV_IS_WEB;
                                843                 :                :     }
                                844                 :                :     else
                                845                 :           1672 :         state.gettoken = gettoken_query_standard;
                                846                 :                : 
                                847                 :                :     /* emit nuisance NOTICEs only if not doing soft errors */
  984 tgl@sss.pgh.pa.us         848   [ +  +  -  + ]:           1933 :     noisy = !(escontext && IsA(escontext, ErrorSaveContext));
                                849                 :                : 
                                850                 :                :     /* init state */
 6591                           851                 :           1933 :     state.buffer = buf;
                                852                 :           1933 :     state.buf = buf;
                                853                 :           1933 :     state.count = 0;
 2711 teodor@sigaev.ru          854                 :           1933 :     state.state = WAITFIRSTOPERAND;
 6574                           855                 :           1933 :     state.polstr = NIL;
  984 tgl@sss.pgh.pa.us         856                 :           1933 :     state.escontext = escontext;
                                857                 :                : 
                                858                 :                :     /* init value parser's state */
                                859                 :           1933 :     state.valstate = init_tsvector_parser(state.buffer, tsv_flags, escontext);
                                860                 :                : 
                                861                 :                :     /* init list of operand */
 6591                           862                 :           1933 :     state.sumlen = 0;
                                863                 :           1933 :     state.lenop = 64;
                                864                 :           1933 :     state.curop = state.op = (char *) palloc(state.lenop);
                                865                 :           1933 :     *(state.curop) = '\0';
                                866                 :                : 
                                867                 :                :     /* parse query & make polish notation (postfix, but in reverse order) */
 6574 teodor@sigaev.ru          868                 :           1933 :     makepol(&state, pushval, opaque);
                                869                 :                : 
                                870                 :           1933 :     close_tsvector_parser(state.valstate);
                                871                 :                : 
  984 tgl@sss.pgh.pa.us         872   [ +  +  +  -  :           1933 :     if (SOFT_ERROR_OCCURRED(escontext))
                                              +  + ]
                                873                 :              9 :         return NULL;
                                874                 :                : 
 1116                           875         [ +  + ]:           1924 :     if (state.polstr == NIL)
                                876                 :                :     {
  984                           877         [ +  - ]:             12 :         if (noisy)
                                878         [ +  - ]:             12 :             ereport(NOTICE,
                                879                 :                :                     (errmsg("text-search query doesn't contain lexemes: \"%s\"",
                                880                 :                :                             state.buffer)));
 6591                           881                 :             12 :         query = (TSQuery) palloc(HDRSIZETQ);
                                882                 :             12 :         SET_VARSIZE(query, HDRSIZETQ);
                                883                 :             12 :         query->size = 0;
                                884                 :             12 :         return query;
                                885                 :                :     }
                                886                 :                : 
 4219 noah@leadboat.com         887         [ -  + ]:           1912 :     if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
  984 tgl@sss.pgh.pa.us         888         [ #  # ]:UBC           0 :         ereturn(escontext, NULL,
                                889                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                890                 :                :                  errmsg("tsquery is too large")));
 6574 teodor@sigaev.ru          891                 :CBC        1912 :     commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
                                892                 :                : 
                                893                 :                :     /* Pack the QueryItems in the final TSQuery struct to return to caller */
                                894                 :           1912 :     query = (TSQuery) palloc0(commonlen);
 6591 tgl@sss.pgh.pa.us         895                 :           1912 :     SET_VARSIZE(query, commonlen);
 6574 teodor@sigaev.ru          896                 :           1912 :     query->size = list_length(state.polstr);
 6591 tgl@sss.pgh.pa.us         897                 :           1912 :     ptr = GETQUERY(query);
                                898                 :                : 
                                899                 :                :     /* Copy QueryItems to TSQuery */
 6574 teodor@sigaev.ru          900                 :           1912 :     i = 0;
                                901   [ +  -  +  +  :           9564 :     foreach(cell, state.polstr)
                                              +  + ]
                                902                 :                :     {
 3376 rhaas@postgresql.org      903                 :           7652 :         QueryItem  *item = (QueryItem *) lfirst(cell);
                                904                 :                : 
 6505 bruce@momjian.us          905   [ +  +  +  - ]:           7652 :         switch (item->type)
                                906                 :                :         {
 6574 teodor@sigaev.ru          907                 :           4200 :             case QI_VAL:
                                908                 :           4200 :                 memcpy(&ptr[i], item, sizeof(QueryOperand));
                                909                 :           4200 :                 break;
                                910                 :            333 :             case QI_VALSTOP:
                                911                 :            333 :                 ptr[i].type = QI_VALSTOP;
                                912                 :            333 :                 break;
                                913                 :           3119 :             case QI_OPR:
                                914                 :           3119 :                 memcpy(&ptr[i], item, sizeof(QueryOperator));
                                915                 :           3119 :                 break;
 6574 teodor@sigaev.ru          916                 :UBC           0 :             default:
 6492 tgl@sss.pgh.pa.us         917         [ #  # ]:              0 :                 elog(ERROR, "unrecognized QueryItem type: %d", item->type);
                                918                 :                :         }
 6574 teodor@sigaev.ru          919                 :CBC        7652 :         i++;
                                920                 :                :     }
                                921                 :                : 
                                922                 :                :     /* Copy all the operand strings to TSQuery */
  942 peter@eisentraut.org      923                 :           1912 :     memcpy(GETOPERAND(query), state.op, state.sumlen);
 6591 tgl@sss.pgh.pa.us         924                 :           1912 :     pfree(state.op);
                                925                 :                : 
                                926                 :                :     /*
                                927                 :                :      * Set left operand pointers for every operator.  While we're at it,
                                928                 :                :      * detect whether there are any QI_VALSTOP nodes.
                                929                 :                :      */
 3439 teodor@sigaev.ru          930                 :           1912 :     findoprnd(ptr, query->size, &needcleanup);
                                931                 :                : 
                                932                 :                :     /*
                                933                 :                :      * If there are QI_VALSTOP nodes, delete them and simplify the tree.
                                934                 :                :      */
                                935         [ +  + ]:           1912 :     if (needcleanup)
  984 tgl@sss.pgh.pa.us         936                 :            216 :         query = cleanup_tsquery_stopwords(query, noisy);
                                937                 :                : 
 6591                           938                 :           1912 :     return query;
                                939                 :                : }
                                940                 :                : 
                                941                 :                : static void
 6571 teodor@sigaev.ru          942                 :           2650 : pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval,
                                943                 :                :              int16 weight, bool prefix)
                                944                 :                : {
 6322 tgl@sss.pgh.pa.us         945                 :           2650 :     pushValue(state, strval, lenval, weight, prefix);
 6574 teodor@sigaev.ru          946                 :           2650 : }
                                947                 :                : 
                                948                 :                : /*
                                949                 :                :  * in without morphology
                                950                 :                :  */
                                951                 :                : Datum
 6591 tgl@sss.pgh.pa.us         952                 :           1295 : tsqueryin(PG_FUNCTION_ARGS)
                                953                 :                : {
                                954                 :           1295 :     char       *in = PG_GETARG_CSTRING(0);
  984                           955                 :           1295 :     Node       *escontext = fcinfo->context;
                                956                 :                : 
                                957                 :           1295 :     PG_RETURN_TSQUERY(parse_tsquery(in,
                                958                 :                :                                     pushval_asis,
                                959                 :                :                                     PointerGetDatum(NULL),
                                960                 :                :                                     0,
                                961                 :                :                                     escontext));
                                962                 :                : }
                                963                 :                : 
                                964                 :                : /*
                                965                 :                :  * out function
                                966                 :                :  */
                                967                 :                : typedef struct
                                968                 :                : {
                                969                 :                :     QueryItem  *curpol;
                                970                 :                :     char       *buf;
                                971                 :                :     char       *cur;
                                972                 :                :     char       *op;
                                973                 :                :     int         buflen;
                                974                 :                : } INFIX;
                                975                 :                : 
                                976                 :                : /* Makes sure inf->buf is large enough for adding 'addsize' bytes */
                                977                 :                : #define RESIZEBUF(inf, addsize) \
                                978                 :                : while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
                                979                 :                : { \
                                980                 :                :     int len = (inf)->cur - (inf)->buf; \
                                981                 :                :     (inf)->buflen *= 2; \
                                982                 :                :     (inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
                                983                 :                :     (inf)->cur = (inf)->buf + len; \
                                984                 :                : }
                                985                 :                : 
                                986                 :                : /*
                                987                 :                :  * recursively traverse the tree and
                                988                 :                :  * print it in infix (human-readable) form
                                989                 :                :  */
                                990                 :                : static void
 3358 teodor@sigaev.ru          991                 :           3644 : infix(INFIX *in, int parentPriority, bool rightPhraseOp)
                                992                 :                : {
                                993                 :                :     /* since this function recurses, it could be driven to stack overflow. */
 6574                           994                 :           3644 :     check_stack_depth();
                                995                 :                : 
                                996         [ +  + ]:           3644 :     if (in->curpol->type == QI_VAL)
                                997                 :                :     {
 5896 peter_e@gmx.net           998                 :           2108 :         QueryOperand *curpol = &in->curpol->qoperand;
 6574 teodor@sigaev.ru          999                 :           2108 :         char       *op = in->op + curpol->distance;
                               1000                 :                :         int         clen;
                               1001                 :                : 
 6322 tgl@sss.pgh.pa.us        1002         [ +  + ]:           3441 :         RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
 6591                          1003                 :           2108 :         *(in->cur) = '\'';
                               1004                 :           2108 :         in->cur++;
                               1005         [ +  + ]:           8182 :         while (*op)
                               1006                 :                :         {
                               1007         [ +  + ]:           6074 :             if (t_iseq(op, '\''))
                               1008                 :                :             {
                               1009                 :              6 :                 *(in->cur) = '\'';
                               1010                 :              6 :                 in->cur++;
                               1011                 :                :             }
 6504 teodor@sigaev.ru         1012         [ +  + ]:           6068 :             else if (t_iseq(op, '\\'))
                               1013                 :                :             {
                               1014                 :              3 :                 *(in->cur) = '\\';
                               1015                 :              3 :                 in->cur++;
                               1016                 :                :             }
 6591 tgl@sss.pgh.pa.us        1017                 :           6074 :             COPYCHAR(in->cur, op);
                               1018                 :                : 
                               1019                 :           6074 :             clen = pg_mblen(op);
                               1020                 :           6074 :             op += clen;
                               1021                 :           6074 :             in->cur += clen;
                               1022                 :                :         }
                               1023                 :           2108 :         *(in->cur) = '\'';
                               1024                 :           2108 :         in->cur++;
 6322                          1025   [ +  +  +  + ]:           2108 :         if (curpol->weight || curpol->prefix)
                               1026                 :                :         {
 6591                          1027                 :             87 :             *(in->cur) = ':';
                               1028                 :             87 :             in->cur++;
 5931 bruce@momjian.us         1029         [ +  + ]:             87 :             if (curpol->prefix)
                               1030                 :                :             {
 6322 tgl@sss.pgh.pa.us        1031                 :             12 :                 *(in->cur) = '*';
                               1032                 :             12 :                 in->cur++;
                               1033                 :                :             }
 6574 teodor@sigaev.ru         1034         [ +  + ]:             87 :             if (curpol->weight & (1 << 3))
                               1035                 :                :             {
 6591 tgl@sss.pgh.pa.us        1036                 :             30 :                 *(in->cur) = 'A';
                               1037                 :             30 :                 in->cur++;
                               1038                 :                :             }
 6574 teodor@sigaev.ru         1039         [ +  + ]:             87 :             if (curpol->weight & (1 << 2))
                               1040                 :                :             {
 6591 tgl@sss.pgh.pa.us        1041                 :             48 :                 *(in->cur) = 'B';
                               1042                 :             48 :                 in->cur++;
                               1043                 :                :             }
 6574 teodor@sigaev.ru         1044         [ +  + ]:             87 :             if (curpol->weight & (1 << 1))
                               1045                 :                :             {
 6591 tgl@sss.pgh.pa.us        1046                 :              9 :                 *(in->cur) = 'C';
                               1047                 :              9 :                 in->cur++;
                               1048                 :                :             }
 6574 teodor@sigaev.ru         1049         [ +  + ]:             87 :             if (curpol->weight & 1)
                               1050                 :                :             {
 6591 tgl@sss.pgh.pa.us        1051                 :              3 :                 *(in->cur) = 'D';
                               1052                 :              3 :                 in->cur++;
                               1053                 :                :             }
                               1054                 :                :         }
                               1055                 :           2108 :         *(in->cur) = '\0';
                               1056                 :           2108 :         in->curpol++;
                               1057                 :                :     }
 5896 peter_e@gmx.net          1058         [ +  + ]:           1536 :     else if (in->curpol->qoperator.oper == OP_NOT)
                               1059                 :                :     {
 3358 teodor@sigaev.ru         1060                 :            186 :         int         priority = QO_PRIORITY(in->curpol);
                               1061                 :                : 
 3439                          1062         [ -  + ]:            186 :         if (priority < parentPriority)
                               1063                 :                :         {
 6591 tgl@sss.pgh.pa.us        1064         [ #  # ]:UBC           0 :             RESIZEBUF(in, 2);
                               1065                 :              0 :             sprintf(in->cur, "( ");
                               1066                 :              0 :             in->cur = strchr(in->cur, '\0');
                               1067                 :                :         }
 3439 teodor@sigaev.ru         1068         [ -  + ]:CBC         186 :         RESIZEBUF(in, 1);
                               1069                 :            186 :         *(in->cur) = '!';
                               1070                 :            186 :         in->cur++;
                               1071                 :            186 :         *(in->cur) = '\0';
                               1072                 :            186 :         in->curpol++;
                               1073                 :                : 
 3358                          1074                 :            186 :         infix(in, priority, false);
 3439                          1075         [ -  + ]:            186 :         if (priority < parentPriority)
                               1076                 :                :         {
 6591 tgl@sss.pgh.pa.us        1077         [ #  # ]:UBC           0 :             RESIZEBUF(in, 2);
                               1078                 :              0 :             sprintf(in->cur, " )");
                               1079                 :              0 :             in->cur = strchr(in->cur, '\0');
                               1080                 :                :         }
                               1081                 :                :     }
                               1082                 :                :     else
                               1083                 :                :     {
 5896 peter_e@gmx.net          1084                 :CBC        1350 :         int8        op = in->curpol->qoperator.oper;
 3358 teodor@sigaev.ru         1085                 :           1350 :         int         priority = QO_PRIORITY(in->curpol);
 3439                          1086                 :           1350 :         int16       distance = in->curpol->qoperator.distance;
                               1087                 :                :         INFIX       nrm;
                               1088                 :           1350 :         bool        needParenthesis = false;
                               1089                 :                : 
 6591 tgl@sss.pgh.pa.us        1090                 :           1350 :         in->curpol++;
 3439 teodor@sigaev.ru         1091   [ +  +  +  + ]:           1350 :         if (priority < parentPriority ||
                               1092                 :                :         /* phrase operator depends on order */
 3309 tgl@sss.pgh.pa.us        1093         [ +  + ]:            360 :             (op == OP_PHRASE && rightPhraseOp))
                               1094                 :                :         {
 3439 teodor@sigaev.ru         1095                 :            166 :             needParenthesis = true;
 6591 tgl@sss.pgh.pa.us        1096         [ -  + ]:            166 :             RESIZEBUF(in, 2);
                               1097                 :            166 :             sprintf(in->cur, "( ");
                               1098                 :            166 :             in->cur = strchr(in->cur, '\0');
                               1099                 :                :         }
                               1100                 :                : 
                               1101                 :           1350 :         nrm.curpol = in->curpol;
                               1102                 :           1350 :         nrm.op = in->op;
                               1103                 :           1350 :         nrm.buflen = 16;
                               1104                 :           1350 :         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1105                 :                : 
                               1106                 :                :         /* get right operand */
 3358 teodor@sigaev.ru         1107                 :           1350 :         infix(&nrm, priority, (op == OP_PHRASE));
                               1108                 :                : 
                               1109                 :                :         /* get & print left operand */
 6591 tgl@sss.pgh.pa.us        1110                 :           1350 :         in->curpol = nrm.curpol;
 3358 teodor@sigaev.ru         1111                 :           1350 :         infix(in, priority, false);
                               1112                 :                : 
                               1113                 :                :         /* print operator & right operand */
 3376 rhaas@postgresql.org     1114         [ +  + ]:           1840 :         RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
 6505 bruce@momjian.us         1115   [ +  +  +  - ]:           1350 :         switch (op)
                               1116                 :                :         {
 6574 teodor@sigaev.ru         1117                 :            366 :             case OP_OR:
                               1118                 :            366 :                 sprintf(in->cur, " | %s", nrm.buf);
                               1119                 :            366 :                 break;
                               1120                 :            618 :             case OP_AND:
                               1121                 :            618 :                 sprintf(in->cur, " & %s", nrm.buf);
                               1122                 :            618 :                 break;
 3439                          1123                 :            366 :             case OP_PHRASE:
                               1124         [ +  + ]:            366 :                 if (distance != 1)
                               1125                 :             87 :                     sprintf(in->cur, " <%d> %s", distance, nrm.buf);
                               1126                 :                :                 else
                               1127                 :            279 :                     sprintf(in->cur, " <-> %s", nrm.buf);
                               1128                 :            366 :                 break;
 6574 teodor@sigaev.ru         1129                 :UBC           0 :             default:
                               1130                 :                :                 /* OP_NOT is handled in above if-branch */
 6492 tgl@sss.pgh.pa.us        1131         [ #  # ]:              0 :                 elog(ERROR, "unrecognized operator type: %d", op);
                               1132                 :                :         }
 6591 tgl@sss.pgh.pa.us        1133                 :CBC        1350 :         in->cur = strchr(in->cur, '\0');
                               1134                 :           1350 :         pfree(nrm.buf);
                               1135                 :                : 
 3439 teodor@sigaev.ru         1136         [ +  + ]:           1350 :         if (needParenthesis)
                               1137                 :                :         {
 6591 tgl@sss.pgh.pa.us        1138         [ -  + ]:            166 :             RESIZEBUF(in, 2);
                               1139                 :            166 :             sprintf(in->cur, " )");
                               1140                 :            166 :             in->cur = strchr(in->cur, '\0');
                               1141                 :                :         }
                               1142                 :                :     }
                               1143                 :           3644 : }
                               1144                 :                : 
                               1145                 :                : Datum
                               1146                 :            773 : tsqueryout(PG_FUNCTION_ARGS)
                               1147                 :                : {
                               1148                 :            773 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1149                 :                :     INFIX       nrm;
                               1150                 :                : 
                               1151         [ +  + ]:            773 :     if (query->size == 0)
                               1152                 :                :     {
                               1153                 :             15 :         char       *b = palloc(1);
                               1154                 :                : 
                               1155                 :             15 :         *b = '\0';
                               1156                 :             15 :         PG_RETURN_POINTER(b);
                               1157                 :                :     }
                               1158                 :            758 :     nrm.curpol = GETQUERY(query);
                               1159                 :            758 :     nrm.buflen = 32;
                               1160                 :            758 :     nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1161                 :            758 :     *(nrm.cur) = '\0';
                               1162                 :            758 :     nrm.op = GETOPERAND(query);
 3309                          1163                 :            758 :     infix(&nrm, -1 /* lowest priority */ , false);
                               1164                 :                : 
 6591                          1165         [ -  + ]:            758 :     PG_FREE_IF_COPY(query, 0);
                               1166                 :            758 :     PG_RETURN_CSTRING(nrm.buf);
                               1167                 :                : }
                               1168                 :                : 
                               1169                 :                : /*
                               1170                 :                :  * Binary Input / Output functions. The binary format is as follows:
                               1171                 :                :  *
                               1172                 :                :  * uint32    number of operators/operands in the query
                               1173                 :                :  *
                               1174                 :                :  * Followed by the operators and operands, in prefix notation. For each
                               1175                 :                :  * operand:
                               1176                 :                :  *
                               1177                 :                :  * uint8    type, QI_VAL
                               1178                 :                :  * uint8    weight
                               1179                 :                :  * uint8    prefix
                               1180                 :                :  *          operand text in client encoding, null-terminated
                               1181                 :                :  *
                               1182                 :                :  * For each operator:
                               1183                 :                :  *
                               1184                 :                :  * uint8    type, QI_OPR
                               1185                 :                :  * uint8    operator, one of OP_AND, OP_PHRASE OP_OR, OP_NOT.
                               1186                 :                :  * uint16   distance (only for OP_PHRASE)
                               1187                 :                :  */
                               1188                 :                : Datum
 6591 tgl@sss.pgh.pa.us        1189                 :UBC           0 : tsquerysend(PG_FUNCTION_ARGS)
                               1190                 :                : {
                               1191                 :              0 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1192                 :                :     StringInfoData buf;
                               1193                 :                :     int         i;
                               1194                 :              0 :     QueryItem  *item = GETQUERY(query);
                               1195                 :                : 
                               1196                 :              0 :     pq_begintypsend(&buf);
                               1197                 :                : 
 2887 andres@anarazel.de       1198                 :              0 :     pq_sendint32(&buf, query->size);
 6591 tgl@sss.pgh.pa.us        1199         [ #  # ]:              0 :     for (i = 0; i < query->size; i++)
                               1200                 :                :     {
 2887 andres@anarazel.de       1201                 :              0 :         pq_sendint8(&buf, item->type);
                               1202                 :                : 
 6505 bruce@momjian.us         1203      [ #  #  # ]:              0 :         switch (item->type)
                               1204                 :                :         {
 6574 teodor@sigaev.ru         1205                 :              0 :             case QI_VAL:
 2887 andres@anarazel.de       1206                 :              0 :                 pq_sendint8(&buf, item->qoperand.weight);
                               1207                 :              0 :                 pq_sendint8(&buf, item->qoperand.prefix);
 5896 peter_e@gmx.net          1208                 :              0 :                 pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
 6574 teodor@sigaev.ru         1209                 :              0 :                 break;
                               1210                 :              0 :             case QI_OPR:
 2887 andres@anarazel.de       1211                 :              0 :                 pq_sendint8(&buf, item->qoperator.oper);
 3439 teodor@sigaev.ru         1212         [ #  # ]:              0 :                 if (item->qoperator.oper == OP_PHRASE)
 2887 andres@anarazel.de       1213                 :              0 :                     pq_sendint16(&buf, item->qoperator.distance);
 6574 teodor@sigaev.ru         1214                 :              0 :                 break;
                               1215                 :              0 :             default:
 6492 tgl@sss.pgh.pa.us        1216         [ #  # ]:              0 :                 elog(ERROR, "unrecognized tsquery node type: %d", item->type);
                               1217                 :                :         }
 6591                          1218                 :              0 :         item++;
                               1219                 :                :     }
                               1220                 :                : 
                               1221         [ #  # ]:              0 :     PG_FREE_IF_COPY(query, 0);
                               1222                 :                : 
                               1223                 :              0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                               1224                 :                : }
                               1225                 :                : 
                               1226                 :                : Datum
                               1227                 :              0 : tsqueryrecv(PG_FUNCTION_ARGS)
                               1228                 :                : {
 3376 rhaas@postgresql.org     1229                 :              0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                               1230                 :                :     TSQuery     query;
                               1231                 :                :     int         i,
                               1232                 :                :                 len;
                               1233                 :                :     QueryItem  *item;
                               1234                 :                :     int         datalen;
                               1235                 :                :     char       *ptr;
                               1236                 :                :     uint32      size;
                               1237                 :                :     const char **operands;
                               1238                 :                :     bool        needcleanup;
                               1239                 :                : 
 6591 tgl@sss.pgh.pa.us        1240                 :              0 :     size = pq_getmsgint(buf, sizeof(uint32));
 6574 teodor@sigaev.ru         1241         [ #  # ]:              0 :     if (size > (MaxAllocSize / sizeof(QueryItem)))
 6591 tgl@sss.pgh.pa.us        1242         [ #  # ]:              0 :         elog(ERROR, "invalid size of tsquery");
                               1243                 :                : 
                               1244                 :                :     /* Allocate space to temporarily hold operand strings */
 6574 teodor@sigaev.ru         1245                 :              0 :     operands = palloc(size * sizeof(char *));
                               1246                 :                : 
                               1247                 :                :     /* Allocate space for all the QueryItems. */
                               1248                 :              0 :     len = HDRSIZETQ + sizeof(QueryItem) * size;
                               1249                 :              0 :     query = (TSQuery) palloc0(len);
 6591 tgl@sss.pgh.pa.us        1250                 :              0 :     query->size = size;
                               1251                 :              0 :     item = GETQUERY(query);
                               1252                 :                : 
 6574 teodor@sigaev.ru         1253                 :              0 :     datalen = 0;
 6591 tgl@sss.pgh.pa.us        1254         [ #  # ]:              0 :     for (i = 0; i < size; i++)
                               1255                 :                :     {
                               1256                 :              0 :         item->type = (int8) pq_getmsgint(buf, sizeof(int8));
                               1257                 :                : 
 6574 teodor@sigaev.ru         1258         [ #  # ]:              0 :         if (item->type == QI_VAL)
                               1259                 :                :         {
                               1260                 :                :             size_t      val_len;    /* length after recoding to server
                               1261                 :                :                                      * encoding */
                               1262                 :                :             uint8       weight;
                               1263                 :                :             uint8       prefix;
                               1264                 :                :             const char *val;
                               1265                 :                :             pg_crc32    valcrc;
                               1266                 :                : 
 6505 bruce@momjian.us         1267                 :              0 :             weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
 6322 tgl@sss.pgh.pa.us        1268                 :              0 :             prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
 6574 teodor@sigaev.ru         1269                 :              0 :             val = pq_getmsgstring(buf);
                               1270                 :              0 :             val_len = strlen(val);
                               1271                 :                : 
                               1272                 :                :             /* Sanity checks */
                               1273                 :                : 
                               1274         [ #  # ]:              0 :             if (weight > 0xF)
 6492 tgl@sss.pgh.pa.us        1275         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: invalid weight bitmap");
                               1276                 :                : 
 6574 teodor@sigaev.ru         1277         [ #  # ]:              0 :             if (val_len > MAXSTRLEN)
 6492 tgl@sss.pgh.pa.us        1278         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: operand too long");
                               1279                 :                : 
 6574 teodor@sigaev.ru         1280         [ #  # ]:              0 :             if (datalen > MAXSTRPOS)
 6492 tgl@sss.pgh.pa.us        1281         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: total operand length exceeded");
                               1282                 :                : 
                               1283                 :                :             /* Looks valid. */
                               1284                 :                : 
 3959 heikki.linnakangas@i     1285                 :              0 :             INIT_LEGACY_CRC32(valcrc);
                               1286         [ #  # ]:              0 :             COMP_LEGACY_CRC32(valcrc, val, val_len);
                               1287                 :              0 :             FIN_LEGACY_CRC32(valcrc);
                               1288                 :                : 
 5896 peter_e@gmx.net          1289                 :              0 :             item->qoperand.weight = weight;
                               1290                 :              0 :             item->qoperand.prefix = (prefix) ? true : false;
                               1291                 :              0 :             item->qoperand.valcrc = (int32) valcrc;
                               1292                 :              0 :             item->qoperand.length = val_len;
                               1293                 :              0 :             item->qoperand.distance = datalen;
                               1294                 :                : 
                               1295                 :                :             /*
                               1296                 :                :              * Operand strings are copied to the final struct after this loop;
                               1297                 :                :              * here we just collect them to an array
                               1298                 :                :              */
 6574 teodor@sigaev.ru         1299                 :              0 :             operands[i] = val;
                               1300                 :                : 
 2999 tgl@sss.pgh.pa.us        1301                 :              0 :             datalen += val_len + 1; /* + 1 for the '\0' terminator */
                               1302                 :                :         }
 6574 teodor@sigaev.ru         1303         [ #  # ]:              0 :         else if (item->type == QI_OPR)
                               1304                 :                :         {
                               1305                 :                :             int8        oper;
                               1306                 :                : 
                               1307                 :              0 :             oper = (int8) pq_getmsgint(buf, sizeof(int8));
 3439                          1308   [ #  #  #  #  :              0 :             if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
                                        #  #  #  # ]
 6492 tgl@sss.pgh.pa.us        1309         [ #  # ]:              0 :                 elog(ERROR, "invalid tsquery: unrecognized operator type %d",
                               1310                 :                :                      (int) oper);
 6574 teodor@sigaev.ru         1311         [ #  # ]:              0 :             if (i == size - 1)
                               1312         [ #  # ]:              0 :                 elog(ERROR, "invalid pointer to right operand");
                               1313                 :                : 
 5896 peter_e@gmx.net          1314                 :              0 :             item->qoperator.oper = oper;
 3439 teodor@sigaev.ru         1315         [ #  # ]:              0 :             if (oper == OP_PHRASE)
                               1316                 :              0 :                 item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
                               1317                 :                :         }
                               1318                 :                :         else
 6492 tgl@sss.pgh.pa.us        1319         [ #  # ]:              0 :             elog(ERROR, "unrecognized tsquery node type: %d", item->type);
                               1320                 :                : 
 6591                          1321                 :              0 :         item++;
                               1322                 :                :     }
                               1323                 :                : 
                               1324                 :                :     /* Enlarge buffer to make room for the operand values. */
                               1325                 :              0 :     query = (TSQuery) repalloc(query, len + datalen);
                               1326                 :              0 :     item = GETQUERY(query);
                               1327                 :              0 :     ptr = GETOPERAND(query);
                               1328                 :                : 
                               1329                 :                :     /*
                               1330                 :                :      * Fill in the left-pointers. Checks that the tree is well-formed as a
                               1331                 :                :      * side-effect.
                               1332                 :                :      */
 3439 teodor@sigaev.ru         1333                 :              0 :     findoprnd(item, size, &needcleanup);
                               1334                 :                : 
                               1335                 :                :     /* Can't have found any QI_VALSTOP nodes */
 3181 tgl@sss.pgh.pa.us        1336         [ #  # ]:              0 :     Assert(!needcleanup);
                               1337                 :                : 
                               1338                 :                :     /* Copy operands to output struct */
 6591                          1339         [ #  # ]:              0 :     for (i = 0; i < size; i++)
                               1340                 :                :     {
 6574 teodor@sigaev.ru         1341         [ #  # ]:              0 :         if (item->type == QI_VAL)
                               1342                 :                :         {
 5896 peter_e@gmx.net          1343                 :              0 :             memcpy(ptr, operands[i], item->qoperand.length + 1);
                               1344                 :              0 :             ptr += item->qoperand.length + 1;
                               1345                 :                :         }
 6591 tgl@sss.pgh.pa.us        1346                 :              0 :         item++;
                               1347                 :                :     }
                               1348                 :                : 
 6574 teodor@sigaev.ru         1349                 :              0 :     pfree(operands);
                               1350                 :                : 
 6591 tgl@sss.pgh.pa.us        1351         [ #  # ]:              0 :     Assert(ptr - GETOPERAND(query) == datalen);
                               1352                 :                : 
                               1353                 :              0 :     SET_VARSIZE(query, len + datalen);
                               1354                 :                : 
 3439 teodor@sigaev.ru         1355                 :              0 :     PG_RETURN_TSQUERY(query);
                               1356                 :                : }
                               1357                 :                : 
                               1358                 :                : /*
                               1359                 :                :  * debug function, used only for view query
                               1360                 :                :  * which will be executed in non-leaf pages in index
                               1361                 :                :  */
                               1362                 :                : Datum
 6591 tgl@sss.pgh.pa.us        1363                 :              0 : tsquerytree(PG_FUNCTION_ARGS)
                               1364                 :                : {
                               1365                 :              0 :     TSQuery     query = PG_GETARG_TSQUERY(0);
                               1366                 :                :     INFIX       nrm;
                               1367                 :                :     text       *res;
                               1368                 :                :     QueryItem  *q;
                               1369                 :                :     int         len;
                               1370                 :                : 
                               1371         [ #  # ]:              0 :     if (query->size == 0)
                               1372                 :                :     {
                               1373                 :              0 :         res = (text *) palloc(VARHDRSZ);
                               1374                 :              0 :         SET_VARSIZE(res, VARHDRSZ);
                               1375                 :              0 :         PG_RETURN_POINTER(res);
                               1376                 :                :     }
                               1377                 :                : 
                               1378                 :              0 :     q = clean_NOT(GETQUERY(query), &len);
                               1379                 :                : 
                               1380         [ #  # ]:              0 :     if (!q)
                               1381                 :                :     {
 6374                          1382                 :              0 :         res = cstring_to_text("T");
                               1383                 :                :     }
                               1384                 :                :     else
                               1385                 :                :     {
 6591                          1386                 :              0 :         nrm.curpol = q;
                               1387                 :              0 :         nrm.buflen = 32;
                               1388                 :              0 :         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
                               1389                 :              0 :         *(nrm.cur) = '\0';
                               1390                 :              0 :         nrm.op = GETOPERAND(query);
 3358 teodor@sigaev.ru         1391                 :              0 :         infix(&nrm, -1, false);
 6374 tgl@sss.pgh.pa.us        1392                 :              0 :         res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
 6591                          1393                 :              0 :         pfree(q);
                               1394                 :                :     }
                               1395                 :                : 
                               1396         [ #  # ]:              0 :     PG_FREE_IF_COPY(query, 0);
                               1397                 :                : 
 6374                          1398                 :              0 :     PG_RETURN_TEXT_P(res);
                               1399                 :                : }
        

Generated by: LCOV version 2.4-beta