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

◆ STACKDEPTH

#define STACKDEPTH   32

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

650 {
651  int opPriority = OP_PRIORITY(op);
652 
653  while (*lenstack)
654  {
655  /* NOT is right associative unlike to others */
656  if ((op != OP_NOT && opPriority > OP_PRIORITY(stack[*lenstack - 1].op)) ||
657  (op == OP_NOT && opPriority >= OP_PRIORITY(stack[*lenstack - 1].op)))
658  break;
659 
660  (*lenstack)--;
661  pushOperator(state, stack[*lenstack].op,
662  stack[*lenstack].distance);
663  }
664 }
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:531

References OP_NOT, OP_PRIORITY, and pushOperator().

Referenced by makepol().

◆ findoprnd()

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

Definition at line 784 of file tsquery.c.

785 {
786  uint32 pos;
787 
788  *needcleanup = false;
789  pos = 0;
790  findoprnd_recurse(ptr, &pos, size, needcleanup);
791 
792  if (pos != size)
793  elog(ERROR, "malformed tsquery: extra nodes");
794 }
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:726

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

727 {
728  /* since this function recurses, it could be driven to stack overflow. */
730 
731  if (*pos >= nnodes)
732  elog(ERROR, "malformed tsquery: operand not found");
733 
734  if (ptr[*pos].type == QI_VAL)
735  {
736  (*pos)++;
737  }
738  else if (ptr[*pos].type == QI_VALSTOP)
739  {
740  *needcleanup = true; /* we'll have to remove stop words */
741  (*pos)++;
742  }
743  else
744  {
745  Assert(ptr[*pos].type == QI_OPR);
746 
747  if (ptr[*pos].qoperator.oper == OP_NOT)
748  {
749  ptr[*pos].qoperator.left = 1; /* fixed offset */
750  (*pos)++;
751 
752  /* process the only argument */
753  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
754  }
755  else
756  {
757  QueryOperator *curitem = &ptr[*pos].qoperator;
758  int tmp = *pos; /* save current position */
759 
760  Assert(curitem->oper == OP_AND ||
761  curitem->oper == OP_OR ||
762  curitem->oper == OP_PHRASE);
763 
764  (*pos)++;
765 
766  /* process RIGHT argument */
767  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
768 
769  curitem->left = *pos - tmp; /* set LEFT arg's offset */
770 
771  /* process LEFT argument */
772  findoprnd_recurse(ptr, pos, nnodes, needcleanup);
773  }
774  }
775 }
#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 510 of file tsquery.c.

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

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:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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  /* ignore, 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 (*state->buf == '\0')
480  {
481  return PT_END;
482  }
483  else if (parse_or_operator(state))
484  {
485  state->state = WAITOPERAND;
486  *operator = OP_OR;
487  return PT_OPR;
488  }
489  else if (ISOPERATOR(state->buf))
490  {
491  /* ignore other operators in this state too */
492  state->buf++;
493  continue;
494  }
495  else if (!t_isspace(state->buf))
496  {
497  /* insert implicit AND between operands */
498  state->state = WAITOPERAND;
499  *operator = OP_AND;
500  return PT_OPR;
501  }
502  break;
503  }
504 
505  state->buf += pg_mblen(state->buf);
506  }
507 }
#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:616

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

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

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

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

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

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

532 {
533  QueryOperator *tmp;
534 
535  Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR || oper == OP_PHRASE);
536 
537  tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
538  tmp->type = QI_OPR;
539  tmp->oper = oper;
540  tmp->distance = (oper == OP_PHRASE) ? distance : 0;
541  /* left is filled in later with findoprnd */
542 
543  state->polstr = lcons(tmp, state->polstr);
544 }
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 636 of file tsquery.c.

637 {
638  if (*lenstack == STACKDEPTH) /* internal error */
639  elog(ERROR, "tsquery stack too small");
640 
641  stack[*lenstack].op = op;
642  stack[*lenstack].distance = distance;
643 
644  (*lenstack)++;
645 }
int16 distance
Definition: tsquery.c:632

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

Referenced by makepol().

◆ pushStop()

void pushStop ( TSQueryParserState  state)

Definition at line 616 of file tsquery.c.

617 {
618  QueryOperand *tmp;
619 
620  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
621  tmp->type = QI_VALSTOP;
622 
623  state->polstr = lcons(tmp, state->polstr);
624 }
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 942 of file tsquery.c.

944 {
945  pushValue(state, strval, lenval, weight, prefix);
946 }
void pushValue(TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:580

References pushValue().

Referenced by tsqueryin().

◆ pushValue()

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

Definition at line 580 of file tsquery.c.

581 {
582  pg_crc32 valcrc;
583 
584  if (lenval >= MAXSTRLEN)
585  ereturn(state->escontext,,
586  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
587  errmsg("word is too long in tsquery: \"%s\"",
588  state->buffer)));
589 
590  INIT_LEGACY_CRC32(valcrc);
591  COMP_LEGACY_CRC32(valcrc, strval, lenval);
592  FIN_LEGACY_CRC32(valcrc);
593  pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);
594 
595  /* append the value string to state.op, enlarging buffer if needed first */
596  while (state->curop - state->op + lenval + 1 >= state->lenop)
597  {
598  int used = state->curop - state->op;
599 
600  state->lenop *= 2;
601  state->op = (char *) repalloc(state->op, state->lenop);
602  state->curop = state->op + used;
603  }
604  memcpy(state->curop, strval, lenval);
605  state->curop += lenval;
606  *(state->curop) = '\0';
607  state->curop++;
608  state->sumlen += lenval + 1 /* \0 */ ;
609 }
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:547

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

548 {
549  QueryOperand *tmp;
550 
551  if (distance >= MAXSTRPOS)
552  ereturn(state->escontext,,
553  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
554  errmsg("value is too big in tsquery: \"%s\"",
555  state->buffer)));
556  if (lenval >= MAXSTRLEN)
557  ereturn(state->escontext,,
558  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
559  errmsg("operand is too long in tsquery: \"%s\"",
560  state->buffer)));
561 
562  tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
563  tmp->type = QI_VAL;
564  tmp->weight = weight;
565  tmp->prefix = prefix;
566  tmp->valcrc = (int32) valcrc;
567  tmp->length = lenval;
568  tmp->distance = distance;
569 
570  state->polstr = lcons(tmp, state->polstr);
571 }
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 952 of file tsquery.c.

953 {
954  char *in = PG_GETARG_CSTRING(0);
955  Node *escontext = fcinfo->context;
956 
958  pushval_asis,
959  PointerGetDatum(NULL),
960  0,
961  escontext));
962 }
#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:817
static void pushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Definition: tsquery.c:942

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

◆ tsqueryout()

Datum tsqueryout ( PG_FUNCTION_ARGS  )

Definition at line 1146 of file tsquery.c.

1147 {
1148  TSQuery query = PG_GETARG_TSQUERY(0);
1149  INFIX nrm;
1150 
1151  if (query->size == 0)
1152  {
1153  char *b = palloc(1);
1154 
1155  *b = '\0';
1157  }
1158  nrm.curpol = GETQUERY(query);
1159  nrm.buflen = 32;
1160  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1161  *(nrm.cur) = '\0';
1162  nrm.op = GETOPERAND(query);
1163  infix(&nrm, -1 /* lowest priority */ , false);
1164 
1165  PG_FREE_IF_COPY(query, 0);
1166  PG_RETURN_CSTRING(nrm.buf);
1167 }
#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 1226 of file tsquery.c.

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

1189 {
1190  TSQuery query = PG_GETARG_TSQUERY(0);
1192  int i;
1193  QueryItem *item = GETQUERY(query);
1194 
1195  pq_begintypsend(&buf);
1196 
1197  pq_sendint32(&buf, query->size);
1198  for (i = 0; i < query->size; i++)
1199  {
1200  pq_sendint8(&buf, item->type);
1201 
1202  switch (item->type)
1203  {
1204  case QI_VAL:
1205  pq_sendint8(&buf, item->qoperand.weight);
1206  pq_sendint8(&buf, item->qoperand.prefix);
1207  pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
1208  break;
1209  case QI_OPR:
1210  pq_sendint8(&buf, item->qoperator.oper);
1211  if (item->qoperator.oper == OP_PHRASE)
1213  break;
1214  default:
1215  elog(ERROR, "unrecognized tsquery node type: %d", item->type);
1216  }
1217  item++;
1218  }
1219 
1220  PG_FREE_IF_COPY(query, 0);
1221 
1223 }
#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 1362 of file tsquery.c.

1363 {
1364  TSQuery query = PG_GETARG_TSQUERY(0);
1365  INFIX nrm;
1366  text *res;
1367  QueryItem *q;
1368  int len;
1369 
1370  if (query->size == 0)
1371  {
1372  res = (text *) palloc(VARHDRSZ);
1375  }
1376 
1377  q = clean_NOT(GETQUERY(query), &len);
1378 
1379  if (!q)
1380  {
1381  res = cstring_to_text("T");
1382  }
1383  else
1384  {
1385  nrm.curpol = q;
1386  nrm.buflen = 32;
1387  nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
1388  *(nrm.cur) = '\0';
1389  nrm.op = GETOPERAND(query);
1390  infix(&nrm, -1, false);
1391  res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
1392  pfree(q);
1393  }
1394 
1395  PG_FREE_IF_COPY(query, 0);
1396 
1398 }
#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.