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-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 */
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 */
40typedef enum
41{
46
47/*
48 * token types for parsing
49 */
50typedef enum
51{
52 PT_END = 0,
53 PT_ERR = 1,
54 PT_VAL = 2,
55 PT_OPR = 3,
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 */
113static char *
114get_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 */
164static 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 (!isdigit((unsigned char) *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 */
243static 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 (!isspace((unsigned char) *ptr))
278 break;
279 }
280
281 pstate->buf += 2;
282 return true;
283}
284
285static 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 (!isspace((unsigned char) *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 (!isspace((unsigned char) *state->buf))
387 {
388 return PT_ERR;
389 }
390 break;
391 }
392
393 state->buf += pg_mblen(state->buf);
394 }
395}
396
397static 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 /* ignore, else gettoken_tsvector() will raise an error */
443 state->buf++;
444 state->state = WAITOPERAND;
445 continue;
446 }
447 else if (!isspace((unsigned char) *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 */
473 return PT_END;
474 }
475 }
476 break;
477
478 case WAITOPERATOR:
479 if (*state->buf == '\0')
480 {
481 return PT_END;
482 }
483 else if (parse_or_operator(state))
484 {
485 state->state = WAITOPERAND;
486 *operator = OP_OR;
487 return PT_OPR;
488 }
489 else if (ISOPERATOR(state->buf))
490 {
491 /* ignore other operators in this state too */
492 state->buf++;
493 continue;
494 }
495 else if (!isspace((unsigned char) *state->buf))
496 {
497 /* insert implicit AND between operands */
498 state->state = WAITOPERAND;
499 *operator = OP_AND;
500 return PT_OPR;
501 }
502 break;
503 }
504
505 state->buf += pg_mblen(state->buf);
506 }
507}
508
509static ts_tokentype
511 int *lenval, char **strval,
512 int16 *weight, bool *prefix)
513{
514 *weight = 0;
515 *prefix = false;
516
517 if (*state->buf == '\0')
518 return PT_END;
519
520 *strval = state->buf;
521 *lenval = strlen(state->buf);
522 state->buf += *lenval;
523 state->count++;
524 return PT_VAL;
525}
526
527/*
528 * Push an operator to state->polstr
529 */
530void
532{
533 QueryOperator *tmp;
534
535 Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
536
537 tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
538 tmp->type = QI_OPR;
539 tmp->oper = oper;
540 tmp->distance = (oper == OP_PHRASE) ? distance : 0;
541 /* left is filled in later with findoprnd */
542
543 state->polstr = lcons(tmp, state->polstr);
544}
545
546static void
547pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
548{
549 QueryOperand *tmp;
550
551 if (distance >= MAXSTRPOS)
552 ereturn(state->escontext,,
553 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
554 errmsg("value is too big in tsquery: \"%s\"",
555 state->buffer)));
556 if (lenval >= MAXSTRLEN)
557 ereturn(state->escontext,,
558 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
559 errmsg("operand is too long in tsquery: \"%s\"",
560 state->buffer)));
561
562 tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
563 tmp->type = QI_VAL;
564 tmp->weight = weight;
565 tmp->prefix = prefix;
566 tmp->valcrc = (int32) valcrc;
567 tmp->length = lenval;
568 tmp->distance = distance;
569
570 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 */
579void
580pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
581{
582 pg_crc32 valcrc;
583
584 if (lenval >= MAXSTRLEN)
585 ereturn(state->escontext,,
586 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
587 errmsg("word is too long in tsquery: \"%s\"",
588 state->buffer)));
589
590 INIT_LEGACY_CRC32(valcrc);
591 COMP_LEGACY_CRC32(valcrc, strval, lenval);
592 FIN_LEGACY_CRC32(valcrc);
593 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 */
596 while (state->curop - state->op + lenval + 1 >= state->lenop)
597 {
598 int used = state->curop - state->op;
599
600 state->lenop *= 2;
601 state->op = (char *) repalloc(state->op, state->lenop);
602 state->curop = state->op + used;
603 }
604 memcpy(state->curop, strval, lenval);
605 state->curop += lenval;
606 *(state->curop) = '\0';
607 state->curop++;
608 state->sumlen += lenval + 1 /* \0 */ ;
609}
610
611
612/*
613 * Push a stopword placeholder to state->polstr
614 */
615void
617{
618 QueryOperand *tmp;
619
620 tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
621 tmp->type = QI_VALSTOP;
622
623 state->polstr = lcons(tmp, state->polstr);
624}
625
626
627#define STACKDEPTH 32
628
629typedef struct OperatorElement
630{
634
635static void
636pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
637{
638 if (*lenstack == STACKDEPTH) /* internal error */
639 elog(ERROR, "tsquery stack too small");
640
641 stack[*lenstack].op = op;
642 stack[*lenstack].distance = distance;
643
644 (*lenstack)++;
645}
646
647static void
649 OperatorElement *stack, int *lenstack, int8 op)
650{
651 int opPriority = OP_PRIORITY(op);
652
653 while (*lenstack)
654 {
655 /* NOT is right associative unlike to others */
656 if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
657 (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
658 break;
659
660 (*lenstack)--;
661 pushOperator(state, stack[*lenstack].op,
662 stack[*lenstack].distance);
663 }
664}
665
666/*
667 * Make polish (prefix) notation of query.
668 *
669 * See parse_tsquery for explanation of pushval.
670 */
671static void
673 PushFunction pushval,
674 Datum opaque)
675{
676 int8 operator = 0;
678 int lenval = 0;
679 char *strval = NULL;
681 int lenstack = 0;
682 int16 weight = 0;
683 bool prefix;
684
685 /* since this function recurses, it could be driven to stack overflow */
687
688 while ((type = state->gettoken(state, &operator,
689 &lenval, &strval,
690 &weight, &prefix)) != PT_END)
691 {
692 switch (type)
693 {
694 case PT_VAL:
695 pushval(opaque, state, strval, lenval, weight, prefix);
696 break;
697 case PT_OPR:
698 cleanOpStack(state, opstack, &lenstack, operator);
699 pushOpStack(opstack, &lenstack, operator, weight);
700 break;
701 case PT_OPEN:
702 makepol(state, pushval, opaque);
703 break;
704 case PT_CLOSE:
705 cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
706 return;
707 case PT_ERR:
708 default:
709 /* don't overwrite a soft error saved by gettoken function */
710 if (!SOFT_ERROR_OCCURRED(state->escontext))
711 errsave(state->escontext,
712 (errcode(ERRCODE_SYNTAX_ERROR),
713 errmsg("syntax error in tsquery: \"%s\"",
714 state->buffer)));
715 return;
716 }
717 /* detect soft error in pushval or recursion */
718 if (SOFT_ERROR_OCCURRED(state->escontext))
719 return;
720 }
721
722 cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
723}
724
725static void
726findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
727{
728 /* since this function recurses, it could be driven to stack overflow. */
730
731 if (*pos >= nnodes)
732 elog(ERROR, "malformed tsquery: operand not found");
733
734 if (ptr[*pos].type == QI_VAL)
735 {
736 (*pos)++;
737 }
738 else if (ptr[*pos].type == QI_VALSTOP)
739 {
740 *needcleanup = true; /* we'll have to remove stop words */
741 (*pos)++;
742 }
743 else
744 {
745 Assert(ptr[*pos].type == QI_OPR);
746
747 if (ptr[*pos].qoperator.oper == OP_NOT)
748 {
749 ptr[*pos].qoperator.left = 1; /* fixed offset */
750 (*pos)++;
751
752 /* process the only argument */
753 findoprnd_recurse(ptr, pos, nnodes, needcleanup);
754 }
755 else
756 {
757 QueryOperator *curitem = &ptr[*pos].qoperator;
758 int tmp = *pos; /* save current position */
759
760 Assert(curitem->oper == OP_AND ||
761 curitem->oper == OP_OR ||
762 curitem->oper == OP_PHRASE);
763
764 (*pos)++;
765
766 /* process RIGHT argument */
767 findoprnd_recurse(ptr, pos, nnodes, needcleanup);
768
769 curitem->left = *pos - tmp; /* set LEFT arg's offset */
770
771 /* process LEFT argument */
772 findoprnd_recurse(ptr, pos, nnodes, needcleanup);
773 }
774 }
775}
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 */
783static void
784findoprnd(QueryItem *ptr, int size, bool *needcleanup)
785{
786 uint32 pos;
787
788 *needcleanup = false;
789 pos = 0;
790 findoprnd_recurse(ptr, &pos, size, needcleanup);
791
792 if (pos != size)
793 elog(ERROR, "malformed tsquery: extra nodes");
794}
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 */
818 PushFunction pushval,
819 Datum opaque,
820 int flags,
821 Node *escontext)
822{
824 int i;
825 TSQuery query;
826 int commonlen;
827 QueryItem *ptr;
828 ListCell *cell;
829 bool noisy;
830 bool needcleanup;
831 int tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
832
833 /* plain should not be used with web */
834 Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
835
836 /* select suitable tokenizer */
837 if (flags & P_TSQ_PLAIN)
838 state.gettoken = gettoken_query_plain;
839 else if (flags & P_TSQ_WEB)
840 {
842 tsv_flags |= P_TSV_IS_WEB;
843 }
844 else
846
847 /* emit nuisance NOTICEs only if not doing soft errors */
848 noisy = !(escontext && IsA(escontext, ErrorSaveContext));
849
850 /* init state */
851 state.buffer = buf;
852 state.buf = buf;
853 state.count = 0;
854 state.state = WAITFIRSTOPERAND;
855 state.polstr = NIL;
856 state.escontext = escontext;
857
858 /* init value parser's state */
859 state.valstate = init_tsvector_parser(state.buffer, tsv_flags, escontext);
860
861 /* init list of operand */
862 state.sumlen = 0;
863 state.lenop = 64;
864 state.curop = state.op = (char *) palloc(state.lenop);
865 *(state.curop) = '\0';
866
867 /* parse query & make polish notation (postfix, but in reverse order) */
868 makepol(&state, pushval, opaque);
869
871
873 return NULL;
874
875 if (state.polstr == NIL)
876 {
877 if (noisy)
879 (errmsg("text-search query doesn't contain lexemes: \"%s\"",
880 state.buffer)));
881 query = (TSQuery) palloc(HDRSIZETQ);
882 SET_VARSIZE(query, HDRSIZETQ);
883 query->size = 0;
884 return query;
885 }
886
887 if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
888 ereturn(escontext, NULL,
889 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
890 errmsg("tsquery is too large")));
891 commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
892
893 /* Pack the QueryItems in the final TSQuery struct to return to caller */
894 query = (TSQuery) palloc0(commonlen);
895 SET_VARSIZE(query, commonlen);
896 query->size = list_length(state.polstr);
897 ptr = GETQUERY(query);
898
899 /* Copy QueryItems to TSQuery */
900 i = 0;
901 foreach(cell, state.polstr)
902 {
903 QueryItem *item = (QueryItem *) lfirst(cell);
904
905 switch (item->type)
906 {
907 case QI_VAL:
908 memcpy(&ptr[i], item, sizeof(QueryOperand));
909 break;
910 case QI_VALSTOP:
911 ptr[i].type = QI_VALSTOP;
912 break;
913 case QI_OPR:
914 memcpy(&ptr[i], item, sizeof(QueryOperator));
915 break;
916 default:
917 elog(ERROR, "unrecognized QueryItem type: %d", item->type);
918 }
919 i++;
920 }
921
922 /* Copy all the operand strings to TSQuery */
923 memcpy(GETOPERAND(query), state.op, state.sumlen);
924 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 */
930 findoprnd(ptr, query->size, &needcleanup);
931
932 /*
933 * If there are QI_VALSTOP nodes, delete them and simplify the tree.
934 */
935 if (needcleanup)
936 query = cleanup_tsquery_stopwords(query, noisy);
937
938 return query;
939}
940
941static void
942pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval,
943 int16 weight, bool prefix)
944{
945 pushValue(state, strval, lenval, weight, prefix);
946}
947
948/*
949 * in without morphology
950 */
951Datum
953{
954 char *in = PG_GETARG_CSTRING(0);
955 Node *escontext = fcinfo->context;
956
959 PointerGetDatum(NULL),
960 0,
961 escontext));
962}
963
964/*
965 * out function
966 */
967typedef struct
968{
970 char *buf;
971 char *cur;
972 char *op;
974} INFIX;
975
976/* Makes sure inf->buf is large enough for adding 'addsize' bytes */
977#define RESIZEBUF(inf, addsize) \
978while( ( (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 */
990static void
991infix(INFIX *in, int parentPriority, bool rightPhraseOp)
992{
993 /* since this function recurses, it could be driven to stack overflow. */
995
996 if (in->curpol->type == QI_VAL)
997 {
998 QueryOperand *curpol = &in->curpol->qoperand;
999 char *op = in->op + curpol->distance;
1000 int clen;
1001
1002 RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
1003 *(in->cur) = '\'';
1004 in->cur++;
1005 while (*op)
1006 {
1007 if (t_iseq(op, '\''))
1008 {
1009 *(in->cur) = '\'';
1010 in->cur++;
1011 }
1012 else if (t_iseq(op, '\\'))
1013 {
1014 *(in->cur) = '\\';
1015 in->cur++;
1016 }
1017 COPYCHAR(in->cur, op);
1018
1019 clen = pg_mblen(op);
1020 op += clen;
1021 in->cur += clen;
1022 }
1023 *(in->cur) = '\'';
1024 in->cur++;
1025 if (curpol->weight || curpol->prefix)
1026 {
1027 *(in->cur) = ':';
1028 in->cur++;
1029 if (curpol->prefix)
1030 {
1031 *(in->cur) = '*';
1032 in->cur++;
1033 }
1034 if (curpol->weight & (1 << 3))
1035 {
1036 *(in->cur) = 'A';
1037 in->cur++;
1038 }
1039 if (curpol->weight & (1 << 2))
1040 {
1041 *(in->cur) = 'B';
1042 in->cur++;
1043 }
1044 if (curpol->weight & (1 << 1))
1045 {
1046 *(in->cur) = 'C';
1047 in->cur++;
1048 }
1049 if (curpol->weight & 1)
1050 {
1051 *(in->cur) = 'D';
1052 in->cur++;
1053 }
1054 }
1055 *(in->cur) = '\0';
1056 in->curpol++;
1057 }
1058 else if (in->curpol->qoperator.oper == OP_NOT)
1059 {
1060 int priority = QO_PRIORITY(in->curpol);
1061
1062 if (priority < parentPriority)
1063 {
1064 RESIZEBUF(in, 2);
1065 sprintf(in->cur, "( ");
1066 in->cur = strchr(in->cur, '\0');
1067 }
1068 RESIZEBUF(in, 1);
1069 *(in->cur) = '!';
1070 in->cur++;
1071 *(in->cur) = '\0';
1072 in->curpol++;
1073
1074 infix(in, priority, false);
1075 if (priority < parentPriority)
1076 {
1077 RESIZEBUF(in, 2);
1078 sprintf(in->cur, " )");
1079 in->cur = strchr(in->cur, '\0');
1080 }
1081 }
1082 else
1083 {
1084 int8 op = in->curpol->qoperator.oper;
1085 int priority = QO_PRIORITY(in->curpol);
1086 int16 distance = in->curpol->qoperator.distance;
1087 INFIX nrm;
1088 bool needParenthesis = false;
1089
1090 in->curpol++;
1091 if (priority < parentPriority ||
1092 /* phrase operator depends on order */
1093 (op == OP_PHRASE && rightPhraseOp))
1094 {
1095 needParenthesis = true;
1096 RESIZEBUF(in, 2);
1097 sprintf(in->cur, "( ");
1098 in->cur = strchr(in->cur, '\0');
1099 }
1100
1101 nrm.curpol = in->curpol;
1102 nrm.op = in->op;
1103 nrm.buflen = 16;
1104 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1105
1106 /* get right operand */
1107 infix(&nrm, priority, (op == OP_PHRASE));
1108
1109 /* get & print left operand */
1110 in->curpol = nrm.curpol;
1111 infix(in, priority, false);
1112
1113 /* print operator & right operand */
1114 RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
1115 switch (op)
1116 {
1117 case OP_OR:
1118 sprintf(in->cur, " | %s", nrm.buf);
1119 break;
1120 case OP_AND:
1121 sprintf(in->cur, " & %s", nrm.buf);
1122 break;
1123 case OP_PHRASE:
1124 if (distance != 1)
1125 sprintf(in->cur, " <%d> %s", distance, nrm.buf);
1126 else
1127 sprintf(in->cur, " <-> %s", nrm.buf);
1128 break;
1129 default:
1130 /* OP_NOT is handled in above if-branch */
1131 elog(ERROR, "unrecognized operator type: %d", op);
1132 }
1133 in->cur = strchr(in->cur, '\0');
1134 pfree(nrm.buf);
1135
1136 if (needParenthesis)
1137 {
1138 RESIZEBUF(in, 2);
1139 sprintf(in->cur, " )");
1140 in->cur = strchr(in->cur, '\0');
1141 }
1142 }
1143}
1144
1145Datum
1147{
1148 TSQuery query = PG_GETARG_TSQUERY(0);
1149 INFIX nrm;
1150
1151 if (query->size == 0)
1152 {
1153 char *b = palloc(1);
1154
1155 *b = '\0';
1157 }
1158 nrm.curpol = GETQUERY(query);
1159 nrm.buflen = 32;
1160 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1161 *(nrm.cur) = '\0';
1162 nrm.op = GETOPERAND(query);
1163 infix(&nrm, -1 /* lowest priority */ , false);
1164
1165 PG_FREE_IF_COPY(query, 0);
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 */
1188Datum
1190{
1191 TSQuery query = PG_GETARG_TSQUERY(0);
1193 int i;
1194 QueryItem *item = GETQUERY(query);
1195
1197
1198 pq_sendint32(&buf, query->size);
1199 for (i = 0; i < query->size; i++)
1200 {
1201 pq_sendint8(&buf, item->type);
1202
1203 switch (item->type)
1204 {
1205 case QI_VAL:
1206 pq_sendint8(&buf, item->qoperand.weight);
1207 pq_sendint8(&buf, item->qoperand.prefix);
1208 pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
1209 break;
1210 case QI_OPR:
1211 pq_sendint8(&buf, item->qoperator.oper);
1212 if (item->qoperator.oper == OP_PHRASE)
1214 break;
1215 default:
1216 elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1217 }
1218 item++;
1219 }
1220
1221 PG_FREE_IF_COPY(query, 0);
1222
1224}
1225
1226Datum
1228{
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
1240 size = pq_getmsgint(buf, sizeof(uint32));
1241 if (size > (MaxAllocSize / sizeof(QueryItem)))
1242 elog(ERROR, "invalid size of tsquery");
1243
1244 /* Allocate space to temporarily hold operand strings */
1245 operands = palloc(size * sizeof(char *));
1246
1247 /* Allocate space for all the QueryItems. */
1248 len = HDRSIZETQ + sizeof(QueryItem) * size;
1249 query = (TSQuery) palloc0(len);
1250 query->size = size;
1251 item = GETQUERY(query);
1252
1253 datalen = 0;
1254 for (i = 0; i < size; i++)
1255 {
1256 item->type = (int8) pq_getmsgint(buf, sizeof(int8));
1257
1258 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
1267 weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
1268 prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
1270 val_len = strlen(val);
1271
1272 /* Sanity checks */
1273
1274 if (weight > 0xF)
1275 elog(ERROR, "invalid tsquery: invalid weight bitmap");
1276
1277 if (val_len > MAXSTRLEN)
1278 elog(ERROR, "invalid tsquery: operand too long");
1279
1280 if (datalen > MAXSTRPOS)
1281 elog(ERROR, "invalid tsquery: total operand length exceeded");
1282
1283 /* Looks valid. */
1284
1285 INIT_LEGACY_CRC32(valcrc);
1286 COMP_LEGACY_CRC32(valcrc, val, val_len);
1287 FIN_LEGACY_CRC32(valcrc);
1288
1289 item->qoperand.weight = weight;
1290 item->qoperand.prefix = (prefix) ? true : false;
1291 item->qoperand.valcrc = (int32) valcrc;
1292 item->qoperand.length = val_len;
1293 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 */
1299 operands[i] = val;
1300
1301 datalen += val_len + 1; /* + 1 for the '\0' terminator */
1302 }
1303 else if (item->type == QI_OPR)
1304 {
1305 int8 oper;
1306
1307 oper = (int8) pq_getmsgint(buf, sizeof(int8));
1308 if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
1309 elog(ERROR, "invalid tsquery: unrecognized operator type %d",
1310 (int) oper);
1311 if (i == size - 1)
1312 elog(ERROR, "invalid pointer to right operand");
1313
1314 item->qoperator.oper = oper;
1315 if (oper == OP_PHRASE)
1316 item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
1317 }
1318 else
1319 elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1320
1321 item++;
1322 }
1323
1324 /* Enlarge buffer to make room for the operand values. */
1325 query = (TSQuery) repalloc(query, len + datalen);
1326 item = GETQUERY(query);
1327 ptr = GETOPERAND(query);
1328
1329 /*
1330 * Fill in the left-pointers. Checks that the tree is well-formed as a
1331 * side-effect.
1332 */
1333 findoprnd(item, size, &needcleanup);
1334
1335 /* Can't have found any QI_VALSTOP nodes */
1336 Assert(!needcleanup);
1337
1338 /* Copy operands to output struct */
1339 for (i = 0; i < size; i++)
1340 {
1341 if (item->type == QI_VAL)
1342 {
1343 memcpy(ptr, operands[i], item->qoperand.length + 1);
1344 ptr += item->qoperand.length + 1;
1345 }
1346 item++;
1347 }
1348
1349 pfree(operands);
1350
1351 Assert(ptr - GETOPERAND(query) == datalen);
1352
1353 SET_VARSIZE(query, len + datalen);
1354
1355 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 */
1362Datum
1364{
1365 TSQuery query = PG_GETARG_TSQUERY(0);
1366 INFIX nrm;
1367 text *res;
1368 QueryItem *q;
1369 int len;
1370
1371 if (query->size == 0)
1372 {
1373 res = (text *) palloc(VARHDRSZ);
1374 SET_VARSIZE(res, VARHDRSZ);
1375 PG_RETURN_POINTER(res);
1376 }
1377
1378 q = clean_NOT(GETQUERY(query), &len);
1379
1380 if (!q)
1381 {
1382 res = cstring_to_text("T");
1383 }
1384 else
1385 {
1386 nrm.curpol = q;
1387 nrm.buflen = 32;
1388 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1389 *(nrm.cur) = '\0';
1390 nrm.op = GETOPERAND(query);
1391 infix(&nrm, -1, false);
1392 res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
1393 pfree(q);
1394 }
1395
1396 PG_FREE_IF_COPY(query, 0);
1397
1398 PG_RETURN_TEXT_P(res);
1399}
#define COMPUTESIZE(size)
Definition: _int.h:155
#define GETQUERY(x)
Definition: _int.h:157
uint8_t uint8
Definition: c.h:500
#define VARHDRSZ
Definition: c.h:663
int16_t int16
Definition: c.h:497
int8_t int8
Definition: c.h:496
int32_t int32
Definition: c.h:498
uint32_t uint32
Definition: c.h:502
struct cursor * cur
Definition: ecpg.c:29
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereturn(context, dummy_value,...)
Definition: elog.h:277
#define errsave(context,...)
Definition: elog.h:261
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
#define MaxAllocSize
Definition: fe_memutils.h:22
#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
Assert(PointerIsAligned(start, uint64))
long val
Definition: informix.c:689
int b
Definition: isn.c:74
int i
Definition: isn.c:77
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 * repalloc(void *pointer, Size size)
Definition: mcxt.c:2172
void pfree(void *pointer)
Definition: mcxt.c:2152
void * palloc0(Size size)
Definition: mcxt.c:1975
void * palloc(Size size)
Definition: mcxt.c:1945
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
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:72
#define sprintf
Definition: port.h:241
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
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
void check_stack_depth(void)
Definition: stack_depth.c:95
StringInfoData * StringInfo
Definition: stringinfo.h:54
int buflen
Definition: tsquery.c:973
char * buf
Definition: _int_bool.c:552
QueryItem * curpol
Definition: tsquery.c:969
char * cur
Definition: _int_bool.c:553
int32 buflen
Definition: _int_bool.c:554
ITEM * curpol
Definition: _int_bool.c:551
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:135
int16 distance
Definition: tsquery.c:632
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:658
int t_isalnum(const char *ptr)
Definition: ts_locale.c:50
#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 char * get_modifiers(char *buf, int16 *weight, bool *prefix)
Definition: tsquery.c:114
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:636
void pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:580
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:1227
static void pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
Definition: tsquery.c:547
Datum tsquerytree(PG_FUNCTION_ARGS)
Definition: tsquery.c:1363
#define RESIZEBUF(inf, addsize)
Definition: tsquery.c:977
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:784
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:817
void pushOperator(TSQueryParserState state, int8 oper, int16 distance)
Definition: tsquery.c:531
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:1189
static void cleanOpStack(TSQueryParserState state, OperatorElement *stack, int *lenstack, int8 op)
Definition: tsquery.c:648
static void makepol(TSQueryParserState state, PushFunction pushval, Datum opaque)
Definition: tsquery.c:672
Datum tsqueryin(PG_FUNCTION_ARGS)
Definition: tsquery.c:952
Datum tsqueryout(PG_FUNCTION_ARGS)
Definition: tsquery.c:1146
static void pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:942
#define STACKDEPTH
Definition: tsquery.c:627
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:991
static ts_tokentype gettoken_query_plain(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:510
void pushStop(TSQueryParserState state)
Definition: tsquery.c:616
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:726
static ts_tokentype gettoken_query_websearch(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:398
TSQuery cleanup_tsquery_stopwords(TSQuery in, bool noisy)
QueryItem * clean_NOT(QueryItem *ptr, int *len)
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:204
text * cstring_to_text(const char *s)
Definition: varlena.c:192
const char * type