PostgreSQL Source Code  git master
tsquery.c File Reference
#include "postgres.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "nodes/miscnodes.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 "varatt.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, Node *escontext)
 
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
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1540
const void size_t len
static char * buf
Definition: pg_test_fsync.c:73

Definition at line 981 of file tsquery.c.

◆ STACKDEPTH

#define STACKDEPTH   32

Definition at line 631 of file tsquery.c.

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

Enumeration Type Documentation

◆ ts_parserstate

Enumerator
WAITOPERAND 
WAITOPERATOR 
WAITFIRSTOPERAND 

Definition at line 40 of file tsquery.c.

41 {
42  WAITOPERAND = 1,
43  WAITOPERATOR = 2,
44  WAITFIRSTOPERAND = 3,
ts_parserstate
Definition: tsquery.c:41
@ WAITOPERATOR
Definition: tsquery.c:43
@ WAITFIRSTOPERAND
Definition: tsquery.c:44
@ WAITOPERAND
Definition: tsquery.c:42

◆ ts_tokentype

Enumerator
PT_END 
PT_ERR 
PT_VAL 
PT_OPR 
PT_OPEN 
PT_CLOSE 

Definition at line 50 of file tsquery.c.

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

Function Documentation

◆ cleanOpStack()

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

Definition at line 652 of file tsquery.c.

654 {
655  int opPriority = OP_PRIORITY(op);
656 
657  while (*lenstack)
658  {
659  /* NOT is right associative unlike to others */
660  if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
661  (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
662  break;
663 
664  (*lenstack)--;
665  pushOperator(state, stack[*lenstack].op,
666  stack[*lenstack].distance);
667  }
668 }
Definition: regguts.h:323
#define OP_PRIORITY(x)
Definition: ts_type.h:188
#define OP_NOT
Definition: ts_type.h:179
void pushOperator(TSQueryParserState state, int8 oper, int16 distance)
Definition: tsquery.c:535

References OP_NOT, OP_PRIORITY, and pushOperator().

Referenced by makepol().

◆ findoprnd()

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

Definition at line 788 of file tsquery.c.

789 {
790  uint32 pos;
791 
792  *needcleanup = false;
793  pos = 0;
794  findoprnd_recurse(ptr, &pos, size, needcleanup);
795 
796  if (pos != size)
797  elog(ERROR, "malformed tsquery: extra nodes");
798 }
unsigned int uint32
Definition: c.h:506
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static pg_noinline void Size size
Definition: slab.c:607
static void findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
Definition: tsquery.c:730

References elog, ERROR, findoprnd_recurse(), and size.

Referenced by parse_tsquery(), and tsqueryrecv().

◆ findoprnd_recurse()

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

Definition at line 730 of file tsquery.c.

731 {
732  /* since this function recurses, it could be driven to stack overflow. */
734 
735  if (*pos >= nnodes)
736  elog(ERROR, "malformed tsquery: operand not found");
737 
738  if (ptr[*pos].type == QI_VAL)
739  {
740  (*pos)++;
741  }
742  else if (ptr[*pos].type == QI_VALSTOP)
743  {
744  *needcleanup = true; /* we'll have to remove stop words */
745  (*pos)++;
746  }
747  else
748  {
749  Assert(ptr[*pos].type == QI_OPR);
750 
751  if (ptr[*pos].qoperator.oper == OP_NOT)
752  {
753  ptr[*pos].qoperator.left = 1; /* fixed offset */
754  (*pos)++;
755 
756  /* process the only argument */
757  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
758  }
759  else
760  {
761  QueryOperator *curitem = &ptr[*pos].qoperator;
762  int tmp = *pos; /* save current position */
763 
764  Assert(curitem->oper == OP_AND ||
765  curitem->oper == OP_OR ||
766  curitem->oper == OP_PHRASE);
767 
768  (*pos)++;
769 
770  /* process RIGHT argument */
771  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
772 
773  curitem->left = *pos - tmp; /* set LEFT arg's offset */
774 
775  /* process LEFT argument */
776  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
777  }
778  }
779 }
#define Assert(condition)
Definition: c.h:858
void check_stack_depth(void)
Definition: postgres.c:3531
uint32 left
Definition: ts_type.h:197
#define QI_OPR
Definition: ts_type.h:150
#define QI_VAL
Definition: ts_type.h:149
#define QI_VALSTOP
Definition: ts_type.h:151
#define OP_AND
Definition: ts_type.h:180
#define OP_PHRASE
Definition: ts_type.h:182
#define OP_OR
Definition: ts_type.h:181
QueryOperator qoperator
Definition: ts_type.h:209
const char * type

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 type.

Referenced by findoprnd().

◆ get_modifiers()

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

Definition at line 114 of file tsquery.c.

115 {
116  *weight = 0;
117  *prefix = false;
118 
119  if (!t_iseq(buf, ':'))
120  return buf;
121 
122  buf++;
123  while (*buf && pg_mblen(buf) == 1)
124  {
125  switch (*buf)
126  {
127  case 'a':
128  case 'A':
129  *weight |= 1 << 3;
130  break;
131  case 'b':
132  case 'B':
133  *weight |= 1 << 2;
134  break;
135  case 'c':
136  case 'C':
137  *weight |= 1 << 1;
138  break;
139  case 'd':
140  case 'D':
141  *weight |= 1;
142  break;
143  case '*':
144  *prefix = true;
145  break;
146  default:
147  return buf;
148  }
149  buf++;
150  }
151 
152  return buf;
153 }
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
#define t_iseq(x, c)
Definition: ts_locale.h:38

References buf, pg_mblen(), and t_iseq.

Referenced by gettoken_query_standard().

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

517 {
518  *weight = 0;
519  *prefix = false;
520 
521  if (*state->buf == '\0')
522  return PT_END;
523 
524  *strval = state->buf;
525  *lenval = strlen(state->buf);
526  state->buf += *lenval;
527  state->count++;
528  return PT_VAL;
529 }

References PT_END, and PT_VAL.

Referenced by parse_tsquery().

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

289 {
290  *weight = 0;
291  *prefix = false;
292 
293  while (true)
294  {
295  switch (state->state)
296  {
297  case WAITFIRSTOPERAND:
298  case WAITOPERAND:
299  if (t_iseq(state->buf, '!'))
300  {
301  state->buf++;
302  state->state = WAITOPERAND;
303  *operator = OP_NOT;
304  return PT_OPR;
305  }
306  else if (t_iseq(state->buf, '('))
307  {
308  state->buf++;
309  state->state = WAITOPERAND;
310  state->count++;
311  return PT_OPEN;
312  }
313  else if (t_iseq(state->buf, ':'))
314  {
315  /* generic syntax error message is fine */
316  return PT_ERR;
317  }
318  else if (!t_isspace(state->buf))
319  {
320  /*
321  * We rely on the tsvector parser to parse the value for
322  * us
323  */
324  reset_tsvector_parser(state->valstate, state->buf);
325  if (gettoken_tsvector(state->valstate, strval, lenval,
326  NULL, NULL, &state->buf))
327  {
328  state->buf = get_modifiers(state->buf, weight, prefix);
329  state->state = WAITOPERATOR;
330  return PT_VAL;
331  }
332  else if (SOFT_ERROR_OCCURRED(state->escontext))
333  {
334  /* gettoken_tsvector reported a soft error */
335  return PT_ERR;
336  }
337  else if (state->state == WAITFIRSTOPERAND)
338  {
339  return PT_END;
340  }
341  else
342  ereturn(state->escontext, PT_ERR,
343  (errcode(ERRCODE_SYNTAX_ERROR),
344  errmsg("no operand in tsquery: \"%s\"",
345  state->buffer)));
346  }
347  break;
348 
349  case WAITOPERATOR:
350  if (t_iseq(state->buf, '&'))
351  {
352  state->buf++;
353  state->state = WAITOPERAND;
354  *operator = OP_AND;
355  return PT_OPR;
356  }
357  else if (t_iseq(state->buf, '|'))
358  {
359  state->buf++;
360  state->state = WAITOPERAND;
361  *operator = OP_OR;
362  return PT_OPR;
363  }
364  else if (parse_phrase_operator(state, weight))
365  {
366  /* weight var is used as storage for distance */
367  state->state = WAITOPERAND;
368  *operator = OP_PHRASE;
369  return PT_OPR;
370  }
371  else if (SOFT_ERROR_OCCURRED(state->escontext))
372  {
373  /* parse_phrase_operator reported a soft error */
374  return PT_ERR;
375  }
376  else if (t_iseq(state->buf, ')'))
377  {
378  state->buf++;
379  state->count--;
380  return (state->count < 0) ? PT_ERR : PT_CLOSE;
381  }
382  else if (*state->buf == '\0')
383  {
384  return (state->count) ? PT_ERR : PT_END;
385  }
386  else if (!t_isspace(state->buf))
387  {
388  return PT_ERR;
389  }
390  break;
391  }
392 
393  state->buf += pg_mblen(state->buf);
394  }
395 }
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:52
int t_isspace(const char *ptr)
Definition: ts_locale.c:50
static bool parse_phrase_operator(TSQueryParserState pstate, int16 *distance)
Definition: tsquery.c:165
static char * get_modifiers(char *buf, int16 *weight, bool *prefix)
Definition: tsquery.c:114
void reset_tsvector_parser(TSVectorParseState state, char *input)
bool gettoken_tsvector(TSVectorParseState state, char **strval, int *lenval, WordEntryPos **pos_ptr, int *poslen, char **endptr)

References ereturn, errcode(), errmsg(), 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(), SOFT_ERROR_OCCURRED, t_iseq, t_isspace(), WAITFIRSTOPERAND, WAITOPERAND, and WAITOPERATOR.

Referenced by parse_tsquery().

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

401 {
402  *weight = 0;
403  *prefix = false;
404 
405  while (true)
406  {
407  switch (state->state)
408  {
409  case WAITFIRSTOPERAND:
410  case WAITOPERAND:
411  if (t_iseq(state->buf, '-'))
412  {
413  state->buf++;
414  state->state = WAITOPERAND;
415 
416  *operator = OP_NOT;
417  return PT_OPR;
418  }
419  else if (t_iseq(state->buf, '"'))
420  {
421  /* Everything in quotes is processed as a single token */
422 
423  /* skip opening quote */
424  state->buf++;
425  *strval = state->buf;
426 
427  /* iterate to the closing quote or end of the string */
428  while (*state->buf != '\0' && !t_iseq(state->buf, '"'))
429  state->buf++;
430  *lenval = state->buf - *strval;
431 
432  /* skip closing quote if not end of the string */
433  if (*state->buf != '\0')
434  state->buf++;
435 
436  state->state = WAITOPERATOR;
437  state->count++;
438  return PT_VAL;
439  }
440  else if (ISOPERATOR(state->buf))
441  {
442  /* or else gettoken_tsvector() will raise an error */
443  state->buf++;
444  state->state = WAITOPERAND;
445  continue;
446  }
447  else if (!t_isspace(state->buf))
448  {
449  /*
450  * We rely on the tsvector parser to parse the value for
451  * us
452  */
453  reset_tsvector_parser(state->valstate, state->buf);
454  if (gettoken_tsvector(state->valstate, strval, lenval,
455  NULL, NULL, &state->buf))
456  {
457  state->state = WAITOPERATOR;
458  return PT_VAL;
459  }
460  else if (SOFT_ERROR_OCCURRED(state->escontext))
461  {
462  /* gettoken_tsvector reported a soft error */
463  return PT_ERR;
464  }
465  else if (state->state == WAITFIRSTOPERAND)
466  {
467  return PT_END;
468  }
469  else
470  {
471  /* finally, we have to provide an operand */
472  pushStop(state);
473  return PT_END;
474  }
475  }
476  break;
477 
478  case WAITOPERATOR:
479  if (t_iseq(state->buf, '"'))
480  {
481  /*
482  * put implicit AND after an operand and handle this quote
483  * in WAITOPERAND
484  */
485  state->state = WAITOPERAND;
486  *operator = OP_AND;
487  return PT_OPR;
488  }
489  else if (parse_or_operator(state))
490  {
491  state->state = WAITOPERAND;
492  *operator = OP_OR;
493  return PT_OPR;
494  }
495  else if (*state->buf == '\0')
496  {
497  return PT_END;
498  }
499  else if (!t_isspace(state->buf))
500  {
501  /* put implicit AND after an operand */
502  *operator = OP_AND;
503  state->state = WAITOPERAND;
504  return PT_OPR;
505  }
506  break;
507  }
508 
509  state->buf += pg_mblen(state->buf);
510  }
511 }
#define ISOPERATOR(x)
Definition: ltree.h:167
static bool parse_or_operator(TSQueryParserState pstate)
Definition: tsquery.c:244
void pushStop(TSQueryParserState state)
Definition: tsquery.c:620

References gettoken_tsvector(), ISOPERATOR, OP_AND, OP_NOT, OP_OR, parse_or_operator(), pg_mblen(), PT_END, PT_ERR, PT_OPR, PT_VAL, pushStop(), reset_tsvector_parser(), SOFT_ERROR_OCCURRED, t_iseq, t_isspace(), WAITFIRSTOPERAND, WAITOPERAND, and WAITOPERATOR.

Referenced by parse_tsquery().

◆ infix()

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

Definition at line 995 of file tsquery.c.

996 {
997  /* since this function recurses, it could be driven to stack overflow. */
999 
1000  if (in->curpol->type == QI_VAL)
1001  {
1002  QueryOperand *curpol = &in->curpol->qoperand;
1003  char *op = in->op + curpol->distance;
1004  int clen;
1005 
1006  RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
1007  *(in->cur) = '\'';
1008  in->cur++;
1009  while (*op)
1010  {
1011  if (t_iseq(op, '\''))
1012  {
1013  *(in->cur) = '\'';
1014  in->cur++;
1015  }
1016  else if (t_iseq(op, '\\'))
1017  {
1018  *(in->cur) = '\\';
1019  in->cur++;
1020  }
1021  COPYCHAR(in->cur, op);
1022 
1023  clen = pg_mblen(op);
1024  op += clen;
1025  in->cur += clen;
1026  }
1027  *(in->cur) = '\'';
1028  in->cur++;
1029  if (curpol->weight || curpol->prefix)
1030  {
1031  *(in->cur) = ':';
1032  in->cur++;
1033  if (curpol->prefix)
1034  {
1035  *(in->cur) = '*';
1036  in->cur++;
1037  }
1038  if (curpol->weight & (1 << 3))
1039  {
1040  *(in->cur) = 'A';
1041  in->cur++;
1042  }
1043  if (curpol->weight & (1 << 2))
1044  {
1045  *(in->cur) = 'B';
1046  in->cur++;
1047  }
1048  if (curpol->weight & (1 << 1))
1049  {
1050  *(in->cur) = 'C';
1051  in->cur++;
1052  }
1053  if (curpol->weight & 1)
1054  {
1055  *(in->cur) = 'D';
1056  in->cur++;
1057  }
1058  }
1059  *(in->cur) = '\0';
1060  in->curpol++;
1061  }
1062  else if (in->curpol->qoperator.oper == OP_NOT)
1063  {
1064  int priority = QO_PRIORITY(in->curpol);
1065 
1066  if (priority < parentPriority)
1067  {
1068  RESIZEBUF(in, 2);
1069  sprintf(in->cur, "( ");
1070  in->cur = strchr(in->cur, '\0');
1071  }
1072  RESIZEBUF(in, 1);
1073  *(in->cur) = '!';
1074  in->cur++;
1075  *(in->cur) = '\0';
1076  in->curpol++;
1077 
1078  infix(in, priority, false);
1079  if (priority < parentPriority)
1080  {
1081  RESIZEBUF(in, 2);
1082  sprintf(in->cur, " )");
1083  in->cur = strchr(in->cur, '\0');
1084  }
1085  }
1086  else
1087  {
1088  int8 op = in->curpol->qoperator.oper;
1089  int priority = QO_PRIORITY(in->curpol);
1090  int16 distance = in->curpol->qoperator.distance;
1091  INFIX nrm;
1092  bool needParenthesis = false;
1093 
1094  in->curpol++;
1095  if (priority < parentPriority ||
1096  /* phrase operator depends on order */
1097  (op == OP_PHRASE && rightPhraseOp))
1098  {
1099  needParenthesis = true;
1100  RESIZEBUF(in, 2);
1101  sprintf(in->cur, "( ");
1102  in->cur = strchr(in->cur, '\0');
1103  }
1104 
1105  nrm.curpol = in->curpol;
1106  nrm.op = in->op;
1107  nrm.buflen = 16;
1108  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1109 
1110  /* get right operand */
1111  infix(&nrm, priority, (op == OP_PHRASE));
1112 
1113  /* get & print left operand */
1114  in->curpol = nrm.curpol;
1115  infix(in, priority, false);
1116 
1117  /* print operator & right operand */
1118  RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
1119  switch (op)
1120  {
1121  case OP_OR:
1122  sprintf(in->cur, " | %s", nrm.buf);
1123  break;
1124  case OP_AND:
1125  sprintf(in->cur, " & %s", nrm.buf);
1126  break;
1127  case OP_PHRASE:
1128  if (distance != 1)
1129  sprintf(in->cur, " <%d> %s", distance, nrm.buf);
1130  else
1131  sprintf(in->cur, " <-> %s", nrm.buf);
1132  break;
1133  default:
1134  /* OP_NOT is handled in above if-branch */
1135  elog(ERROR, "unrecognized operator type: %d", op);
1136  }
1137  in->cur = strchr(in->cur, '\0');
1138  pfree(nrm.buf);
1139 
1140  if (needParenthesis)
1141  {
1142  RESIZEBUF(in, 2);
1143  sprintf(in->cur, " )");
1144  in->cur = strchr(in->cur, '\0');
1145  }
1146  }
1147 }
signed char int8
Definition: c.h:492
signed short int16
Definition: c.h:493
int pg_database_encoding_max_length(void)
Definition: mbutils.c:1546
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
#define sprintf
Definition: port.h:240
char * buf
Definition: _int_bool.c:553
char * cur
Definition: _int_bool.c:554
int32 buflen
Definition: _int_bool.c:555
ITEM * curpol
Definition: _int_bool.c:552
char * op
Definition: ltxtquery_io.c:454
uint16 distance
Definition: ltree.h:146
int16 type
Definition: _int.h:142
bool prefix
Definition: ts_type.h:163
uint8 weight
Definition: ts_type.h:159
uint32 distance
Definition: ts_type.h:172
uint32 length
Definition: ts_type.h:171
#define COPYCHAR(d, s)
Definition: ts_locale.h:40
#define QO_PRIORITY(x)
Definition: ts_type.h:190
#define RESIZEBUF(inf, addsize)
Definition: tsquery.c:981
static void infix(INFIX *in, int parentPriority, bool rightPhraseOp)
Definition: tsquery.c:995

References INFIX::buf, INFIX::buflen, check_stack_depth(), COPYCHAR, INFIX::cur, INFIX::curpol, ITEM::distance, QueryOperand::distance, elog, ERROR, QueryOperand::length, INFIX::op, TSQueryParserStateData::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().

◆ makepol()

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

Definition at line 676 of file tsquery.c.

679 {
680  int8 operator = 0;
682  int lenval = 0;
683  char *strval = NULL;
684  OperatorElement opstack[STACKDEPTH];
685  int lenstack = 0;
686  int16 weight = 0;
687  bool prefix;
688 
689  /* since this function recurses, it could be driven to stack overflow */
691 
692  while ((type = state->gettoken(state, &operator,
693  &lenval, &strval,
694  &weight, &prefix)) != PT_END)
695  {
696  switch (type)
697  {
698  case PT_VAL:
699  pushval(opaque, state, strval, lenval, weight, prefix);
700  break;
701  case PT_OPR:
702  cleanOpStack(state, opstack, &lenstack, operator);
703  pushOpStack(opstack, &lenstack, operator, weight);
704  break;
705  case PT_OPEN:
706  makepol(state, pushval, opaque);
707  break;
708  case PT_CLOSE:
709  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
710  return;
711  case PT_ERR:
712  default:
713  /* don't overwrite a soft error saved by gettoken function */
714  if (!SOFT_ERROR_OCCURRED(state->escontext))
715  errsave(state->escontext,
716  (errcode(ERRCODE_SYNTAX_ERROR),
717  errmsg("syntax error in tsquery: \"%s\"",
718  state->buffer)));
719  return;
720  }
721  /* detect soft error in pushval or recursion */
722  if (SOFT_ERROR_OCCURRED(state->escontext))
723  return;
724  }
725 
726  cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */ );
727 }
#define errsave(context,...)
Definition: elog.h:260
static void pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
Definition: tsquery.c:640
static void cleanOpStack(TSQueryParserState state, OperatorElement *stack, int *lenstack, int8 op)
Definition: tsquery.c:652
static void makepol(TSQueryParserState state, PushFunction pushval, Datum opaque)
Definition: tsquery.c:676
#define STACKDEPTH
Definition: tsquery.c:631

References check_stack_depth(), cleanOpStack(), errcode(), errmsg(), errsave, OP_OR, PT_CLOSE, PT_END, PT_ERR, PT_OPEN, PT_OPR, PT_VAL, pushOpStack(), SOFT_ERROR_OCCURRED, STACKDEPTH, and type.

Referenced by parse_tsquery().

◆ parse_or_operator()

static bool parse_or_operator ( TSQueryParserState  pstate)
static

Definition at line 244 of file tsquery.c.

245 {
246  char *ptr = pstate->buf;
247 
248  /* it should begin with "OR" literal */
249  if (pg_strncasecmp(ptr, "or", 2) != 0)
250  return false;
251 
252  ptr += 2;
253 
254  /*
255  * it shouldn't be a part of any word but somewhere later it should be
256  * some operand
257  */
258  if (*ptr == '\0') /* no operand */
259  return false;
260 
261  /* it shouldn't be a part of any word */
262  if (t_iseq(ptr, '-') || t_iseq(ptr, '_') || t_isalnum(ptr))
263  return false;
264 
265  for (;;)
266  {
267  ptr += pg_mblen(ptr);
268 
269  if (*ptr == '\0') /* got end of string without operand */
270  return false;
271 
272  /*
273  * Suppose, we found an operand, but could be a not correct operand.
274  * So we still treat OR literal as operation with possibly incorrect
275  * operand and will not search it as lexeme
276  */
277  if (!t_isspace(ptr))
278  break;
279  }
280 
281  pstate->buf += 2;
282  return true;
283 }
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
int t_isalnum(const char *ptr)
Definition: ts_locale.c:80

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

Referenced by gettoken_query_websearch().

◆ parse_phrase_operator()

static bool parse_phrase_operator ( TSQueryParserState  pstate,
int16 distance 
)
static

Definition at line 165 of file tsquery.c.

166 {
167  enum
168  {
169  PHRASE_OPEN = 0,
170  PHRASE_DIST,
171  PHRASE_CLOSE,
172  PHRASE_FINISH
173  } state = PHRASE_OPEN;
174  char *ptr = pstate->buf;
175  char *endptr;
176  long l = 1; /* default distance */
177 
178  while (*ptr)
179  {
180  switch (state)
181  {
182  case PHRASE_OPEN:
183  if (t_iseq(ptr, '<'))
184  {
185  state = PHRASE_DIST;
186  ptr++;
187  }
188  else
189  return false;
190  break;
191 
192  case PHRASE_DIST:
193  if (t_iseq(ptr, '-'))
194  {
195  state = PHRASE_CLOSE;
196  ptr++;
197  continue;
198  }
199 
200  if (!t_isdigit(ptr))
201  return false;
202 
203  errno = 0;
204  l = strtol(ptr, &endptr, 10);
205  if (ptr == endptr)
206  return false;
207  else if (errno == ERANGE || l < 0 || l > MAXENTRYPOS)
208  ereturn(pstate->escontext, false,
209  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
210  errmsg("distance in phrase operator must be an integer value between zero and %d inclusive",
211  MAXENTRYPOS)));
212  else
213  {
214  state = PHRASE_CLOSE;
215  ptr = endptr;
216  }
217  break;
218 
219  case PHRASE_CLOSE:
220  if (t_iseq(ptr, '>'))
221  {
222  state = PHRASE_FINISH;
223  ptr++;
224  }
225  else
226  return false;
227  break;
228 
229  case PHRASE_FINISH:
230  *distance = (int16) l;
231  pstate->buf = ptr;
232  return true;
233  }
234  }
235 
236  return false;
237 }
int t_isdigit(const char *ptr)
Definition: ts_locale.c:35
#define MAXENTRYPOS
Definition: ts_type.h:85

References TSQueryParserStateData::buf, ereturn, errcode(), errmsg(), TSQueryParserStateData::escontext, MAXENTRYPOS, t_isdigit(), and t_iseq.

Referenced by gettoken_query_standard().

◆ parse_tsquery()

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

Definition at line 821 of file tsquery.c.

826 {
828  int i;
829  TSQuery query;
830  int commonlen;
831  QueryItem *ptr;
832  ListCell *cell;
833  bool noisy;
834  bool needcleanup;
835  int tsv_flags = P_TSV_OPR_IS_DELIM | P_TSV_IS_TSQUERY;
836 
837  /* plain should not be used with web */
838  Assert((flags & (P_TSQ_PLAIN | P_TSQ_WEB)) != (P_TSQ_PLAIN | P_TSQ_WEB));
839 
840  /* select suitable tokenizer */
841  if (flags & P_TSQ_PLAIN)
842  state.gettoken = gettoken_query_plain;
843  else if (flags & P_TSQ_WEB)
844  {
845  state.gettoken = gettoken_query_websearch;
846  tsv_flags |= P_TSV_IS_WEB;
847  }
848  else
849  state.gettoken = gettoken_query_standard;
850 
851  /* emit nuisance NOTICEs only if not doing soft errors */
852  noisy = !(escontext && IsA(escontext, ErrorSaveContext));
853 
854  /* init state */
855  state.buffer = buf;
856  state.buf = buf;
857  state.count = 0;
858  state.state = WAITFIRSTOPERAND;
859  state.polstr = NIL;
860  state.escontext = escontext;
861 
862  /* init value parser's state */
863  state.valstate = init_tsvector_parser(state.buffer, tsv_flags, escontext);
864 
865  /* init list of operand */
866  state.sumlen = 0;
867  state.lenop = 64;
868  state.curop = state.op = (char *) palloc(state.lenop);
869  *(state.curop) = '\0';
870 
871  /* parse query & make polish notation (postfix, but in reverse order) */
872  makepol(&state, pushval, opaque);
873 
874  close_tsvector_parser(state.valstate);
875 
877  return NULL;
878 
879  if (state.polstr == NIL)
880  {
881  if (noisy)
882  ereport(NOTICE,
883  (errmsg("text-search query doesn't contain lexemes: \"%s\"",
884  state.buffer)));
885  query = (TSQuery) palloc(HDRSIZETQ);
886  SET_VARSIZE(query, HDRSIZETQ);
887  query->size = 0;
888  return query;
889  }
890 
891  if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
892  ereturn(escontext, NULL,
893  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
894  errmsg("tsquery is too large")));
895  commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
896 
897  /* Pack the QueryItems in the final TSQuery struct to return to caller */
898  query = (TSQuery) palloc0(commonlen);
899  SET_VARSIZE(query, commonlen);
900  query->size = list_length(state.polstr);
901  ptr = GETQUERY(query);
902 
903  /* Copy QueryItems to TSQuery */
904  i = 0;
905  foreach(cell, state.polstr)
906  {
907  QueryItem *item = (QueryItem *) lfirst(cell);
908 
909  switch (item->type)
910  {
911  case QI_VAL:
912  memcpy(&ptr[i], item, sizeof(QueryOperand));
913  break;
914  case QI_VALSTOP:
915  ptr[i].type = QI_VALSTOP;
916  break;
917  case QI_OPR:
918  memcpy(&ptr[i], item, sizeof(QueryOperator));
919  break;
920  default:
921  elog(ERROR, "unrecognized QueryItem type: %d", item->type);
922  }
923  i++;
924  }
925 
926  /* Copy all the operand strings to TSQuery */
927  memcpy(GETOPERAND(query), state.op, state.sumlen);
928  pfree(state.op);
929 
930  /*
931  * Set left operand pointers for every operator. While we're at it,
932  * detect whether there are any QI_VALSTOP nodes.
933  */
934  findoprnd(ptr, query->size, &needcleanup);
935 
936  /*
937  * If there are QI_VALSTOP nodes, delete them and simplify the tree.
938  */
939  if (needcleanup)
940  query = cleanup_tsquery_stopwords(query, noisy);
941 
942  return query;
943 }
#define COMPUTESIZE(size)
Definition: _int.h:155
#define GETQUERY(x)
Definition: _int.h:157
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:73
#define GETOPERAND(x)
Definition: ltree.h:165
void * palloc0(Size size)
Definition: mcxt.c:1346
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
int32 size
Definition: ts_type.h:221
TSQueryData * TSQuery
Definition: ts_type.h:225
#define HDRSIZETQ
Definition: ts_type.h:227
#define TSQUERY_TOO_BIG(size, lenofoperand)
Definition: ts_type.h:233
#define P_TSV_IS_TSQUERY
Definition: ts_utils.h:30
#define P_TSV_IS_WEB
Definition: ts_utils.h:31
#define P_TSQ_PLAIN
Definition: ts_utils.h:64
#define P_TSV_OPR_IS_DELIM
Definition: ts_utils.h:29
#define P_TSQ_WEB
Definition: ts_utils.h:65
static ts_tokentype gettoken_query_standard(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:286
static void findoprnd(QueryItem *ptr, int size, bool *needcleanup)
Definition: tsquery.c:788
static ts_tokentype gettoken_query_plain(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:514
static ts_tokentype gettoken_query_websearch(TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
Definition: tsquery.c:398
TSQuery cleanup_tsquery_stopwords(TSQuery in, bool noisy)
void close_tsvector_parser(TSVectorParseState state)
TSVectorParseState init_tsvector_parser(char *input, int flags, Node *escontext)
QueryItemType type
Definition: ts_type.h:208
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References Assert, buf, cleanup_tsquery_stopwords(), close_tsvector_parser(), COMPUTESIZE, elog, ereport, ereturn, errcode(), errmsg(), ERROR, TSQueryParserStateData::escontext, findoprnd(), GETOPERAND, GETQUERY, gettoken_query_plain(), gettoken_query_standard(), gettoken_query_websearch(), HDRSIZETQ, i, init_tsvector_parser(), IsA, lfirst, list_length(), makepol(), NIL, NOTICE, P_TSQ_PLAIN, P_TSQ_WEB, P_TSV_IS_TSQUERY, P_TSV_IS_WEB, P_TSV_OPR_IS_DELIM, palloc(), palloc0(), pfree(), QI_OPR, QI_VAL, QI_VALSTOP, SET_VARSIZE, TSQueryData::size, SOFT_ERROR_OCCURRED, TSQUERY_TOO_BIG, QueryItem::type, and WAITFIRSTOPERAND.

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

◆ pushOperator()

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

Definition at line 535 of file tsquery.c.

536 {
537  QueryOperator *tmp;
538 
539  Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
540 
541  tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
542  tmp->type = QI_OPR;
543  tmp->oper = oper;
544  tmp->distance = (oper == OP_PHRASE) ? distance : 0;
545  /* left is filled in later with findoprnd */
546 
547  state->polstr = lcons(tmp, state->polstr);
548 }
List * lcons(void *datum, List *list)
Definition: list.c:495
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:370
int16 distance
Definition: ts_type.h:196
QueryItemType type
Definition: ts_type.h:194

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

Referenced by cleanOpStack(), and pushval_morph().

◆ pushOpStack()

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

Definition at line 640 of file tsquery.c.

641 {
642  if (*lenstack == STACKDEPTH) /* internal error */
643  elog(ERROR, "tsquery stack too small");
644 
645  stack[*lenstack].op = op;
646  stack[*lenstack].distance = distance;
647 
648  (*lenstack)++;
649 }
int16 distance
Definition: tsquery.c:636

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

Referenced by makepol().

◆ pushStop()

void pushStop ( TSQueryParserState  state)

Definition at line 620 of file tsquery.c.

621 {
622  QueryOperand *tmp;
623 
624  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
625  tmp->type = QI_VALSTOP;
626 
627  state->polstr = lcons(tmp, state->polstr);
628 }
QueryItemType type
Definition: ts_type.h:158

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

Referenced by gettoken_query_websearch(), and pushval_morph().

◆ pushval_asis()

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

Definition at line 946 of file tsquery.c.

948 {
949  pushValue(state, strval, lenval, weight, prefix);
950 }
void pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:584

References pushValue().

Referenced by tsqueryin().

◆ pushValue()

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

Definition at line 584 of file tsquery.c.

585 {
586  pg_crc32 valcrc;
587 
588  if (lenval >= MAXSTRLEN)
589  ereturn(state->escontext,,
590  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
591  errmsg("word is too long in tsquery: \"%s\"",
592  state->buffer)));
593 
594  INIT_LEGACY_CRC32(valcrc);
595  COMP_LEGACY_CRC32(valcrc, strval, lenval);
596  FIN_LEGACY_CRC32(valcrc);
597  pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
598 
599  /* append the value string to state.op, enlarging buffer if needed first */
600  while (state->curop - state->op + lenval + 1 >= state->lenop)
601  {
602  int used = state->curop - state->op;
603 
604  state->lenop *= 2;
605  state->op = (char *) repalloc(state->op, state->lenop);
606  state->curop = state->op + used;
607  }
608  memcpy(state->curop, strval, lenval);
609  state->curop += lenval;
610  *(state->curop) = '\0';
611  state->curop++;
612  state->sumlen += lenval + 1 /* \0 */ ;
613 }
uint32 pg_crc32
Definition: pg_crc.h:37
#define INIT_LEGACY_CRC32(crc)
Definition: pg_crc.h:79
#define COMP_LEGACY_CRC32(crc, data, len)
Definition: pg_crc.h:81
#define FIN_LEGACY_CRC32(crc)
Definition: pg_crc.h:80
#define MAXSTRLEN
Definition: ts_type.h:49
static void pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
Definition: tsquery.c:551

References COMP_LEGACY_CRC32, ereturn, errcode(), errmsg(), FIN_LEGACY_CRC32, INIT_LEGACY_CRC32, MAXSTRLEN, pushValue_internal(), and repalloc().

Referenced by pushval_asis(), and pushval_morph().

◆ pushValue_internal()

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

Definition at line 551 of file tsquery.c.

552 {
553  QueryOperand *tmp;
554 
555  if (distance >= MAXSTRPOS)
556  ereturn(state->escontext,,
557  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
558  errmsg("value is too big in tsquery: \"%s\"",
559  state->buffer)));
560  if (lenval >= MAXSTRLEN)
561  ereturn(state->escontext,,
562  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
563  errmsg("operand is too long in tsquery: \"%s\"",
564  state->buffer)));
565 
566  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
567  tmp->type = QI_VAL;
568  tmp->weight = weight;
569  tmp->prefix = prefix;
570  tmp->valcrc = (int32) valcrc;
571  tmp->length = lenval;
572  tmp->distance = distance;
573 
574  state->polstr = lcons(tmp, state->polstr);
575 }
signed int int32
Definition: c.h:494
int32 valcrc
Definition: ts_type.h:164
#define MAXSTRPOS
Definition: ts_type.h:50

References QueryOperand::distance, ereturn, errcode(), errmsg(), lcons(), QueryOperand::length, MAXSTRLEN, MAXSTRPOS, palloc0(), QueryOperand::prefix, QI_VAL, QueryOperand::type, QueryOperand::valcrc, and QueryOperand::weight.

Referenced by pushValue().

◆ tsqueryin()

Datum tsqueryin ( PG_FUNCTION_ARGS  )

Definition at line 956 of file tsquery.c.

957 {
958  char *in = PG_GETARG_CSTRING(0);
959  Node *escontext = fcinfo->context;
960 
962  pushval_asis,
963  PointerGetDatum(NULL),
964  0,
965  escontext));
966 }
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
Definition: nodes.h:129
#define PG_RETURN_TSQUERY(x)
Definition: ts_type.h:268
TSQuery parse_tsquery(char *buf, PushFunction pushval, Datum opaque, int flags, Node *escontext)
Definition: tsquery.c:821
static void pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:946

References TSQueryParserStateData::escontext, parse_tsquery(), PG_GETARG_CSTRING, PG_RETURN_TSQUERY, PointerGetDatum(), and pushval_asis().

◆ tsqueryout()

Datum tsqueryout ( PG_FUNCTION_ARGS  )

Definition at line 1150 of file tsquery.c.

1151 {
1152  TSQuery query = PG_GETARG_TSQUERY(0);
1153  INFIX nrm;
1154 
1155  if (query->size == 0)
1156  {
1157  char *b = palloc(1);
1158 
1159  *b = '\0';
1161  }
1162  nrm.curpol = GETQUERY(query);
1163  nrm.buflen = 32;
1164  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1165  *(nrm.cur) = '\0';
1166  nrm.op = GETOPERAND(query);
1167  infix(&nrm, -1 /* lowest priority */ , false);
1168 
1169  PG_FREE_IF_COPY(query, 0);
1170  PG_RETURN_CSTRING(nrm.buf);
1171 }
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
int b
Definition: isn.c:70
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:266

References b, 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.

◆ tsqueryrecv()

Datum tsqueryrecv ( PG_FUNCTION_ARGS  )

Definition at line 1230 of file tsquery.c.

1231 {
1233  TSQuery query;
1234  int i,
1235  len;
1236  QueryItem *item;
1237  int datalen;
1238  char *ptr;
1239  uint32 size;
1240  const char **operands;
1241  bool needcleanup;
1242 
1243  size = pq_getmsgint(buf, sizeof(uint32));
1244  if (size > (MaxAllocSize / sizeof(QueryItem)))
1245  elog(ERROR, "invalid size of tsquery");
1246 
1247  /* Allocate space to temporarily hold operand strings */
1248  operands = palloc(size * sizeof(char *));
1249 
1250  /* Allocate space for all the QueryItems. */
1251  len = HDRSIZETQ + sizeof(QueryItem) * size;
1252  query = (TSQuery) palloc0(len);
1253  query->size = size;
1254  item = GETQUERY(query);
1255 
1256  datalen = 0;
1257  for (i = 0; i < size; i++)
1258  {
1259  item->type = (int8) pq_getmsgint(buf, sizeof(int8));
1260 
1261  if (item->type == QI_VAL)
1262  {
1263  size_t val_len; /* length after recoding to server
1264  * encoding */
1265  uint8 weight;
1266  uint8 prefix;
1267  const char *val;
1268  pg_crc32 valcrc;
1269 
1270  weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
1271  prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
1272  val = pq_getmsgstring(buf);
1273  val_len = strlen(val);
1274 
1275  /* Sanity checks */
1276 
1277  if (weight > 0xF)
1278  elog(ERROR, "invalid tsquery: invalid weight bitmap");
1279 
1280  if (val_len > MAXSTRLEN)
1281  elog(ERROR, "invalid tsquery: operand too long");
1282 
1283  if (datalen > MAXSTRPOS)
1284  elog(ERROR, "invalid tsquery: total operand length exceeded");
1285 
1286  /* Looks valid. */
1287 
1288  INIT_LEGACY_CRC32(valcrc);
1289  COMP_LEGACY_CRC32(valcrc, val, val_len);
1290  FIN_LEGACY_CRC32(valcrc);
1291 
1292  item->qoperand.weight = weight;
1293  item->qoperand.prefix = (prefix) ? true : false;
1294  item->qoperand.valcrc = (int32) valcrc;
1295  item->qoperand.length = val_len;
1296  item->qoperand.distance = datalen;
1297 
1298  /*
1299  * Operand strings are copied to the final struct after this loop;
1300  * here we just collect them to an array
1301  */
1302  operands[i] = val;
1303 
1304  datalen += val_len + 1; /* + 1 for the '\0' terminator */
1305  }
1306  else if (item->type == QI_OPR)
1307  {
1308  int8 oper;
1309 
1310  oper = (int8) pq_getmsgint(buf, sizeof(int8));
1311  if (oper != OP_NOT && oper != OP_OR && oper != OP_AND && oper != OP_PHRASE)
1312  elog(ERROR, "invalid tsquery: unrecognized operator type %d",
1313  (int) oper);
1314  if (i == size - 1)
1315  elog(ERROR, "invalid pointer to right operand");
1316 
1317  item->qoperator.oper = oper;
1318  if (oper == OP_PHRASE)
1319  item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
1320  }
1321  else
1322  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1323 
1324  item++;
1325  }
1326 
1327  /* Enlarge buffer to make room for the operand values. */
1328  query = (TSQuery) repalloc(query, len + datalen);
1329  item = GETQUERY(query);
1330  ptr = GETOPERAND(query);
1331 
1332  /*
1333  * Fill in the left-pointers. Checks that the tree is well-formed as a
1334  * side-effect.
1335  */
1336  findoprnd(item, size, &needcleanup);
1337 
1338  /* Can't have found any QI_VALSTOP nodes */
1339  Assert(!needcleanup);
1340 
1341  /* Copy operands to output struct */
1342  for (i = 0; i < size; i++)
1343  {
1344  if (item->type == QI_VAL)
1345  {
1346  memcpy(ptr, operands[i], item->qoperand.length + 1);
1347  ptr += item->qoperand.length + 1;
1348  }
1349  item++;
1350  }
1351 
1352  pfree(operands);
1353 
1354  Assert(ptr - GETOPERAND(query) == datalen);
1355 
1356  SET_VARSIZE(query, len + datalen);
1357 
1358  PG_RETURN_TSQUERY(query);
1359 }
unsigned char uint8
Definition: c.h:504
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
long val
Definition: informix.c:670
#define MaxAllocSize
Definition: memutils.h:40
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
const char * pq_getmsgstring(StringInfo msg)
Definition: pqformat.c:579
StringInfoData * StringInfo
Definition: stringinfo.h:54
QueryOperand qoperand
Definition: ts_type.h:210

References Assert, buf, COMP_LEGACY_CRC32, QueryOperand::distance, QueryOperator::distance, elog, ERROR, FIN_LEGACY_CRC32, findoprnd(), GETOPERAND, GETQUERY, HDRSIZETQ, i, INIT_LEGACY_CRC32, len, QueryOperand::length, MaxAllocSize, MAXSTRLEN, MAXSTRPOS, OP_AND, OP_NOT, OP_OR, OP_PHRASE, oper(), QueryOperator::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, size, TSQueryData::size, QueryItem::type, val, QueryOperand::valcrc, and QueryOperand::weight.

◆ tsquerysend()

Datum tsquerysend ( PG_FUNCTION_ARGS  )

Definition at line 1192 of file tsquery.c.

1193 {
1194  TSQuery query = PG_GETARG_TSQUERY(0);
1196  int i;
1197  QueryItem *item = GETQUERY(query);
1198 
1199  pq_begintypsend(&buf);
1200 
1201  pq_sendint32(&buf, query->size);
1202  for (i = 0; i < query->size; i++)
1203  {
1204  pq_sendint8(&buf, item->type);
1205 
1206  switch (item->type)
1207  {
1208  case QI_VAL:
1209  pq_sendint8(&buf, item->qoperand.weight);
1210  pq_sendint8(&buf, item->qoperand.prefix);
1211  pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
1212  break;
1213  case QI_OPR:
1214  pq_sendint8(&buf, item->qoperator.oper);
1215  if (item->qoperator.oper == OP_PHRASE)
1217  break;
1218  default:
1219  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1220  }
1221  item++;
1222  }
1223 
1224  PG_FREE_IF_COPY(query, 0);
1225 
1227 }
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
void pq_sendstring(StringInfo buf, const char *str)
Definition: pqformat.c:195
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:128
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:136

References 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.

◆ tsquerytree()

Datum tsquerytree ( PG_FUNCTION_ARGS  )

Definition at line 1366 of file tsquery.c.

1367 {
1368  TSQuery query = PG_GETARG_TSQUERY(0);
1369  INFIX nrm;
1370  text *res;
1371  QueryItem *q;
1372  int len;
1373 
1374  if (query->size == 0)
1375  {
1376  res = (text *) palloc(VARHDRSZ);
1379  }
1380 
1381  q = clean_NOT(GETQUERY(query), &len);
1382 
1383  if (!q)
1384  {
1385  res = cstring_to_text("T");
1386  }
1387  else
1388  {
1389  nrm.curpol = q;
1390  nrm.buflen = 32;
1391  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1392  *(nrm.cur) = '\0';
1393  nrm.op = GETOPERAND(query);
1394  infix(&nrm, -1, false);
1395  res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
1396  pfree(q);
1397  }
1398 
1399  PG_FREE_IF_COPY(query, 0);
1400 
1402 }
#define VARHDRSZ
Definition: c.h:692
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
Definition: c.h:687
QueryItem * clean_NOT(QueryItem *ptr, int *len)
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196
text * cstring_to_text(const char *s)
Definition: varlena.c:184

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

Variable Documentation

◆ tsearch_op_priority

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

Definition at line 29 of file tsquery.c.