PostgreSQL Source Code  git master
tsquery.c File Reference
#include "postgres.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "tsearch/ts_type.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_utils.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/pg_crc.h"
Include dependency graph for tsquery.c:

Go to the source code of this file.

Data Structures

struct  TSQueryParserStateData
 
struct  OperatorElement
 
struct  INFIX
 

Macros

#define STACKDEPTH   32
 
#define RESIZEBUF(inf, addsize)
 

Typedefs

typedef ts_tokentype(* ts_tokenizer) (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
 
typedef struct OperatorElement OperatorElement
 

Enumerations

enum  ts_parserstate { WAITOPERAND = 1, WAITOPERATOR = 2, WAITFIRSTOPERAND = 3 }
 
enum  ts_tokentype {
  PT_END = 0, PT_ERR = 1, PT_VAL = 2, PT_OPR = 3,
  PT_OPEN = 4, PT_CLOSE = 5
}
 

Functions

static char * get_modifiers (char *buf, int16 *weight, bool *prefix)
 
static bool parse_phrase_operator (TSQueryParserState pstate, int16 *distance)
 
static bool parse_or_operator (TSQueryParserState pstate)
 
static ts_tokentype gettoken_query_standard (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
 
static ts_tokentype gettoken_query_websearch (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
 
static ts_tokentype gettoken_query_plain (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
 
void pushOperator (TSQueryParserState state, int8 oper, int16 distance)
 
static void pushValue_internal (TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
 
void pushValue (TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
 
void pushStop (TSQueryParserState state)
 
static void pushOpStack (OperatorElement *stack, int *lenstack, int8 op, int16 distance)
 
static void cleanOpStack (TSQueryParserState state, OperatorElement *stack, int *lenstack, int8 op)
 
static void makepol (TSQueryParserState state, PushFunction pushval, Datum opaque)
 
static void findoprnd_recurse (QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
 
static void findoprnd (QueryItem *ptr, int size, bool *needcleanup)
 
TSQuery parse_tsquery (char *buf, PushFunction pushval, Datum opaque, int flags)
 
static void pushval_asis (Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
 
Datum tsqueryin (PG_FUNCTION_ARGS)
 
static void infix (INFIX *in, int parentPriority, bool rightPhraseOp)
 
Datum tsqueryout (PG_FUNCTION_ARGS)
 
Datum tsquerysend (PG_FUNCTION_ARGS)
 
Datum tsqueryrecv (PG_FUNCTION_ARGS)
 
Datum tsquerytree (PG_FUNCTION_ARGS)
 

Variables

const int tsearch_op_priority [OP_COUNT]
 

Macro Definition Documentation

◆ RESIZEBUF

#define RESIZEBUF (   inf,
  addsize 
)
Value:
while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
{ \
int len = (inf)->cur - (inf)->buf; \
(inf)->buflen *= 2; \
(inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
(inf)->cur = (inf)->buf + len; \
}
struct cursor * cur
Definition: ecpg.c:28
static char * buf
Definition: pg_test_fsync.c:67
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044

Definition at line 957 of file tsquery.c.

Referenced by infix().

◆ STACKDEPTH

#define STACKDEPTH   32

Definition at line 635 of file tsquery.c.

Referenced by makepol(), and pushOpStack().

Typedef Documentation

◆ OperatorElement

◆ ts_tokenizer

typedef ts_tokentype(* ts_tokenizer) (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)

Definition at line 66 of file tsquery.c.

Enumeration Type Documentation

◆ ts_parserstate

Enumerator
WAITOPERAND 
WAITOPERATOR 
WAITFIRSTOPERAND 

Definition at line 38 of file tsquery.c.

39 {
40  WAITOPERAND = 1,
41  WAITOPERATOR = 2,
ts_parserstate
Definition: tsquery.c:38

◆ ts_tokentype

Enumerator
PT_END 
PT_ERR 
PT_VAL 
PT_OPR 
PT_OPEN 
PT_CLOSE 

Definition at line 48 of file tsquery.c.

49 {
50  PT_END = 0,
51  PT_ERR = 1,
52  PT_VAL = 2,
53  PT_OPR = 3,
54  PT_OPEN = 4,
55  PT_CLOSE = 5
56 } ts_tokentype;
Definition: tsquery.c:51
Definition: tsquery.c:50
Definition: tsquery.c:52
Definition: tsquery.c:53
ts_tokentype
Definition: tsquery.c:48

Function Documentation

◆ cleanOpStack()

static void cleanOpStack ( TSQueryParserState  state,
OperatorElement stack,
int *  lenstack,
int8  op 
)
static

Definition at line 656 of file tsquery.c.

References OP_NOT, OP_PRIORITY, and pushOperator().

Referenced by makepol().

658 {
659  int opPriority = OP_PRIORITY(op);
660 
661  while (*lenstack)
662  {
663  /* NOT is right associative unlike to others */
664  if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
665  (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
666  break;
667 
668  (*lenstack)--;
669  pushOperator(state, stack[*lenstack].op,
670  stack[*lenstack].distance);
671  }
672 }
#define OP_PRIORITY(x)
Definition: ts_type.h:175
void pushOperator(TSQueryParserState state, int8 oper, int16 distance)
Definition: tsquery.c:539
#define OP_NOT
Definition: ts_type.h:166

◆ findoprnd()

static void findoprnd ( QueryItem ptr,
int  size,
bool needcleanup 
)
static

Definition at line 786 of file tsquery.c.

References elog, ERROR, and findoprnd_recurse().

Referenced by parse_tsquery(), and tsqueryrecv().

787 {
788  uint32 pos;
789 
790  *needcleanup = false;
791  pos = 0;
792  findoprnd_recurse(ptr, &pos, size, needcleanup);
793 
794  if (pos != size)
795  elog(ERROR, "malformed tsquery: extra nodes");
796 }
#define ERROR
Definition: elog.h:43
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:728
unsigned int uint32
Definition: c.h:325
#define elog
Definition: elog.h:219

◆ findoprnd_recurse()

static void findoprnd_recurse ( QueryItem ptr,
uint32 pos,
int  nnodes,
bool needcleanup 
)
static

Definition at line 728 of file tsquery.c.

References Assert, check_stack_depth(), elog, ERROR, QueryOperator::left, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, QI_OPR, QI_VAL, QI_VALSTOP, QueryItem::qoperator, and generate_unaccent_rules::type.

Referenced by findoprnd().

729 {
730  /* since this function recurses, it could be driven to stack overflow. */
732 
733  if (*pos >= nnodes)
734  elog(ERROR, "malformed tsquery: operand not found");
735 
736  if (ptr[*pos].type == QI_VAL)
737  {
738  (*pos)++;
739  }
740  else if (ptr[*pos].type == QI_VALSTOP)
741  {
742  *needcleanup = true; /* we'll have to remove stop words */
743  (*pos)++;
744  }
745  else
746  {
747  Assert(ptr[*pos].type == QI_OPR);
748 
749  if (ptr[*pos].qoperator.oper == OP_NOT)
750  {
751  ptr[*pos].qoperator.left = 1; /* fixed offset */
752  (*pos)++;
753 
754  /* process the only argument */
755  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
756  }
757  else
758  {
759  QueryOperator *curitem = &ptr[*pos].qoperator;
760  int tmp = *pos; /* save current position */
761 
762  Assert(curitem->oper == OP_AND ||
763  curitem->oper == OP_OR ||
764  curitem->oper == OP_PHRASE);
765 
766  (*pos)++;
767 
768  /* process RIGHT argument */
769  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
770 
771  curitem->left = *pos - tmp; /* set LEFT arg's offset */
772 
773  /* process LEFT argument */
774  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
775  }
776  }
777 }
#define QI_VALSTOP
Definition: ts_type.h:136
QueryOperator qoperator
Definition: ts_type.h:196
#define QI_VAL
Definition: ts_type.h:134
#define OP_OR
Definition: ts_type.h:168
#define OP_AND
Definition: ts_type.h:167
#define ERROR
Definition: elog.h:43
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:728
void check_stack_depth(void)
Definition: postgres.c:3155
#define QI_OPR
Definition: ts_type.h:135
#define Assert(condition)
Definition: c.h:699
#define OP_PHRASE
Definition: ts_type.h:169
uint32 left
Definition: ts_type.h:184
#define elog
Definition: elog.h:219
#define OP_NOT
Definition: ts_type.h:166

◆ get_modifiers()

static char* get_modifiers ( char *  buf,
int16 weight,
bool prefix 
)
static

Definition at line 104 of file tsquery.c.

References TSQueryParserStateData::buf, pg_mblen(), and t_iseq.

Referenced by gettoken_query_standard().

105 {
106  *weight = 0;
107  *prefix = false;
108 
109  if (!t_iseq(buf, ':'))
110  return buf;
111 
112  buf++;
113  while (*buf && pg_mblen(buf) == 1)
114  {
115  switch (*buf)
116  {
117  case 'a':
118  case 'A':
119  *weight |= 1 << 3;
120  break;
121  case 'b':
122  case 'B':
123  *weight |= 1 << 2;
124  break;
125  case 'c':
126  case 'C':
127  *weight |= 1 << 1;
128  break;
129  case 'd':
130  case 'D':
131  *weight |= 1;
132  break;
133  case '*':
134  *prefix = true;
135  break;
136  default:
137  return buf;
138  }
139  buf++;
140  }
141 
142  return buf;
143 }
static char * buf
Definition: pg_test_fsync.c:67
#define t_iseq(x, c)
Definition: ts_locale.h:45
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760

◆ gettoken_query_plain()

static ts_tokentype gettoken_query_plain ( TSQueryParserState  state,
int8 operator,
int *  lenval,
char **  strval,
int16 weight,
bool prefix 
)
static

Definition at line 518 of file tsquery.c.

References TSQueryParserStateData::buf, TSQueryParserStateData::count, PT_END, and PT_VAL.

Referenced by parse_tsquery().

521 {
522  *weight = 0;
523  *prefix = false;
524 
525  if (*state->buf == '\0')
526  return PT_END;
527 
528  *strval = state->buf;
529  *lenval = strlen(state->buf);
530  state->buf += *lenval;
531  state->count++;
532  return PT_VAL;
533 }
Definition: tsquery.c:50
Definition: tsquery.c:52

◆ gettoken_query_standard()

static ts_tokentype gettoken_query_standard ( TSQueryParserState  state,
int8 operator,
int *  lenval,
char **  strval,
int16 weight,
bool prefix 
)
static

Definition at line 279 of file tsquery.c.

References TSQueryParserStateData::buf, TSQueryParserStateData::buffer, TSQueryParserStateData::count, ereport, errcode(), errmsg(), ERROR, get_modifiers(), gettoken_tsvector(), OP_AND, OP_NOT, OP_OR, OP_PHRASE, parse_phrase_operator(), pg_mblen(), PT_CLOSE, PT_END, PT_ERR, PT_OPEN, PT_OPR, PT_VAL, reset_tsvector_parser(), TSQueryParserStateData::state, t_iseq, t_isspace(), TSQueryParserStateData::valstate, WAITFIRSTOPERAND, WAITOPERAND, and WAITOPERATOR.

Referenced by parse_tsquery().

282 {
283  *weight = 0;
284  *prefix = false;
285 
286  while (true)
287  {
288  switch (state->state)
289  {
290  case WAITFIRSTOPERAND:
291  case WAITOPERAND:
292  if (t_iseq(state->buf, '!'))
293  {
294  state->buf++;
295  state->state = WAITOPERAND;
296  *operator = OP_NOT;
297  return PT_OPR;
298  }
299  else if (t_iseq(state->buf, '('))
300  {
301  state->buf++;
302  state->state = WAITOPERAND;
303  state->count++;
304  return PT_OPEN;
305  }
306  else if (t_iseq(state->buf, ':'))
307  {
308  ereport(ERROR,
309  (errcode(ERRCODE_SYNTAX_ERROR),
310  errmsg("syntax error in tsquery: \"%s\"",
311  state->buffer)));
312  }
313  else if (!t_isspace(state->buf))
314  {
315  /* We rely on the tsvector parser to parse the value for us */
316  reset_tsvector_parser(state->valstate, state->buf);
317  if (gettoken_tsvector(state->valstate, strval, lenval,
318  NULL, NULL, &state->buf))
319  {
320  state->buf = get_modifiers(state->buf, weight, prefix);
321  state->state = WAITOPERATOR;
322  return PT_VAL;
323  }
324  else if (state->state == WAITFIRSTOPERAND)
325  {
326  return PT_END;
327  }
328  else
329  ereport(ERROR,
330  (errcode(ERRCODE_SYNTAX_ERROR),
331  errmsg("no operand in tsquery: \"%s\"",
332  state->buffer)));
333  }
334  break;
335 
336  case WAITOPERATOR:
337  if (t_iseq(state->buf, '&'))
338  {
339  state->buf++;
340  state->state = WAITOPERAND;
341  *operator = OP_AND;
342  return PT_OPR;
343  }
344  else if (t_iseq(state->buf, '|'))
345  {
346  state->buf++;
347  state->state = WAITOPERAND;
348  *operator = OP_OR;
349  return PT_OPR;
350  }
351  else if (parse_phrase_operator(state, weight))
352  {
353  /* weight var is used as storage for distance */
354  state->state = WAITOPERAND;
355  *operator = OP_PHRASE;
356  return PT_OPR;
357  }
358  else if (t_iseq(state->buf, ')'))
359  {
360  state->buf++;
361  state->count--;
362  return (state->count < 0) ? PT_ERR : PT_CLOSE;
363  }
364  else if (*state->buf == '\0')
365  {
366  return (state->count) ? PT_ERR : PT_END;
367  }
368  else if (!t_isspace(state->buf))
369  {
370  return PT_ERR;
371  }
372  break;
373  }
374 
375  state->buf += pg_mblen(state->buf);
376  }
377 }
bool gettoken_tsvector(TSVectorParseState state, char **strval, int *lenval, WordEntryPos **pos_ptr, int *poslen, char **endptr)
Definition: tsquery.c:51
TSVectorParseState valstate
Definition: tsquery.c:96
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OP_OR
Definition: ts_type.h:168
#define OP_AND
Definition: ts_type.h:167
#define ERROR
Definition: elog.h:43
int t_isspace(const char *ptr)
Definition: ts_locale.c:41
static bool parse_phrase_operator(TSQueryParserState pstate, int16 *distance)
Definition: tsquery.c:155
#define t_iseq(x, c)
Definition: ts_locale.h:45
#define ereport(elevel, rest)
Definition: elog.h:122
static char * get_modifiers(char *buf, int16 *weight, bool *prefix)
Definition: tsquery.c:104
ts_parserstate state
Definition: tsquery.c:81
Definition: tsquery.c:50
void reset_tsvector_parser(TSVectorParseState state, char *input)
#define OP_PHRASE
Definition: ts_type.h:169
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760
Definition: tsquery.c:52
Definition: tsquery.c:53
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define OP_NOT
Definition: ts_type.h:166

◆ gettoken_query_websearch()

static ts_tokentype gettoken_query_websearch ( TSQueryParserState  state,
int8 operator,
int *  lenval,
char **  strval,
int16 weight,
bool prefix 
)
static

Definition at line 380 of file tsquery.c.

References TSQueryParserStateData::buf, gettoken_tsvector(), TSQueryParserStateData::in_quotes, ISOPERATOR, OP_AND, OP_NOT, OP_OR, OP_PHRASE, parse_or_operator(), pg_mblen(), PT_CLOSE, PT_END, PT_OPEN, PT_OPR, PT_VAL, pushStop(), reset_tsvector_parser(), TSQueryParserStateData::state, t_iseq, t_isspace(), TSQueryParserStateData::valstate, WAITFIRSTOPERAND, WAITOPERAND, and WAITOPERATOR.

Referenced by parse_tsquery().

383 {
384  *weight = 0;
385  *prefix = false;
386 
387  while (true)
388  {
389  switch (state->state)
390  {
391  case WAITFIRSTOPERAND:
392  case WAITOPERAND:
393  if (t_iseq(state->buf, '-'))
394  {
395  state->buf++;
396  state->state = WAITOPERAND;
397 
398  if (state->in_quotes)
399  continue;
400 
401  *operator = OP_NOT;
402  return PT_OPR;
403  }
404  else if (t_iseq(state->buf, '"'))
405  {
406  state->buf++;
407 
408  if (!state->in_quotes)
409  {
410  state->state = WAITOPERAND;
411 
412  if (strchr(state->buf, '"'))
413  {
414  /* quoted text should be ordered <-> */
415  state->in_quotes = true;
416  return PT_OPEN;
417  }
418 
419  /* web search tolerates missing quotes */
420  continue;
421  }
422  else
423  {
424  /* we have to provide an operand */
425  state->in_quotes = false;
426  state->state = WAITOPERATOR;
427  pushStop(state);
428  return PT_CLOSE;
429  }
430  }
431  else if (ISOPERATOR(state->buf))
432  {
433  /* or else gettoken_tsvector() will raise an error */
434  state->buf++;
435  state->state = WAITOPERAND;
436  continue;
437  }
438  else if (!t_isspace(state->buf))
439  {
440  /* We rely on the tsvector parser to parse the value for us */
441  reset_tsvector_parser(state->valstate, state->buf);
442  if (gettoken_tsvector(state->valstate, strval, lenval,
443  NULL, NULL, &state->buf))
444  {
445  state->state = WAITOPERATOR;
446  return PT_VAL;
447  }
448  else if (state->state == WAITFIRSTOPERAND)
449  {
450  return PT_END;
451  }
452  else
453  {
454  /* finally, we have to provide an operand */
455  pushStop(state);
456  return PT_END;
457  }
458  }
459  break;
460 
461  case WAITOPERATOR:
462  if (t_iseq(state->buf, '"'))
463  {
464  if (!state->in_quotes)
465  {
466  /*
467  * put implicit AND after an operand
468  * and handle this quote in WAITOPERAND
469  */
470  state->state = WAITOPERAND;
471  *operator = OP_AND;
472  return PT_OPR;
473  }
474  else
475  {
476  state->buf++;
477 
478  /* just close quotes */
479  state->in_quotes = false;
480  return PT_CLOSE;
481  }
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 (*state->buf == '\0')
490  {
491  return PT_END;
492  }
493  else if (!t_isspace(state->buf))
494  {
495  if (state->in_quotes)
496  {
497  /* put implicit <-> after an operand */
498  *operator = OP_PHRASE;
499  *weight = 1;
500  }
501  else
502  {
503  /* put implicit AND after an operand */
504  *operator = OP_AND;
505  }
506 
507  state->state = WAITOPERAND;
508  return PT_OPR;
509  }
510  break;
511  }
512 
513  state->buf += pg_mblen(state->buf);
514  }
515 }
bool gettoken_tsvector(TSVectorParseState state, char **strval, int *lenval, WordEntryPos **pos_ptr, int *poslen, char **endptr)
TSVectorParseState valstate
Definition: tsquery.c:96
#define OP_OR
Definition: ts_type.h:168
#define ISOPERATOR(x)
Definition: ltree.h:120
#define OP_AND
Definition: ts_type.h:167
void pushStop(TSQueryParserState state)
Definition: tsquery.c:624
int t_isspace(const char *ptr)
Definition: ts_locale.c:41
#define t_iseq(x, c)
Definition: ts_locale.h:45
ts_parserstate state
Definition: tsquery.c:81
Definition: tsquery.c:50
void reset_tsvector_parser(TSVectorParseState state, char *input)
static bool parse_or_operator(TSQueryParserState pstate)
Definition: tsquery.c:234
#define OP_PHRASE
Definition: ts_type.h:169
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760
Definition: tsquery.c:52
Definition: tsquery.c:53
#define OP_NOT
Definition: ts_type.h:166

◆ infix()

static void infix ( INFIX in,
int  parentPriority,
bool  rightPhraseOp 
)
static

Definition at line 971 of file tsquery.c.

References INFIX::buf, INFIX::buflen, check_stack_depth(), COPYCHAR, INFIX::cur, INFIX::curpol, ITEM::distance, QueryOperand::distance, elog, ERROR, QueryOperand::length, TSQueryParserStateData::op, INFIX::op, OP_AND, OP_NOT, OP_OR, OP_PHRASE, palloc(), pfree(), pg_database_encoding_max_length(), pg_mblen(), QueryOperand::prefix, QI_VAL, QO_PRIORITY, RESIZEBUF, t_iseq, ITEM::type, and QueryOperand::weight.

Referenced by tsqueryout(), and tsquerytree().

972 {
973  /* since this function recurses, it could be driven to stack overflow. */
975 
976  if (in->curpol->type == QI_VAL)
977  {
978  QueryOperand *curpol = &in->curpol->qoperand;
979  char *op = in->op + curpol->distance;
980  int clen;
981 
982  RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
983  *(in->cur) = '\'';
984  in->cur++;
985  while (*op)
986  {
987  if (t_iseq(op, '\''))
988  {
989  *(in->cur) = '\'';
990  in->cur++;
991  }
992  else if (t_iseq(op, '\\'))
993  {
994  *(in->cur) = '\\';
995  in->cur++;
996  }
997  COPYCHAR(in->cur, op);
998 
999  clen = pg_mblen(op);
1000  op += clen;
1001  in->cur += clen;
1002  }
1003  *(in->cur) = '\'';
1004  in->cur++;
1005  if (curpol->weight || curpol->prefix)
1006  {
1007  *(in->cur) = ':';
1008  in->cur++;
1009  if (curpol->prefix)
1010  {
1011  *(in->cur) = '*';
1012  in->cur++;
1013  }
1014  if (curpol->weight & (1 << 3))
1015  {
1016  *(in->cur) = 'A';
1017  in->cur++;
1018  }
1019  if (curpol->weight & (1 << 2))
1020  {
1021  *(in->cur) = 'B';
1022  in->cur++;
1023  }
1024  if (curpol->weight & (1 << 1))
1025  {
1026  *(in->cur) = 'C';
1027  in->cur++;
1028  }
1029  if (curpol->weight & 1)
1030  {
1031  *(in->cur) = 'D';
1032  in->cur++;
1033  }
1034  }
1035  *(in->cur) = '\0';
1036  in->curpol++;
1037  }
1038  else if (in->curpol->qoperator.oper == OP_NOT)
1039  {
1040  int priority = QO_PRIORITY(in->curpol);
1041 
1042  if (priority < parentPriority)
1043  {
1044  RESIZEBUF(in, 2);
1045  sprintf(in->cur, "( ");
1046  in->cur = strchr(in->cur, '\0');
1047  }
1048  RESIZEBUF(in, 1);
1049  *(in->cur) = '!';
1050  in->cur++;
1051  *(in->cur) = '\0';
1052  in->curpol++;
1053 
1054  infix(in, priority, false);
1055  if (priority < parentPriority)
1056  {
1057  RESIZEBUF(in, 2);
1058  sprintf(in->cur, " )");
1059  in->cur = strchr(in->cur, '\0');
1060  }
1061  }
1062  else
1063  {
1064  int8 op = in->curpol->qoperator.oper;
1065  int priority = QO_PRIORITY(in->curpol);
1066  int16 distance = in->curpol->qoperator.distance;
1067  INFIX nrm;
1068  bool needParenthesis = false;
1069 
1070  in->curpol++;
1071  if (priority < parentPriority ||
1072  /* phrase operator depends on order */
1073  (op == OP_PHRASE && rightPhraseOp))
1074  {
1075  needParenthesis = true;
1076  RESIZEBUF(in, 2);
1077  sprintf(in->cur, "( ");
1078  in->cur = strchr(in->cur, '\0');
1079  }
1080 
1081  nrm.curpol = in->curpol;
1082  nrm.op = in->op;
1083  nrm.buflen = 16;
1084  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1085 
1086  /* get right operand */
1087  infix(&nrm, priority, (op == OP_PHRASE));
1088 
1089  /* get & print left operand */
1090  in->curpol = nrm.curpol;
1091  infix(in, priority, false);
1092 
1093  /* print operator & right operand */
1094  RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
1095  switch (op)
1096  {
1097  case OP_OR:
1098  sprintf(in->cur, " | %s", nrm.buf);
1099  break;
1100  case OP_AND:
1101  sprintf(in->cur, " & %s", nrm.buf);
1102  break;
1103  case OP_PHRASE:
1104  if (distance != 1)
1105  sprintf(in->cur, " <%d> %s", distance, nrm.buf);
1106  else
1107  sprintf(in->cur, " <-> %s", nrm.buf);
1108  break;
1109  default:
1110  /* OP_NOT is handled in above if-branch */
1111  elog(ERROR, "unrecognized operator type: %d", op);
1112  }
1113  in->cur = strchr(in->cur, '\0');
1114  pfree(nrm.buf);
1115 
1116  if (needParenthesis)
1117  {
1118  RESIZEBUF(in, 2);
1119  sprintf(in->cur, " )");
1120  in->cur = strchr(in->cur, '\0');
1121  }
1122  }
1123 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:47
signed short int16
Definition: c.h:312
#define QO_PRIORITY(x)
Definition: ts_type.h:177
ITEM * curpol
Definition: _int_bool.c:551
char * op
Definition: ltxtquery_io.c:399
#define QI_VAL
Definition: ts_type.h:134
uint32 distance
Definition: ts_type.h:158
#define OP_OR
Definition: ts_type.h:168
#define RESIZEBUF(inf, addsize)
Definition: tsquery.c:957
int16 type
Definition: _int.h:127
#define OP_AND
Definition: ts_type.h:167
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:971
uint8 weight
Definition: ts_type.h:146
void check_stack_depth(void)
Definition: postgres.c:3155
int pg_database_encoding_max_length(void)
Definition: wchar.c:1833
#define t_iseq(x, c)
Definition: ts_locale.h:45
signed char int8
Definition: c.h:311
#define OP_PHRASE
Definition: ts_type.h:169
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760
uint32 length
Definition: ts_type.h:158
char * cur
Definition: _int_bool.c:553
void * palloc(Size size)
Definition: mcxt.c:924
int32 buflen
Definition: _int_bool.c:554
bool prefix
Definition: ts_type.h:150
#define elog
Definition: elog.h:219
uint16 distance
Definition: ltree.h:99
char * buf
Definition: _int_bool.c:552
#define OP_NOT
Definition: ts_type.h:166

◆ makepol()

static void makepol ( TSQueryParserState  state,
PushFunction  pushval,
Datum  opaque 
)
static

Definition at line 680 of file tsquery.c.

References TSQueryParserStateData::buffer, check_stack_depth(), cleanOpStack(), ereport, errcode(), errmsg(), ERROR, TSQueryParserStateData::gettoken, OP_OR, PT_CLOSE, PT_END, PT_ERR, PT_OPEN, PT_OPR, PT_VAL, pushOpStack(), STACKDEPTH, and generate_unaccent_rules::type.

Referenced by parse_tsquery().

683 {
684  int8 operator = 0;
686  int lenval = 0;
687  char *strval = NULL;
688  OperatorElement opstack[STACKDEPTH];
689  int lenstack = 0;
690  int16 weight = 0;
691  bool prefix;
692 
693  /* since this function recurses, it could be driven to stack overflow */
695 
696  while ((type = state->gettoken(state, &operator,
697  &lenval, &strval,
698  &weight, &prefix)) != PT_END)
699  {
700  switch (type)
701  {
702  case PT_VAL:
703  pushval(opaque, state, strval, lenval, weight, prefix);
704  break;
705  case PT_OPR:
706  cleanOpStack(state, opstack, &lenstack, operator);
707  pushOpStack(opstack, &lenstack, operator, weight);
708  break;
709  case PT_OPEN:
710  makepol(state, pushval, opaque);
711  break;
712  case PT_CLOSE:
713  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
714  return;
715  case PT_ERR:
716  default:
717  ereport(ERROR,
718  (errcode(ERRCODE_SYNTAX_ERROR),
719  errmsg("syntax error in tsquery: \"%s\"",
720  state->buffer)));
721  }
722  }
723 
724  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
725 }
signed short int16
Definition: c.h:312
static void makepol(TSQueryParserState state, PushFunction pushval, Datum opaque)
Definition: tsquery.c:680
Definition: tsquery.c:51
static void pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
Definition: tsquery.c:644
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OP_OR
Definition: ts_type.h:168
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3155
#define ereport(elevel, rest)
Definition: elog.h:122
#define STACKDEPTH
Definition: tsquery.c:635
signed char int8
Definition: c.h:311
Definition: tsquery.c:50
ts_tokenizer gettoken
Definition: tsquery.c:73
Definition: tsquery.c:52
Definition: tsquery.c:53
int errmsg(const char *fmt,...)
Definition: elog.c:797
ts_tokentype
Definition: tsquery.c:48
static void cleanOpStack(TSQueryParserState state, OperatorElement *stack, int *lenstack, int8 op)
Definition: tsquery.c:656

◆ parse_or_operator()

static bool parse_or_operator ( TSQueryParserState  pstate)
static

Definition at line 234 of file tsquery.c.

References TSQueryParserStateData::buf, TSQueryParserStateData::in_quotes, pg_mblen(), pg_strncasecmp(), t_isalpha(), t_isdigit(), t_iseq, and t_isspace().

Referenced by gettoken_query_websearch().

235 {
236  char *ptr = pstate->buf;
237 
238  if (pstate->in_quotes)
239  return false;
240 
241  /* it should begin with "OR" literal */
242  if (pg_strncasecmp(ptr, "or", 2) != 0)
243  return false;
244 
245  ptr += 2;
246 
247  /*
248  * it shouldn't be a part of any word but somewhere later it should be some
249  * operand
250  */
251  if (*ptr == '\0') /* no operand */
252  return false;
253 
254  /* it shouldn't be a part of any word */
255  if (t_iseq(ptr, '-') || t_iseq(ptr, '_') || t_isalpha(ptr) || t_isdigit(ptr))
256  return false;
257 
258  for(;;)
259  {
260  ptr += pg_mblen(ptr);
261 
262  if (*ptr == '\0') /* got end of string without operand */
263  return false;
264 
265  /*
266  * Suppose, we found an operand, but could be a not correct operand. So
267  * we still treat OR literal as operation with possibly incorrect
268  * operand and will not search it as lexeme
269  */
270  if (!t_isspace(ptr))
271  break;
272  }
273 
274  pstate->buf += 2;
275  return true;
276 }
int t_isdigit(const char *ptr)
Definition: ts_locale.c:25
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
int t_isspace(const char *ptr)
Definition: ts_locale.c:41
#define t_iseq(x, c)
Definition: ts_locale.h:45
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760
int t_isalpha(const char *ptr)
Definition: ts_locale.c:57

◆ parse_phrase_operator()

static bool parse_phrase_operator ( TSQueryParserState  pstate,
int16 distance 
)
static

Definition at line 155 of file tsquery.c.

References TSQueryParserStateData::buf, ereport, errcode(), errmsg(), ERROR, MAXENTRYPOS, t_isdigit(), and t_iseq.

Referenced by gettoken_query_standard().

156 {
157  enum
158  {
159  PHRASE_OPEN = 0,
160  PHRASE_DIST,
161  PHRASE_CLOSE,
162  PHRASE_FINISH
163  } state = PHRASE_OPEN;
164  char *ptr = pstate->buf;
165  char *endptr;
166  long l = 1; /* default distance */
167 
168  while (*ptr)
169  {
170  switch (state)
171  {
172  case PHRASE_OPEN:
173  if (t_iseq(ptr, '<'))
174  {
175  state = PHRASE_DIST;
176  ptr++;
177  }
178  else
179  return false;
180  break;
181 
182  case PHRASE_DIST:
183  if (t_iseq(ptr, '-'))
184  {
185  state = PHRASE_CLOSE;
186  ptr++;
187  continue;
188  }
189 
190  if (!t_isdigit(ptr))
191  return false;
192 
193  errno = 0;
194  l = strtol(ptr, &endptr, 10);
195  if (ptr == endptr)
196  return false;
197  else if (errno == ERANGE || l < 0 || l > MAXENTRYPOS)
198  ereport(ERROR,
199  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
200  errmsg("distance in phrase operator should not be greater than %d",
201  MAXENTRYPOS)));
202  else
203  {
204  state = PHRASE_CLOSE;
205  ptr = endptr;
206  }
207  break;
208 
209  case PHRASE_CLOSE:
210  if (t_iseq(ptr, '>'))
211  {
212  state = PHRASE_FINISH;
213  ptr++;
214  }
215  else
216  return false;
217  break;
218 
219  case PHRASE_FINISH:
220  *distance = (int16) l;
221  pstate->buf = ptr;
222  return true;
223  }
224  }
225 
226  return false;
227 }
signed short int16
Definition: c.h:312
int errcode(int sqlerrcode)
Definition: elog.c:575
int t_isdigit(const char *ptr)
Definition: ts_locale.c:25
#define ERROR
Definition: elog.h:43
#define t_iseq(x, c)
Definition: ts_locale.h:45
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: regguts.h:298
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define MAXENTRYPOS
Definition: ts_type.h:85

◆ parse_tsquery()

TSQuery parse_tsquery ( char *  buf,
PushFunction  pushval,
Datum  opaque,
int  flags 
)

Definition at line 811 of file tsquery.c.

References Assert, TSQueryParserStateData::buf, TSQueryParserStateData::buffer, cleanup_tsquery_stopwords(), close_tsvector_parser(), COMPUTESIZE, TSQueryParserStateData::count, TSQueryParserStateData::curop, elog, ereport, errcode(), errmsg(), ERROR, findoprnd(), GETOPERAND, GETQUERY, TSQueryParserStateData::gettoken, gettoken_query_plain(), gettoken_query_standard(), gettoken_query_websearch(), HDRSIZETQ, i, TSQueryParserStateData::in_quotes, init_tsvector_parser(), TSQueryParserStateData::lenop, lfirst, list_length(), makepol(), NIL, NOTICE, TSQueryParserStateData::op, P_TSQ_PLAIN, P_TSQ_WEB, P_TSV_IS_TSQUERY, P_TSV_IS_WEB, P_TSV_OPR_IS_DELIM, palloc(), palloc0(), pfree(), TSQueryParserStateData::polstr, QI_OPR, QI_VAL, QI_VALSTOP, SET_VARSIZE, TSQueryData::size, TSQueryParserStateData::state, TSQueryParserStateData::sumlen, TSQUERY_TOO_BIG, QueryItem::type, TSQueryParserStateData::valstate, and WAITFIRSTOPERAND.

Referenced by phraseto_tsquery_byid(), plainto_tsquery_byid(), to_tsquery_byid(), tsqueryin(), and websearch_to_tsquery_byid().

815 {
817  int i;
818  TSQuery query;
819  int commonlen;
820  QueryItem *ptr;
821  ListCell *cell;
822  bool needcleanup;
823  int tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
824 
825  /* plain should not be used with web */
826  Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
827 
828  /* select suitable tokenizer */
829  if (flags & P_TSQ_PLAIN)
830  state.gettoken = gettoken_query_plain;
831  else if (flags & P_TSQ_WEB)
832  {
833  state.gettoken = gettoken_query_websearch;
834  tsv_flags |= P_TSV_IS_WEB;
835  }
836  else
837  state.gettoken = gettoken_query_standard;
838 
839  /* init state */
840  state.buffer = buf;
841  state.buf = buf;
842  state.count = 0;
843  state.in_quotes = false;
844  state.state = WAITFIRSTOPERAND;
845  state.polstr = NIL;
846 
847  /* init value parser's state */
848  state.valstate = init_tsvector_parser(state.buffer, tsv_flags);
849 
850  /* init list of operand */
851  state.sumlen = 0;
852  state.lenop = 64;
853  state.curop = state.op = (char *) palloc(state.lenop);
854  *(state.curop) = '\0';
855 
856  /* parse query & make polish notation (postfix, but in reverse order) */
857  makepol(&state, pushval, opaque);
858 
859  close_tsvector_parser(state.valstate);
860 
861  if (list_length(state.polstr) == 0)
862  {
863  ereport(NOTICE,
864  (errmsg("text-search query doesn't contain lexemes: \"%s\"",
865  state.buffer)));
866  query = (TSQuery) palloc(HDRSIZETQ);
867  SET_VARSIZE(query, HDRSIZETQ);
868  query->size = 0;
869  return query;
870  }
871 
872  if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
873  ereport(ERROR,
874  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
875  errmsg("tsquery is too large")));
876  commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
877 
878  /* Pack the QueryItems in the final TSQuery struct to return to caller */
879  query = (TSQuery) palloc0(commonlen);
880  SET_VARSIZE(query, commonlen);
881  query->size = list_length(state.polstr);
882  ptr = GETQUERY(query);
883 
884  /* Copy QueryItems to TSQuery */
885  i = 0;
886  foreach(cell, state.polstr)
887  {
888  QueryItem *item = (QueryItem *) lfirst(cell);
889 
890  switch (item->type)
891  {
892  case QI_VAL:
893  memcpy(&ptr[i], item, sizeof(QueryOperand));
894  break;
895  case QI_VALSTOP:
896  ptr[i].type = QI_VALSTOP;
897  break;
898  case QI_OPR:
899  memcpy(&ptr[i], item, sizeof(QueryOperator));
900  break;
901  default:
902  elog(ERROR, "unrecognized QueryItem type: %d", item->type);
903  }
904  i++;
905  }
906 
907  /* Copy all the operand strings to TSQuery */
908  memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
909  pfree(state.op);
910 
911  /*
912  * Set left operand pointers for every operator. While we're at it,
913  * detect whether there are any QI_VALSTOP nodes.
914  */
915  findoprnd(ptr, query->size, &needcleanup);
916 
917  /*
918  * If there are QI_VALSTOP nodes, delete them and simplify the tree.
919  */
920  if (needcleanup)
921  query = cleanup_tsquery_stopwords(query);
922 
923  return query;
924 }
#define QI_VALSTOP
Definition: ts_type.h:136
#define NIL
Definition: pg_list.h:69
#define TSQUERY_TOO_BIG(size, lenofoperand)
Definition: ts_type.h:220
#define P_TSV_IS_TSQUERY
Definition: ts_utils.h:29
#define P_TSV_IS_WEB
Definition: ts_utils.h:30
static void makepol(TSQueryParserState state, PushFunction pushval, Datum opaque)
Definition: tsquery.c:680
void close_tsvector_parser(TSVectorParseState state)
static ts_tokentype gettoken_query_websearch(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:380
TSQueryData * TSQuery
Definition: ts_type.h:212
int errcode(int sqlerrcode)
Definition: elog.c:575
#define QI_VAL
Definition: ts_type.h:134
TSQuery cleanup_tsquery_stopwords(TSQuery in)
#define GETQUERY(x)
Definition: _int.h:142
#define GETOPERAND(x)
Definition: ltree.h:118
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define P_TSQ_PLAIN
Definition: ts_utils.h:61
#define ereport(elevel, rest)
Definition: elog.h:122
#define QI_OPR
Definition: ts_type.h:135
QueryItemType type
Definition: ts_type.h:195
void * palloc0(Size size)
Definition: mcxt.c:955
#define COMPUTESIZE(size)
Definition: _int.h:140
#define P_TSV_OPR_IS_DELIM
Definition: ts_utils.h:28
#define NOTICE
Definition: elog.h:37
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
TSVectorParseState init_tsvector_parser(char *input, int flags)
Definition: regguts.h:298
static int list_length(const List *l)
Definition: pg_list.h:89
#define P_TSQ_WEB
Definition: ts_utils.h:62
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 size
Definition: ts_type.h:208
int i
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:327
#define elog
Definition: elog.h:219
static ts_tokentype gettoken_query_plain(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:518
#define HDRSIZETQ
Definition: ts_type.h:214
static ts_tokentype gettoken_query_standard(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:279
static void findoprnd(QueryItem *ptr, int size, bool *needcleanup)
Definition: tsquery.c:786

◆ pushOperator()

void pushOperator ( TSQueryParserState  state,
int8  oper,
int16  distance 
)

Definition at line 539 of file tsquery.c.

References Assert, QueryOperator::distance, lcons(), OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, oper(), palloc0(), TSQueryParserStateData::polstr, QI_OPR, and QueryOperator::type.

Referenced by cleanOpStack(), and pushval_morph().

540 {
541  QueryOperator *tmp;
542 
543  Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
544 
545  tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
546  tmp->type = QI_OPR;
547  tmp->oper = oper;
548  tmp->distance = (oper == OP_PHRASE) ? distance : 0;
549  /* left is filled in later with findoprnd */
550 
551  state->polstr = lcons(tmp, state->polstr);
552 }
int16 distance
Definition: ts_type.h:183
#define OP_OR
Definition: ts_type.h:168
#define OP_AND
Definition: ts_type.h:167
#define QI_OPR
Definition: ts_type.h:135
void * palloc0(Size size)
Definition: mcxt.c:955
List * lcons(void *datum, List *list)
Definition: list.c:259
QueryItemType type
Definition: ts_type.h:181
#define Assert(condition)
Definition: c.h:699
#define OP_PHRASE
Definition: ts_type.h:169
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:377
#define OP_NOT
Definition: ts_type.h:166

◆ pushOpStack()

static void pushOpStack ( OperatorElement stack,
int *  lenstack,
int8  op,
int16  distance 
)
static

Definition at line 644 of file tsquery.c.

References OperatorElement::distance, elog, ERROR, TSQueryParserStateData::op, OperatorElement::op, and STACKDEPTH.

Referenced by makepol().

645 {
646  if (*lenstack == STACKDEPTH) /* internal error */
647  elog(ERROR, "tsquery stack too small");
648 
649  stack[*lenstack].op = op;
650  stack[*lenstack].distance = distance;
651 
652  (*lenstack)++;
653 }
#define ERROR
Definition: elog.h:43
int16 distance
Definition: tsquery.c:640
#define STACKDEPTH
Definition: tsquery.c:635
#define elog
Definition: elog.h:219

◆ pushStop()

void pushStop ( TSQueryParserState  state)

Definition at line 624 of file tsquery.c.

References lcons(), palloc0(), TSQueryParserStateData::polstr, QI_VALSTOP, and QueryOperand::type.

Referenced by gettoken_query_websearch(), and pushval_morph().

625 {
626  QueryOperand *tmp;
627 
628  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
629  tmp->type = QI_VALSTOP;
630 
631  state->polstr = lcons(tmp, state->polstr);
632 }
#define QI_VALSTOP
Definition: ts_type.h:136
void * palloc0(Size size)
Definition: mcxt.c:955
List * lcons(void *datum, List *list)
Definition: list.c:259
QueryItemType type
Definition: ts_type.h:145

◆ pushval_asis()

static void pushval_asis ( Datum  opaque,
TSQueryParserState  state,
char *  strval,
int  lenval,
int16  weight,
bool  prefix 
)
static

Definition at line 927 of file tsquery.c.

References pushValue().

Referenced by tsqueryin().

929 {
930  pushValue(state, strval, lenval, weight, prefix);
931 }
void pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:588

◆ pushValue()

void pushValue ( TSQueryParserState  state,
char *  strval,
int  lenval,
int16  weight,
bool  prefix 
)

Definition at line 588 of file tsquery.c.

References TSQueryParserStateData::buffer, COMP_LEGACY_CRC32, TSQueryParserStateData::curop, ereport, errcode(), errmsg(), ERROR, FIN_LEGACY_CRC32, INIT_LEGACY_CRC32, TSQueryParserStateData::lenop, MAXSTRLEN, TSQueryParserStateData::op, pushValue_internal(), repalloc(), and TSQueryParserStateData::sumlen.

Referenced by pushval_asis(), and pushval_morph().

589 {
590  pg_crc32 valcrc;
591 
592  if (lenval >= MAXSTRLEN)
593  ereport(ERROR,
594  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
595  errmsg("word is too long in tsquery: \"%s\"",
596  state->buffer)));
597 
598  INIT_LEGACY_CRC32(valcrc);
599  COMP_LEGACY_CRC32(valcrc, strval, lenval);
600  FIN_LEGACY_CRC32(valcrc);
601  pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
602 
603  /* append the value string to state.op, enlarging buffer if needed first */
604  while (state->curop - state->op + lenval + 1 >= state->lenop)
605  {
606  int used = state->curop - state->op;
607 
608  state->lenop *= 2;
609  state->op = (char *) repalloc((void *) state->op, state->lenop);
610  state->curop = state->op + used;
611  }
612  memcpy((void *) state->curop, (void *) strval, lenval);
613  state->curop += lenval;
614  *(state->curop) = '\0';
615  state->curop++;
616  state->sumlen += lenval + 1 /* \0 */ ;
617 }
#define INIT_LEGACY_CRC32(crc)
Definition: pg_crc.h:79
int errcode(int sqlerrcode)
Definition: elog.c:575
static void pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
Definition: tsquery.c:555
#define FIN_LEGACY_CRC32(crc)
Definition: pg_crc.h:80
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define COMP_LEGACY_CRC32(crc, data, len)
Definition: pg_crc.h:81
uint32 pg_crc32
Definition: pg_crc.h:37
#define MAXSTRLEN
Definition: ts_type.h:49

◆ pushValue_internal()

static void pushValue_internal ( TSQueryParserState  state,
pg_crc32  valcrc,
int  distance,
int  lenval,
int  weight,
bool  prefix 
)
static

Definition at line 555 of file tsquery.c.

References TSQueryParserStateData::buffer, QueryOperand::distance, ereport, errcode(), errmsg(), ERROR, lcons(), QueryOperand::length, MAXSTRLEN, MAXSTRPOS, palloc0(), TSQueryParserStateData::polstr, QueryOperand::prefix, QI_VAL, QueryOperand::type, QueryOperand::valcrc, and QueryOperand::weight.

Referenced by pushValue().

556 {
557  QueryOperand *tmp;
558 
559  if (distance >= MAXSTRPOS)
560  ereport(ERROR,
561  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
562  errmsg("value is too big in tsquery: \"%s\"",
563  state->buffer)));
564  if (lenval >= MAXSTRLEN)
565  ereport(ERROR,
566  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
567  errmsg("operand is too long in tsquery: \"%s\"",
568  state->buffer)));
569 
570  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
571  tmp->type = QI_VAL;
572  tmp->weight = weight;
573  tmp->prefix = prefix;
574  tmp->valcrc = (int32) valcrc;
575  tmp->length = lenval;
576  tmp->distance = distance;
577 
578  state->polstr = lcons(tmp, state->polstr);
579 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define QI_VAL
Definition: ts_type.h:134
uint32 distance
Definition: ts_type.h:158
#define MAXSTRPOS
Definition: ts_type.h:50
signed int int32
Definition: c.h:313
#define ERROR
Definition: elog.h:43
uint8 weight
Definition: ts_type.h:146
int32 valcrc
Definition: ts_type.h:151
#define ereport(elevel, rest)
Definition: elog.h:122
void * palloc0(Size size)
Definition: mcxt.c:955
List * lcons(void *datum, List *list)
Definition: list.c:259
uint32 length
Definition: ts_type.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
QueryItemType type
Definition: ts_type.h:145
bool prefix
Definition: ts_type.h:150
#define MAXSTRLEN
Definition: ts_type.h:49

◆ tsqueryin()

Datum tsqueryin ( PG_FUNCTION_ARGS  )

Definition at line 937 of file tsquery.c.

References parse_tsquery(), PG_GETARG_CSTRING, PG_RETURN_TSQUERY, PointerGetDatum, and pushval_asis().

938 {
939  char *in = PG_GETARG_CSTRING(0);
940 
942 }
#define PointerGetDatum(X)
Definition: postgres.h:539
#define PG_RETURN_TSQUERY(x)
Definition: ts_type.h:240
static void pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:927
TSQuery parse_tsquery(char *buf, PushFunction pushval, Datum opaque, int flags)
Definition: tsquery.c:811
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:247

◆ tsqueryout()

Datum tsqueryout ( PG_FUNCTION_ARGS  )

Definition at line 1126 of file tsquery.c.

References INFIX::buf, INFIX::buflen, INFIX::cur, INFIX::curpol, GETOPERAND, GETQUERY, infix(), INFIX::op, palloc(), PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_CSTRING, PG_RETURN_POINTER, and TSQueryData::size.

1127 {
1128  TSQuery query = PG_GETARG_TSQUERY(0);
1129  INFIX nrm;
1130 
1131  if (query->size == 0)
1132  {
1133  char *b = palloc(1);
1134 
1135  *b = '\0';
1136  PG_RETURN_POINTER(b);
1137  }
1138  nrm.curpol = GETQUERY(query);
1139  nrm.buflen = 32;
1140  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1141  *(nrm.cur) = '\0';
1142  nrm.op = GETOPERAND(query);
1143  infix(&nrm, -1 /* lowest priority */ , false);
1144 
1145  PG_FREE_IF_COPY(query, 0);
1146  PG_RETURN_CSTRING(nrm.buf);
1147 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:326
ITEM * curpol
Definition: _int_bool.c:551
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
char * op
Definition: ltxtquery_io.c:399
#define GETQUERY(x)
Definition: _int.h:142
#define GETOPERAND(x)
Definition: ltree.h:118
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:971
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:327
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:230
char * cur
Definition: _int_bool.c:553
void * palloc(Size size)
Definition: mcxt.c:924
int32 buflen
Definition: _int_bool.c:554
int32 size
Definition: ts_type.h:208
char * buf
Definition: _int_bool.c:552

◆ tsqueryrecv()

Datum tsqueryrecv ( PG_FUNCTION_ARGS  )

Definition at line 1206 of file tsquery.c.

References Assert, TSQueryParserStateData::buf, COMP_LEGACY_CRC32, QueryOperand::distance, QueryOperator::distance, elog, ERROR, FIN_LEGACY_CRC32, findoprnd(), GETOPERAND, GETQUERY, HDRSIZETQ, i, INIT_LEGACY_CRC32, QueryOperand::length, MaxAllocSize, MAXSTRLEN, MAXSTRPOS, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, oper(), palloc(), palloc0(), pfree(), PG_GETARG_POINTER, PG_RETURN_TSQUERY, pq_getmsgint(), pq_getmsgstring(), QueryOperand::prefix, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, repalloc(), SET_VARSIZE, QueryItem::type, val, QueryOperand::valcrc, and QueryOperand::weight.

1207 {
1209  TSQuery query;
1210  int i,
1211  len;
1212  QueryItem *item;
1213  int datalen;
1214  char *ptr;
1215  uint32 size;
1216  const char **operands;
1217  bool needcleanup;
1218 
1219  size = pq_getmsgint(buf, sizeof(uint32));
1220  if (size > (MaxAllocSize / sizeof(QueryItem)))
1221  elog(ERROR, "invalid size of tsquery");
1222 
1223  /* Allocate space to temporarily hold operand strings */
1224  operands = palloc(size * sizeof(char *));
1225 
1226  /* Allocate space for all the QueryItems. */
1227  len = HDRSIZETQ + sizeof(QueryItem) * size;
1228  query = (TSQuery) palloc0(len);
1229  query->size = size;
1230  item = GETQUERY(query);
1231 
1232  datalen = 0;
1233  for (i = 0; i < size; i++)
1234  {
1235  item->type = (int8) pq_getmsgint(buf, sizeof(int8));
1236 
1237  if (item->type == QI_VAL)
1238  {
1239  size_t val_len; /* length after recoding to server
1240  * encoding */
1241  uint8 weight;
1242  uint8 prefix;
1243  const char *val;
1244  pg_crc32 valcrc;
1245 
1246  weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
1247  prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
1248  val = pq_getmsgstring(buf);
1249  val_len = strlen(val);
1250 
1251  /* Sanity checks */
1252 
1253  if (weight > 0xF)
1254  elog(ERROR, "invalid tsquery: invalid weight bitmap");
1255 
1256  if (val_len > MAXSTRLEN)
1257  elog(ERROR, "invalid tsquery: operand too long");
1258 
1259  if (datalen > MAXSTRPOS)
1260  elog(ERROR, "invalid tsquery: total operand length exceeded");
1261 
1262  /* Looks valid. */
1263 
1264  INIT_LEGACY_CRC32(valcrc);
1265  COMP_LEGACY_CRC32(valcrc, val, val_len);
1266  FIN_LEGACY_CRC32(valcrc);
1267 
1268  item->qoperand.weight = weight;
1269  item->qoperand.prefix = (prefix) ? true : false;
1270  item->qoperand.valcrc = (int32) valcrc;
1271  item->qoperand.length = val_len;
1272  item->qoperand.distance = datalen;
1273 
1274  /*
1275  * Operand strings are copied to the final struct after this loop;
1276  * here we just collect them to an array
1277  */
1278  operands[i] = val;
1279 
1280  datalen += val_len + 1; /* + 1 for the '\0' terminator */
1281  }
1282  else if (item->type == QI_OPR)
1283  {
1284  int8 oper;
1285 
1286  oper = (int8) pq_getmsgint(buf, sizeof(int8));
1287  if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
1288  elog(ERROR, "invalid tsquery: unrecognized operator type %d",
1289  (int) oper);
1290  if (i == size - 1)
1291  elog(ERROR, "invalid pointer to right operand");
1292 
1293  item->qoperator.oper = oper;
1294  if (oper == OP_PHRASE)
1295  item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
1296  }
1297  else
1298  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1299 
1300  item++;
1301  }
1302 
1303  /* Enlarge buffer to make room for the operand values. */
1304  query = (TSQuery) repalloc(query, len + datalen);
1305  item = GETQUERY(query);
1306  ptr = GETOPERAND(query);
1307 
1308  /*
1309  * Fill in the left-pointers. Checks that the tree is well-formed as a
1310  * side-effect.
1311  */
1312  findoprnd(item, size, &needcleanup);
1313 
1314  /* Can't have found any QI_VALSTOP nodes */
1315  Assert(!needcleanup);
1316 
1317  /* Copy operands to output struct */
1318  for (i = 0; i < size; i++)
1319  {
1320  if (item->type == QI_VAL)
1321  {
1322  memcpy(ptr, operands[i], item->qoperand.length + 1);
1323  ptr += item->qoperand.length + 1;
1324  }
1325  item++;
1326  }
1327 
1328  pfree(operands);
1329 
1330  Assert(ptr - GETOPERAND(query) == datalen);
1331 
1332  SET_VARSIZE(query, len + datalen);
1333 
1334  PG_RETURN_TSQUERY(query);
1335 }
signed short int16
Definition: c.h:312
QueryOperator qoperator
Definition: ts_type.h:196
#define INIT_LEGACY_CRC32(crc)
Definition: pg_crc.h:79
const char * pq_getmsgstring(StringInfo msg)
Definition: pqformat.c:581
StringInfoData * StringInfo
Definition: stringinfo.h:43
unsigned char uint8
Definition: c.h:323
TSQueryData * TSQuery
Definition: ts_type.h:212
#define QI_VAL
Definition: ts_type.h:134
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:246
uint32 distance
Definition: ts_type.h:158
int16 distance
Definition: ts_type.h:183
#define MAXSTRPOS
Definition: ts_type.h:50
#define OP_OR
Definition: ts_type.h:168
#define GETQUERY(x)
Definition: _int.h:142
#define FIN_LEGACY_CRC32(crc)
Definition: pg_crc.h:80
signed int int32
Definition: c.h:313
#define GETOPERAND(x)
Definition: ltree.h:118
#define PG_RETURN_TSQUERY(x)
Definition: ts_type.h:240
#define OP_AND
Definition: ts_type.h:167
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
uint8 weight
Definition: ts_type.h:146
static char * buf
Definition: pg_test_fsync.c:67
int32 valcrc
Definition: ts_type.h:151
unsigned int uint32
Definition: c.h:325
#define MaxAllocSize
Definition: memutils.h:40
signed char int8
Definition: c.h:311
#define QI_OPR
Definition: ts_type.h:135
QueryItemType type
Definition: ts_type.h:195
void * palloc0(Size size)
Definition: mcxt.c:955
#define Assert(condition)
Definition: c.h:699
#define OP_PHRASE
Definition: ts_type.h:169
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
uint32 length
Definition: ts_type.h:158
void * palloc(Size size)
Definition: mcxt.c:924
#define COMP_LEGACY_CRC32(crc, data, len)
Definition: pg_crc.h:81
int i
bool prefix
Definition: ts_type.h:150
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:327
uint32 pg_crc32
Definition: pg_crc.h:37
#define elog
Definition: elog.h:219
QueryOperand qoperand
Definition: ts_type.h:197
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:377
long val
Definition: informix.c:689
#define HDRSIZETQ
Definition: ts_type.h:214
#define MAXSTRLEN
Definition: ts_type.h:49
static void findoprnd(QueryItem *ptr, int size, bool *needcleanup)
Definition: tsquery.c:786
#define OP_NOT
Definition: ts_type.h:166

◆ tsquerysend()

Datum tsquerysend ( PG_FUNCTION_ARGS  )

Definition at line 1168 of file tsquery.c.

References TSQueryParserStateData::buf, QueryOperand::distance, QueryOperator::distance, elog, ERROR, GETOPERAND, GETQUERY, i, OP_PHRASE, QueryOperator::oper, PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint16(), pq_sendint32(), pq_sendint8(), pq_sendstring(), QueryOperand::prefix, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, TSQueryData::size, QueryItem::type, and QueryOperand::weight.

1169 {
1170  TSQuery query = PG_GETARG_TSQUERY(0);
1172  int i;
1173  QueryItem *item = GETQUERY(query);
1174 
1175  pq_begintypsend(&buf);
1176 
1177  pq_sendint32(&buf, query->size);
1178  for (i = 0; i < query->size; i++)
1179  {
1180  pq_sendint8(&buf, item->type);
1181 
1182  switch (item->type)
1183  {
1184  case QI_VAL:
1185  pq_sendint8(&buf, item->qoperand.weight);
1186  pq_sendint8(&buf, item->qoperand.prefix);
1187  pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
1188  break;
1189  case QI_OPR:
1190  pq_sendint8(&buf, item->qoperator.oper);
1191  if (item->qoperator.oper == OP_PHRASE)
1192  pq_sendint16(&buf, item->qoperator.distance);
1193  break;
1194  default:
1195  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1196  }
1197  item++;
1198  }
1199 
1200  PG_FREE_IF_COPY(query, 0);
1201 
1203 }
QueryOperator qoperator
Definition: ts_type.h:196
static void pq_sendint32(StringInfo buf, int32 i)
Definition: pqformat.h:148
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
#define QI_VAL
Definition: ts_type.h:134
void pq_sendstring(StringInfo buf, const char *str)
Definition: pqformat.c:197
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:335
uint32 distance
Definition: ts_type.h:158
int16 distance
Definition: ts_type.h:183
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
#define GETQUERY(x)
Definition: _int.h:142
static void pq_sendint8(StringInfo buf, int8 i)
Definition: pqformat.h:132
#define GETOPERAND(x)
Definition: ltree.h:118
#define ERROR
Definition: elog.h:43
uint8 weight
Definition: ts_type.h:146
static char * buf
Definition: pg_test_fsync.c:67
#define QI_OPR
Definition: ts_type.h:135
QueryItemType type
Definition: ts_type.h:195
#define OP_PHRASE
Definition: ts_type.h:169
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:230
static void pq_sendint16(StringInfo buf, int16 i)
Definition: pqformat.h:140
int32 size
Definition: ts_type.h:208
int i
bool prefix
Definition: ts_type.h:150
#define elog
Definition: elog.h:219
QueryOperand qoperand
Definition: ts_type.h:197

◆ tsquerytree()

Datum tsquerytree ( PG_FUNCTION_ARGS  )

Definition at line 1342 of file tsquery.c.

References INFIX::buf, INFIX::buflen, clean_NOT(), cstring_to_text(), cstring_to_text_with_len(), INFIX::cur, INFIX::curpol, GETOPERAND, GETQUERY, infix(), INFIX::op, palloc(), pfree(), PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_POINTER, PG_RETURN_TEXT_P, SET_VARSIZE, TSQueryData::size, and VARHDRSZ.

1343 {
1344  TSQuery query = PG_GETARG_TSQUERY(0);
1345  INFIX nrm;
1346  text *res;
1347  QueryItem *q;
1348  int len;
1349 
1350  if (query->size == 0)
1351  {
1352  res = (text *) palloc(VARHDRSZ);
1353  SET_VARSIZE(res, VARHDRSZ);
1354  PG_RETURN_POINTER(res);
1355  }
1356 
1357  q = clean_NOT(GETQUERY(query), &len);
1358 
1359  if (!q)
1360  {
1361  res = cstring_to_text("T");
1362  }
1363  else
1364  {
1365  nrm.curpol = q;
1366  nrm.buflen = 32;
1367  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1368  *(nrm.cur) = '\0';
1369  nrm.op = GETOPERAND(query);
1370  infix(&nrm, -1, false);
1371  res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
1372  pfree(q);
1373  }
1374 
1375  PG_FREE_IF_COPY(query, 0);
1376 
1377  PG_RETURN_TEXT_P(res);
1378 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:326
ITEM * curpol
Definition: _int_bool.c:551
#define VARHDRSZ
Definition: c.h:522
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
char * op
Definition: ltxtquery_io.c:399
#define GETQUERY(x)
Definition: _int.h:142
#define GETOPERAND(x)
Definition: ltree.h:118
void pfree(void *pointer)
Definition: mcxt.c:1031
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:971
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:161
QueryItem * clean_NOT(QueryItem *ptr, int *len)
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:336
text * cstring_to_text(const char *s)
Definition: varlena.c:149
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:230
char * cur
Definition: _int_bool.c:553
void * palloc(Size size)
Definition: mcxt.c:924
int32 buflen
Definition: _int_bool.c:554
int32 size
Definition: ts_type.h:208
Definition: c.h:516
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:327
char * buf
Definition: _int_bool.c:552

Variable Documentation

◆ tsearch_op_priority

const int tsearch_op_priority[OP_COUNT]
Initial value:
=
{
4,
2,
1,
3
}

Definition at line 27 of file tsquery.c.