PostgreSQL Source Code  git master
tsquery.c File Reference
#include "postgres.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_type.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:68
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182

Definition at line 928 of file tsquery.c.

Referenced by infix().

◆ STACKDEPTH

#define STACKDEPTH   32

Definition at line 607 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 628 of file tsquery.c.

References OP_NOT, OP_PRIORITY, and pushOperator().

Referenced by makepol().

630 {
631  int opPriority = OP_PRIORITY(op);
632 
633  while (*lenstack)
634  {
635  /* NOT is right associative unlike to others */
636  if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
637  (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
638  break;
639 
640  (*lenstack)--;
641  pushOperator(state, stack[*lenstack].op,
642  stack[*lenstack].distance);
643  }
644 }
#define OP_PRIORITY(x)
Definition: ts_type.h:175
void pushOperator(TSQueryParserState state, int8 oper, int16 distance)
Definition: tsquery.c:511
#define OP_NOT
Definition: ts_type.h:166

◆ findoprnd()

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

Definition at line 758 of file tsquery.c.

References elog, ERROR, and findoprnd_recurse().

Referenced by parse_tsquery(), and tsqueryrecv().

759 {
760  uint32 pos;
761 
762  *needcleanup = false;
763  pos = 0;
764  findoprnd_recurse(ptr, &pos, size, needcleanup);
765 
766  if (pos != size)
767  elog(ERROR, "malformed tsquery: extra nodes");
768 }
#define ERROR
Definition: elog.h:46
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:700
unsigned int uint32
Definition: c.h:441
#define elog(elevel,...)
Definition: elog.h:232

◆ findoprnd_recurse()

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

Definition at line 700 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().

701 {
702  /* since this function recurses, it could be driven to stack overflow. */
704 
705  if (*pos >= nnodes)
706  elog(ERROR, "malformed tsquery: operand not found");
707 
708  if (ptr[*pos].type == QI_VAL)
709  {
710  (*pos)++;
711  }
712  else if (ptr[*pos].type == QI_VALSTOP)
713  {
714  *needcleanup = true; /* we'll have to remove stop words */
715  (*pos)++;
716  }
717  else
718  {
719  Assert(ptr[*pos].type == QI_OPR);
720 
721  if (ptr[*pos].qoperator.oper == OP_NOT)
722  {
723  ptr[*pos].qoperator.left = 1; /* fixed offset */
724  (*pos)++;
725 
726  /* process the only argument */
727  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
728  }
729  else
730  {
731  QueryOperator *curitem = &ptr[*pos].qoperator;
732  int tmp = *pos; /* save current position */
733 
734  Assert(curitem->oper == OP_AND ||
735  curitem->oper == OP_OR ||
736  curitem->oper == OP_PHRASE);
737 
738  (*pos)++;
739 
740  /* process RIGHT argument */
741  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
742 
743  curitem->left = *pos - tmp; /* set LEFT arg's offset */
744 
745  /* process LEFT argument */
746  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
747  }
748  }
749 }
#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:46
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:700
void check_stack_depth(void)
Definition: postgres.c:3469
#define QI_OPR
Definition: ts_type.h:135
#define Assert(condition)
Definition: c.h:804
#define OP_PHRASE
Definition: ts_type.h:169
uint32 left
Definition: ts_type.h:184
#define elog(elevel,...)
Definition: elog.h:232
#define OP_NOT
Definition: ts_type.h:166

◆ get_modifiers()

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

Definition at line 103 of file tsquery.c.

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

Referenced by gettoken_query_standard().

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

◆ 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 490 of file tsquery.c.

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

Referenced by parse_tsquery().

493 {
494  *weight = 0;
495  *prefix = false;
496 
497  if (*state->buf == '\0')
498  return PT_END;
499 
500  *strval = state->buf;
501  *lenval = strlen(state->buf);
502  state->buf += *lenval;
503  state->count++;
504  return PT_VAL;
505 }
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 275 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().

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

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

Referenced by parse_tsquery().

382 {
383  *weight = 0;
384  *prefix = false;
385 
386  while (true)
387  {
388  switch (state->state)
389  {
390  case WAITFIRSTOPERAND:
391  case WAITOPERAND:
392  if (t_iseq(state->buf, '-'))
393  {
394  state->buf++;
395  state->state = WAITOPERAND;
396 
397  *operator = OP_NOT;
398  return PT_OPR;
399  }
400  else if (t_iseq(state->buf, '"'))
401  {
402  /* Everything in quotes is processed as a single token */
403 
404  /* skip opening quote */
405  state->buf++;
406  *strval = state->buf;
407 
408  /* iterate to the closing quote or end of the string */
409  while (*state->buf != '\0' && !t_iseq(state->buf, '"'))
410  state->buf++;
411  *lenval = state->buf - *strval;
412 
413  /* skip closing quote if not end of the string */
414  if (*state->buf != '\0')
415  state->buf++;
416 
417  state->state = WAITOPERATOR;
418  state->count++;
419  return PT_VAL;
420  }
421  else if (ISOPERATOR(state->buf))
422  {
423  /* or else gettoken_tsvector() will raise an error */
424  state->buf++;
425  state->state = WAITOPERAND;
426  continue;
427  }
428  else if (!t_isspace(state->buf))
429  {
430  /*
431  * We rely on the tsvector parser to parse the value for
432  * us
433  */
434  reset_tsvector_parser(state->valstate, state->buf);
435  if (gettoken_tsvector(state->valstate, strval, lenval,
436  NULL, NULL, &state->buf))
437  {
438  state->state = WAITOPERATOR;
439  return PT_VAL;
440  }
441  else if (state->state == WAITFIRSTOPERAND)
442  {
443  return PT_END;
444  }
445  else
446  {
447  /* finally, we have to provide an operand */
448  pushStop(state);
449  return PT_END;
450  }
451  }
452  break;
453 
454  case WAITOPERATOR:
455  if (t_iseq(state->buf, '"'))
456  {
457  /*
458  * put implicit AND after an operand and handle this quote
459  * in WAITOPERAND
460  */
461  state->state = WAITOPERAND;
462  *operator = OP_AND;
463  return PT_OPR;
464  }
465  else if (parse_or_operator(state))
466  {
467  state->state = WAITOPERAND;
468  *operator = OP_OR;
469  return PT_OPR;
470  }
471  else if (*state->buf == '\0')
472  {
473  return PT_END;
474  }
475  else if (!t_isspace(state->buf))
476  {
477  /* put implicit AND after an operand */
478  *operator = OP_AND;
479  state->state = WAITOPERAND;
480  return PT_OPR;
481  }
482  break;
483  }
484 
485  state->buf += pg_mblen(state->buf);
486  }
487 }
bool gettoken_tsvector(TSVectorParseState state, char **strval, int *lenval, WordEntryPos **pos_ptr, int *poslen, char **endptr)
TSVectorParseState valstate
Definition: tsquery.c:95
#define OP_OR
Definition: ts_type.h:168
#define ISOPERATOR(x)
Definition: ltree.h:153
#define OP_AND
Definition: ts_type.h:167
void pushStop(TSQueryParserState state)
Definition: tsquery.c:596
int t_isspace(const char *ptr)
Definition: ts_locale.c:53
#define t_iseq(x, c)
Definition: ts_locale.h:46
ts_parserstate state
Definition: tsquery.c:80
Definition: tsquery.c:50
void reset_tsvector_parser(TSVectorParseState state, char *input)
static bool parse_or_operator(TSQueryParserState pstate)
Definition: tsquery.c:233
int pg_mblen(const char *mbstr)
Definition: mbutils.c:966
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 942 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, sprintf, t_iseq, ITEM::type, and QueryOperand::weight.

Referenced by tsqueryout(), and tsquerytree().

943 {
944  /* since this function recurses, it could be driven to stack overflow. */
946 
947  if (in->curpol->type == QI_VAL)
948  {
949  QueryOperand *curpol = &in->curpol->qoperand;
950  char *op = in->op + curpol->distance;
951  int clen;
952 
953  RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
954  *(in->cur) = '\'';
955  in->cur++;
956  while (*op)
957  {
958  if (t_iseq(op, '\''))
959  {
960  *(in->cur) = '\'';
961  in->cur++;
962  }
963  else if (t_iseq(op, '\\'))
964  {
965  *(in->cur) = '\\';
966  in->cur++;
967  }
968  COPYCHAR(in->cur, op);
969 
970  clen = pg_mblen(op);
971  op += clen;
972  in->cur += clen;
973  }
974  *(in->cur) = '\'';
975  in->cur++;
976  if (curpol->weight || curpol->prefix)
977  {
978  *(in->cur) = ':';
979  in->cur++;
980  if (curpol->prefix)
981  {
982  *(in->cur) = '*';
983  in->cur++;
984  }
985  if (curpol->weight & (1 << 3))
986  {
987  *(in->cur) = 'A';
988  in->cur++;
989  }
990  if (curpol->weight & (1 << 2))
991  {
992  *(in->cur) = 'B';
993  in->cur++;
994  }
995  if (curpol->weight & (1 << 1))
996  {
997  *(in->cur) = 'C';
998  in->cur++;
999  }
1000  if (curpol->weight & 1)
1001  {
1002  *(in->cur) = 'D';
1003  in->cur++;
1004  }
1005  }
1006  *(in->cur) = '\0';
1007  in->curpol++;
1008  }
1009  else if (in->curpol->qoperator.oper == OP_NOT)
1010  {
1011  int priority = QO_PRIORITY(in->curpol);
1012 
1013  if (priority < parentPriority)
1014  {
1015  RESIZEBUF(in, 2);
1016  sprintf(in->cur, "( ");
1017  in->cur = strchr(in->cur, '\0');
1018  }
1019  RESIZEBUF(in, 1);
1020  *(in->cur) = '!';
1021  in->cur++;
1022  *(in->cur) = '\0';
1023  in->curpol++;
1024 
1025  infix(in, priority, false);
1026  if (priority < parentPriority)
1027  {
1028  RESIZEBUF(in, 2);
1029  sprintf(in->cur, " )");
1030  in->cur = strchr(in->cur, '\0');
1031  }
1032  }
1033  else
1034  {
1035  int8 op = in->curpol->qoperator.oper;
1036  int priority = QO_PRIORITY(in->curpol);
1037  int16 distance = in->curpol->qoperator.distance;
1038  INFIX nrm;
1039  bool needParenthesis = false;
1040 
1041  in->curpol++;
1042  if (priority < parentPriority ||
1043  /* phrase operator depends on order */
1044  (op == OP_PHRASE && rightPhraseOp))
1045  {
1046  needParenthesis = true;
1047  RESIZEBUF(in, 2);
1048  sprintf(in->cur, "( ");
1049  in->cur = strchr(in->cur, '\0');
1050  }
1051 
1052  nrm.curpol = in->curpol;
1053  nrm.op = in->op;
1054  nrm.buflen = 16;
1055  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1056 
1057  /* get right operand */
1058  infix(&nrm, priority, (op == OP_PHRASE));
1059 
1060  /* get & print left operand */
1061  in->curpol = nrm.curpol;
1062  infix(in, priority, false);
1063 
1064  /* print operator & right operand */
1065  RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
1066  switch (op)
1067  {
1068  case OP_OR:
1069  sprintf(in->cur, " | %s", nrm.buf);
1070  break;
1071  case OP_AND:
1072  sprintf(in->cur, " & %s", nrm.buf);
1073  break;
1074  case OP_PHRASE:
1075  if (distance != 1)
1076  sprintf(in->cur, " <%d> %s", distance, nrm.buf);
1077  else
1078  sprintf(in->cur, " <-> %s", nrm.buf);
1079  break;
1080  default:
1081  /* OP_NOT is handled in above if-branch */
1082  elog(ERROR, "unrecognized operator type: %d", op);
1083  }
1084  in->cur = strchr(in->cur, '\0');
1085  pfree(nrm.buf);
1086 
1087  if (needParenthesis)
1088  {
1089  RESIZEBUF(in, 2);
1090  sprintf(in->cur, " )");
1091  in->cur = strchr(in->cur, '\0');
1092  }
1093  }
1094 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:48
signed short int16
Definition: c.h:428
#define QO_PRIORITY(x)
Definition: ts_type.h:177
ITEM * curpol
Definition: _int_bool.c:550
char * op
Definition: ltxtquery_io.c:425
#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:928
int16 type
Definition: _int.h:142
#define sprintf
Definition: port.h:218
#define OP_AND
Definition: ts_type.h:167
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:942
uint8 weight
Definition: ts_type.h:146
void check_stack_depth(void)
Definition: postgres.c:3469
#define t_iseq(x, c)
Definition: ts_locale.h:46
signed char int8
Definition: c.h:427
#define OP_PHRASE
Definition: ts_type.h:169
int pg_mblen(const char *mbstr)
Definition: mbutils.c:966
int pg_database_encoding_max_length(void)
Definition: mbutils.c:1495
uint32 length
Definition: ts_type.h:158
char * cur
Definition: _int_bool.c:552
void * palloc(Size size)
Definition: mcxt.c:1062
int32 buflen
Definition: _int_bool.c:553
#define elog(elevel,...)
Definition: elog.h:232
bool prefix
Definition: ts_type.h:150
uint16 distance
Definition: ltree.h:132
char * buf
Definition: _int_bool.c:551
#define OP_NOT
Definition: ts_type.h:166

◆ makepol()

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

Definition at line 652 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().

655 {
656  int8 operator = 0;
658  int lenval = 0;
659  char *strval = NULL;
660  OperatorElement opstack[STACKDEPTH];
661  int lenstack = 0;
662  int16 weight = 0;
663  bool prefix;
664 
665  /* since this function recurses, it could be driven to stack overflow */
667 
668  while ((type = state->gettoken(state, &operator,
669  &lenval, &strval,
670  &weight, &prefix)) != PT_END)
671  {
672  switch (type)
673  {
674  case PT_VAL:
675  pushval(opaque, state, strval, lenval, weight, prefix);
676  break;
677  case PT_OPR:
678  cleanOpStack(state, opstack, &lenstack, operator);
679  pushOpStack(opstack, &lenstack, operator, weight);
680  break;
681  case PT_OPEN:
682  makepol(state, pushval, opaque);
683  break;
684  case PT_CLOSE:
685  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
686  return;
687  case PT_ERR:
688  default:
689  ereport(ERROR,
690  (errcode(ERRCODE_SYNTAX_ERROR),
691  errmsg("syntax error in tsquery: \"%s\"",
692  state->buffer)));
693  }
694  }
695 
696  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
697 }
signed short int16
Definition: c.h:428
static void makepol(TSQueryParserState state, PushFunction pushval, Datum opaque)
Definition: tsquery.c:652
Definition: tsquery.c:51
static void pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
Definition: tsquery.c:616
int errcode(int sqlerrcode)
Definition: elog.c:698
#define OP_OR
Definition: ts_type.h:168
#define ERROR
Definition: elog.h:46
void check_stack_depth(void)
Definition: postgres.c:3469
#define STACKDEPTH
Definition: tsquery.c:607
signed char int8
Definition: c.h:427
Definition: tsquery.c:50
ts_tokenizer gettoken
Definition: tsquery.c:73
#define ereport(elevel,...)
Definition: elog.h:157
Definition: tsquery.c:52
Definition: tsquery.c:53
int errmsg(const char *fmt,...)
Definition: elog.c:909
ts_tokentype
Definition: tsquery.c:48
static void cleanOpStack(TSQueryParserState state, OperatorElement *stack, int *lenstack, int8 op)
Definition: tsquery.c:628

◆ parse_or_operator()

static bool parse_or_operator ( TSQueryParserState  pstate)
static

Definition at line 233 of file tsquery.c.

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

Referenced by gettoken_query_websearch().

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

◆ parse_phrase_operator()

static bool parse_phrase_operator ( TSQueryParserState  pstate,
int16 distance 
)
static

Definition at line 154 of file tsquery.c.

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

Referenced by gettoken_query_standard().

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

◆ parse_tsquery()

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

Definition at line 783 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, 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().

787 {
789  int i;
790  TSQuery query;
791  int commonlen;
792  QueryItem *ptr;
793  ListCell *cell;
794  bool needcleanup;
795  int tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
796 
797  /* plain should not be used with web */
798  Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
799 
800  /* select suitable tokenizer */
801  if (flags & P_TSQ_PLAIN)
802  state.gettoken = gettoken_query_plain;
803  else if (flags & P_TSQ_WEB)
804  {
805  state.gettoken = gettoken_query_websearch;
806  tsv_flags |= P_TSV_IS_WEB;
807  }
808  else
809  state.gettoken = gettoken_query_standard;
810 
811  /* init state */
812  state.buffer = buf;
813  state.buf = buf;
814  state.count = 0;
815  state.state = WAITFIRSTOPERAND;
816  state.polstr = NIL;
817 
818  /* init value parser's state */
819  state.valstate = init_tsvector_parser(state.buffer, tsv_flags);
820 
821  /* init list of operand */
822  state.sumlen = 0;
823  state.lenop = 64;
824  state.curop = state.op = (char *) palloc(state.lenop);
825  *(state.curop) = '\0';
826 
827  /* parse query & make polish notation (postfix, but in reverse order) */
828  makepol(&state, pushval, opaque);
829 
830  close_tsvector_parser(state.valstate);
831 
832  if (list_length(state.polstr) == 0)
833  {
834  ereport(NOTICE,
835  (errmsg("text-search query doesn't contain lexemes: \"%s\"",
836  state.buffer)));
837  query = (TSQuery) palloc(HDRSIZETQ);
838  SET_VARSIZE(query, HDRSIZETQ);
839  query->size = 0;
840  return query;
841  }
842 
843  if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
844  ereport(ERROR,
845  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
846  errmsg("tsquery is too large")));
847  commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
848 
849  /* Pack the QueryItems in the final TSQuery struct to return to caller */
850  query = (TSQuery) palloc0(commonlen);
851  SET_VARSIZE(query, commonlen);
852  query->size = list_length(state.polstr);
853  ptr = GETQUERY(query);
854 
855  /* Copy QueryItems to TSQuery */
856  i = 0;
857  foreach(cell, state.polstr)
858  {
859  QueryItem *item = (QueryItem *) lfirst(cell);
860 
861  switch (item->type)
862  {
863  case QI_VAL:
864  memcpy(&ptr[i], item, sizeof(QueryOperand));
865  break;
866  case QI_VALSTOP:
867  ptr[i].type = QI_VALSTOP;
868  break;
869  case QI_OPR:
870  memcpy(&ptr[i], item, sizeof(QueryOperator));
871  break;
872  default:
873  elog(ERROR, "unrecognized QueryItem type: %d", item->type);
874  }
875  i++;
876  }
877 
878  /* Copy all the operand strings to TSQuery */
879  memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
880  pfree(state.op);
881 
882  /*
883  * Set left operand pointers for every operator. While we're at it,
884  * detect whether there are any QI_VALSTOP nodes.
885  */
886  findoprnd(ptr, query->size, &needcleanup);
887 
888  /*
889  * If there are QI_VALSTOP nodes, delete them and simplify the tree.
890  */
891  if (needcleanup)
892  query = cleanup_tsquery_stopwords(query);
893 
894  return query;
895 }
#define QI_VALSTOP
Definition: ts_type.h:136
#define NIL
Definition: pg_list.h:65
#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:652
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:379
TSQueryData * TSQuery
Definition: ts_type.h:212
int errcode(int sqlerrcode)
Definition: elog.c:698
#define QI_VAL
Definition: ts_type.h:134
TSQuery cleanup_tsquery_stopwords(TSQuery in)
#define GETQUERY(x)
Definition: _int.h:157
#define GETOPERAND(x)
Definition: ltree.h:151
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
static char * buf
Definition: pg_test_fsync.c:68
#define P_TSQ_PLAIN
Definition: ts_utils.h:61
#define QI_OPR
Definition: ts_type.h:135
QueryItemType type
Definition: ts_type.h:195
void * palloc0(Size size)
Definition: mcxt.c:1093
#define COMPUTESIZE(size)
Definition: _int.h:155
#define P_TSV_OPR_IS_DELIM
Definition: ts_utils.h:28
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
TSVectorParseState init_tsvector_parser(char *input, int flags)
Definition: regguts.h:317
static int list_length(const List *l)
Definition: pg_list.h:149
#define P_TSQ_WEB
Definition: ts_utils.h:62
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int32 size
Definition: ts_type.h:208
#define elog(elevel,...)
Definition: elog.h:232
int i
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
static ts_tokentype gettoken_query_plain(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:490
#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:275
static void findoprnd(QueryItem *ptr, int size, bool *needcleanup)
Definition: tsquery.c:758

◆ pushOperator()

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

Definition at line 511 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().

512 {
513  QueryOperator *tmp;
514 
515  Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
516 
517  tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
518  tmp->type = QI_OPR;
519  tmp->oper = oper;
520  tmp->distance = (oper == OP_PHRASE) ? distance : 0;
521  /* left is filled in later with findoprnd */
522 
523  state->polstr = lcons(tmp, state->polstr);
524 }
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:1093
List * lcons(void *datum, List *list)
Definition: list.c:468
QueryItemType type
Definition: ts_type.h:181
#define Assert(condition)
Definition: c.h:804
#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:382
#define OP_NOT
Definition: ts_type.h:166

◆ pushOpStack()

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

Definition at line 616 of file tsquery.c.

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

Referenced by makepol().

617 {
618  if (*lenstack == STACKDEPTH) /* internal error */
619  elog(ERROR, "tsquery stack too small");
620 
621  stack[*lenstack].op = op;
622  stack[*lenstack].distance = distance;
623 
624  (*lenstack)++;
625 }
#define ERROR
Definition: elog.h:46
int16 distance
Definition: tsquery.c:612
#define STACKDEPTH
Definition: tsquery.c:607
#define elog(elevel,...)
Definition: elog.h:232

◆ pushStop()

void pushStop ( TSQueryParserState  state)

Definition at line 596 of file tsquery.c.

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

Referenced by gettoken_query_websearch(), and pushval_morph().

597 {
598  QueryOperand *tmp;
599 
600  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
601  tmp->type = QI_VALSTOP;
602 
603  state->polstr = lcons(tmp, state->polstr);
604 }
#define QI_VALSTOP
Definition: ts_type.h:136
void * palloc0(Size size)
Definition: mcxt.c:1093
List * lcons(void *datum, List *list)
Definition: list.c:468
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 898 of file tsquery.c.

References pushValue().

Referenced by tsqueryin().

900 {
901  pushValue(state, strval, lenval, weight, prefix);
902 }
void pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:560

◆ pushValue()

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

Definition at line 560 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().

561 {
562  pg_crc32 valcrc;
563 
564  if (lenval >= MAXSTRLEN)
565  ereport(ERROR,
566  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
567  errmsg("word is too long in tsquery: \"%s\"",
568  state->buffer)));
569 
570  INIT_LEGACY_CRC32(valcrc);
571  COMP_LEGACY_CRC32(valcrc, strval, lenval);
572  FIN_LEGACY_CRC32(valcrc);
573  pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
574 
575  /* append the value string to state.op, enlarging buffer if needed first */
576  while (state->curop - state->op + lenval + 1 >= state->lenop)
577  {
578  int used = state->curop - state->op;
579 
580  state->lenop *= 2;
581  state->op = (char *) repalloc((void *) state->op, state->lenop);
582  state->curop = state->op + used;
583  }
584  memcpy((void *) state->curop, (void *) strval, lenval);
585  state->curop += lenval;
586  *(state->curop) = '\0';
587  state->curop++;
588  state->sumlen += lenval + 1 /* \0 */ ;
589 }
#define INIT_LEGACY_CRC32(crc)
Definition: pg_crc.h:79
int errcode(int sqlerrcode)
Definition: elog.c:698
static void pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
Definition: tsquery.c:527
#define FIN_LEGACY_CRC32(crc)
Definition: pg_crc.h:80
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
int errmsg(const char *fmt,...)
Definition: elog.c:909
#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 527 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().

528 {
529  QueryOperand *tmp;
530 
531  if (distance >= MAXSTRPOS)
532  ereport(ERROR,
533  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
534  errmsg("value is too big in tsquery: \"%s\"",
535  state->buffer)));
536  if (lenval >= MAXSTRLEN)
537  ereport(ERROR,
538  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
539  errmsg("operand is too long in tsquery: \"%s\"",
540  state->buffer)));
541 
542  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
543  tmp->type = QI_VAL;
544  tmp->weight = weight;
545  tmp->prefix = prefix;
546  tmp->valcrc = (int32) valcrc;
547  tmp->length = lenval;
548  tmp->distance = distance;
549 
550  state->polstr = lcons(tmp, state->polstr);
551 }
int errcode(int sqlerrcode)
Definition: elog.c:698
#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:429
#define ERROR
Definition: elog.h:46
uint8 weight
Definition: ts_type.h:146
int32 valcrc
Definition: ts_type.h:151
void * palloc0(Size size)
Definition: mcxt.c:1093
#define ereport(elevel,...)
Definition: elog.h:157
List * lcons(void *datum, List *list)
Definition: list.c:468
uint32 length
Definition: ts_type.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:909
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 908 of file tsquery.c.

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

909 {
910  char *in = PG_GETARG_CSTRING(0);
911 
913 }
#define PointerGetDatum(X)
Definition: postgres.h:600
#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:898
TSQuery parse_tsquery(char *buf, PushFunction pushval, Datum opaque, int flags)
Definition: tsquery.c:783
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277

◆ tsqueryout()

Datum tsqueryout ( PG_FUNCTION_ARGS  )

Definition at line 1097 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.

1098 {
1099  TSQuery query = PG_GETARG_TSQUERY(0);
1100  INFIX nrm;
1101 
1102  if (query->size == 0)
1103  {
1104  char *b = palloc(1);
1105 
1106  *b = '\0';
1107  PG_RETURN_POINTER(b);
1108  }
1109  nrm.curpol = GETQUERY(query);
1110  nrm.buflen = 32;
1111  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1112  *(nrm.cur) = '\0';
1113  nrm.op = GETOPERAND(query);
1114  infix(&nrm, -1 /* lowest priority */ , false);
1115 
1116  PG_FREE_IF_COPY(query, 0);
1117  PG_RETURN_CSTRING(nrm.buf);
1118 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
ITEM * curpol
Definition: _int_bool.c:550
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
char * op
Definition: ltxtquery_io.c:425
#define GETQUERY(x)
Definition: _int.h:157
#define GETOPERAND(x)
Definition: ltree.h:151
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:942
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
char * cur
Definition: _int_bool.c:552
void * palloc(Size size)
Definition: mcxt.c:1062
int32 buflen
Definition: _int_bool.c:553
int32 size
Definition: ts_type.h:208
char * buf
Definition: _int_bool.c:551

◆ tsqueryrecv()

Datum tsqueryrecv ( PG_FUNCTION_ARGS  )

Definition at line 1177 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.

1178 {
1180  TSQuery query;
1181  int i,
1182  len;
1183  QueryItem *item;
1184  int datalen;
1185  char *ptr;
1186  uint32 size;
1187  const char **operands;
1188  bool needcleanup;
1189 
1190  size = pq_getmsgint(buf, sizeof(uint32));
1191  if (size > (MaxAllocSize / sizeof(QueryItem)))
1192  elog(ERROR, "invalid size of tsquery");
1193 
1194  /* Allocate space to temporarily hold operand strings */
1195  operands = palloc(size * sizeof(char *));
1196 
1197  /* Allocate space for all the QueryItems. */
1198  len = HDRSIZETQ + sizeof(QueryItem) * size;
1199  query = (TSQuery) palloc0(len);
1200  query->size = size;
1201  item = GETQUERY(query);
1202 
1203  datalen = 0;
1204  for (i = 0; i < size; i++)
1205  {
1206  item->type = (int8) pq_getmsgint(buf, sizeof(int8));
1207 
1208  if (item->type == QI_VAL)
1209  {
1210  size_t val_len; /* length after recoding to server
1211  * encoding */
1212  uint8 weight;
1213  uint8 prefix;
1214  const char *val;
1215  pg_crc32 valcrc;
1216 
1217  weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
1218  prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
1219  val = pq_getmsgstring(buf);
1220  val_len = strlen(val);
1221 
1222  /* Sanity checks */
1223 
1224  if (weight > 0xF)
1225  elog(ERROR, "invalid tsquery: invalid weight bitmap");
1226 
1227  if (val_len > MAXSTRLEN)
1228  elog(ERROR, "invalid tsquery: operand too long");
1229 
1230  if (datalen > MAXSTRPOS)
1231  elog(ERROR, "invalid tsquery: total operand length exceeded");
1232 
1233  /* Looks valid. */
1234 
1235  INIT_LEGACY_CRC32(valcrc);
1236  COMP_LEGACY_CRC32(valcrc, val, val_len);
1237  FIN_LEGACY_CRC32(valcrc);
1238 
1239  item->qoperand.weight = weight;
1240  item->qoperand.prefix = (prefix) ? true : false;
1241  item->qoperand.valcrc = (int32) valcrc;
1242  item->qoperand.length = val_len;
1243  item->qoperand.distance = datalen;
1244 
1245  /*
1246  * Operand strings are copied to the final struct after this loop;
1247  * here we just collect them to an array
1248  */
1249  operands[i] = val;
1250 
1251  datalen += val_len + 1; /* + 1 for the '\0' terminator */
1252  }
1253  else if (item->type == QI_OPR)
1254  {
1255  int8 oper;
1256 
1257  oper = (int8) pq_getmsgint(buf, sizeof(int8));
1258  if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
1259  elog(ERROR, "invalid tsquery: unrecognized operator type %d",
1260  (int) oper);
1261  if (i == size - 1)
1262  elog(ERROR, "invalid pointer to right operand");
1263 
1264  item->qoperator.oper = oper;
1265  if (oper == OP_PHRASE)
1266  item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
1267  }
1268  else
1269  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1270 
1271  item++;
1272  }
1273 
1274  /* Enlarge buffer to make room for the operand values. */
1275  query = (TSQuery) repalloc(query, len + datalen);
1276  item = GETQUERY(query);
1277  ptr = GETOPERAND(query);
1278 
1279  /*
1280  * Fill in the left-pointers. Checks that the tree is well-formed as a
1281  * side-effect.
1282  */
1283  findoprnd(item, size, &needcleanup);
1284 
1285  /* Can't have found any QI_VALSTOP nodes */
1286  Assert(!needcleanup);
1287 
1288  /* Copy operands to output struct */
1289  for (i = 0; i < size; i++)
1290  {
1291  if (item->type == QI_VAL)
1292  {
1293  memcpy(ptr, operands[i], item->qoperand.length + 1);
1294  ptr += item->qoperand.length + 1;
1295  }
1296  item++;
1297  }
1298 
1299  pfree(operands);
1300 
1301  Assert(ptr - GETOPERAND(query) == datalen);
1302 
1303  SET_VARSIZE(query, len + datalen);
1304 
1305  PG_RETURN_TSQUERY(query);
1306 }
signed short int16
Definition: c.h:428
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:44
unsigned char uint8
Definition: c.h:439
TSQueryData * TSQuery
Definition: ts_type.h:212
#define QI_VAL
Definition: ts_type.h:134
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
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:157
#define FIN_LEGACY_CRC32(crc)
Definition: pg_crc.h:80
signed int int32
Definition: c.h:429
#define GETOPERAND(x)
Definition: ltree.h:151
#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:1169
#define ERROR
Definition: elog.h:46
uint8 weight
Definition: ts_type.h:146
static char * buf
Definition: pg_test_fsync.c:68
int32 valcrc
Definition: ts_type.h:151
unsigned int uint32
Definition: c.h:441
#define MaxAllocSize
Definition: memutils.h:40
signed char int8
Definition: c.h:427
#define QI_OPR
Definition: ts_type.h:135
QueryItemType type
Definition: ts_type.h:195
void * palloc0(Size size)
Definition: mcxt.c:1093
#define Assert(condition)
Definition: c.h:804
#define OP_PHRASE
Definition: ts_type.h:169
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
uint32 length
Definition: ts_type.h:158
void * palloc(Size size)
Definition: mcxt.c:1062
#define COMP_LEGACY_CRC32(crc, data, len)
Definition: pg_crc.h:81
#define elog(elevel,...)
Definition: elog.h:232
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:342
uint32 pg_crc32
Definition: pg_crc.h:37
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:382
long val
Definition: informix.c:664
#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:758
#define OP_NOT
Definition: ts_type.h:166

◆ tsquerysend()

Datum tsquerysend ( PG_FUNCTION_ARGS  )

Definition at line 1139 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.

1140 {
1141  TSQuery query = PG_GETARG_TSQUERY(0);
1143  int i;
1144  QueryItem *item = GETQUERY(query);
1145 
1146  pq_begintypsend(&buf);
1147 
1148  pq_sendint32(&buf, query->size);
1149  for (i = 0; i < query->size; i++)
1150  {
1151  pq_sendint8(&buf, item->type);
1152 
1153  switch (item->type)
1154  {
1155  case QI_VAL:
1156  pq_sendint8(&buf, item->qoperand.weight);
1157  pq_sendint8(&buf, item->qoperand.prefix);
1158  pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
1159  break;
1160  case QI_OPR:
1161  pq_sendint8(&buf, item->qoperator.oper);
1162  if (item->qoperator.oper == OP_PHRASE)
1163  pq_sendint16(&buf, item->qoperator.distance);
1164  break;
1165  default:
1166  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1167  }
1168  item++;
1169  }
1170 
1171  PG_FREE_IF_COPY(query, 0);
1172 
1174 }
QueryOperator qoperator
Definition: ts_type.h:196
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:137
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:371
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:157
#define GETOPERAND(x)
Definition: ltree.h:151
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
#define ERROR
Definition: elog.h:46
uint8 weight
Definition: ts_type.h:146
static char * buf
Definition: pg_test_fsync.c:68
#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:260
int32 size
Definition: ts_type.h:208
#define elog(elevel,...)
Definition: elog.h:232
int i
bool prefix
Definition: ts_type.h:150
QueryOperand qoperand
Definition: ts_type.h:197
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:129

◆ tsquerytree()

Datum tsquerytree ( PG_FUNCTION_ARGS  )

Definition at line 1313 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.

1314 {
1315  TSQuery query = PG_GETARG_TSQUERY(0);
1316  INFIX nrm;
1317  text *res;
1318  QueryItem *q;
1319  int len;
1320 
1321  if (query->size == 0)
1322  {
1323  res = (text *) palloc(VARHDRSZ);
1324  SET_VARSIZE(res, VARHDRSZ);
1325  PG_RETURN_POINTER(res);
1326  }
1327 
1328  q = clean_NOT(GETQUERY(query), &len);
1329 
1330  if (!q)
1331  {
1332  res = cstring_to_text("T");
1333  }
1334  else
1335  {
1336  nrm.curpol = q;
1337  nrm.buflen = 32;
1338  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1339  *(nrm.cur) = '\0';
1340  nrm.op = GETOPERAND(query);
1341  infix(&nrm, -1, false);
1342  res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
1343  pfree(q);
1344  }
1345 
1346  PG_FREE_IF_COPY(query, 0);
1347 
1348  PG_RETURN_TEXT_P(res);
1349 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
ITEM * curpol
Definition: _int_bool.c:550
#define VARHDRSZ
Definition: c.h:627
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
char * op
Definition: ltxtquery_io.c:425
#define GETQUERY(x)
Definition: _int.h:157
#define GETOPERAND(x)
Definition: ltree.h:151
void pfree(void *pointer)
Definition: mcxt.c:1169
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:942
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:202
QueryItem * clean_NOT(QueryItem *ptr, int *len)
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
text * cstring_to_text(const char *s)
Definition: varlena.c:190
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
char * cur
Definition: _int_bool.c:552
void * palloc(Size size)
Definition: mcxt.c:1062
int32 buflen
Definition: _int_bool.c:553
int32 size
Definition: ts_type.h:208
Definition: c.h:621
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
char * buf
Definition: _int_bool.c:551

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.