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