PostgreSQL Source Code  git master
tsquery_cleanup.c File Reference
#include "postgres.h"
#include "miscadmin.h"
#include "tsearch/ts_utils.h"
#include "varatt.h"
Include dependency graph for tsquery_cleanup.c:

Go to the source code of this file.

Data Structures

struct  NODE
 
struct  PLAINTREE
 

Typedefs

typedef struct NODE NODE
 

Functions

static NODEmaketree (QueryItem *in)
 
static void plainnode (PLAINTREE *state, NODE *node)
 
static QueryItemplaintree (NODE *root, int *len)
 
static void freetree (NODE *node)
 
static NODEclean_NOT_intree (NODE *node)
 
QueryItemclean_NOT (QueryItem *ptr, int *len)
 
static NODEclean_stopword_intree (NODE *node, int *ladd, int *radd)
 
static int32 calcstrlen (NODE *node)
 
TSQuery cleanup_tsquery_stopwords (TSQuery in, bool noisy)
 

Typedef Documentation

◆ NODE

typedef struct NODE NODE

Function Documentation

◆ calcstrlen()

static int32 calcstrlen ( NODE node)
static

Definition at line 363 of file tsquery_cleanup.c.

364 {
365  int32 size = 0;
366 
367  if (node->valnode->type == QI_VAL)
368  {
369  size = node->valnode->qoperand.length + 1;
370  }
371  else
372  {
373  Assert(node->valnode->type == QI_OPR);
374 
375  size = calcstrlen(node->right);
376  if (node->valnode->qoperator.oper != OP_NOT)
377  size += calcstrlen(node->left);
378  }
379 
380  return size;
381 }
signed int int32
Definition: c.h:478
Assert(fmt[strlen(fmt) - 1] !='\n')
struct NODE * right
QueryItem * valnode
struct NODE * left
uint32 length
Definition: ts_type.h:171
#define QI_OPR
Definition: ts_type.h:150
#define QI_VAL
Definition: ts_type.h:149
#define OP_NOT
Definition: ts_type.h:179
static int32 calcstrlen(NODE *node)
QueryOperator qoperator
Definition: ts_type.h:209
QueryOperand qoperand
Definition: ts_type.h:210
QueryItemType type
Definition: ts_type.h:208

References Assert(), NODE::left, QueryOperand::length, OP_NOT, QueryOperator::oper, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, NODE::right, QueryItem::type, and NODE::valnode.

Referenced by cleanup_tsquery_stopwords().

◆ clean_NOT()

QueryItem* clean_NOT ( QueryItem ptr,
int *  len 
)

Definition at line 190 of file tsquery_cleanup.c.

191 {
192  NODE *root = maketree(ptr);
193 
194  return plaintree(clean_NOT_intree(root), len);
195 }
const void size_t len
Definition: _int_bool.c:27
static NODE * clean_NOT_intree(NODE *node)
static NODE * maketree(QueryItem *in)
static QueryItem * plaintree(NODE *root, int *len)

References clean_NOT_intree(), len, maketree(), and plaintree().

Referenced by tsquerytree().

◆ clean_NOT_intree()

static NODE* clean_NOT_intree ( NODE node)
static

Definition at line 136 of file tsquery_cleanup.c.

137 {
138  /* since this function recurses, it could be driven to stack overflow. */
140 
141  if (node->valnode->type == QI_VAL)
142  return node;
143 
144  if (node->valnode->qoperator.oper == OP_NOT)
145  {
146  freetree(node);
147  return NULL;
148  }
149 
150  /* operator & or | */
151  if (node->valnode->qoperator.oper == OP_OR)
152  {
153  if ((node->left = clean_NOT_intree(node->left)) == NULL ||
154  (node->right = clean_NOT_intree(node->right)) == NULL)
155  {
156  freetree(node);
157  return NULL;
158  }
159  }
160  else
161  {
162  NODE *res = node;
163 
164  Assert(node->valnode->qoperator.oper == OP_AND ||
165  node->valnode->qoperator.oper == OP_PHRASE);
166 
167  node->left = clean_NOT_intree(node->left);
168  node->right = clean_NOT_intree(node->right);
169  if (node->left == NULL && node->right == NULL)
170  {
171  pfree(node);
172  res = NULL;
173  }
174  else if (node->left == NULL)
175  {
176  res = node->right;
177  pfree(node);
178  }
179  else if (node->right == NULL)
180  {
181  res = node->left;
182  pfree(node);
183  }
184  return res;
185  }
186  return node;
187 }
void pfree(void *pointer)
Definition: mcxt.c:1456
void check_stack_depth(void)
Definition: postgres.c:3508
#define OP_AND
Definition: ts_type.h:180
#define OP_PHRASE
Definition: ts_type.h:182
#define OP_OR
Definition: ts_type.h:181
static void freetree(NODE *node)

References Assert(), check_stack_depth(), freetree(), NODE::left, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, pfree(), QI_VAL, QueryItem::qoperator, res, NODE::right, QueryItem::type, and NODE::valnode.

Referenced by clean_NOT().

◆ clean_stopword_intree()

static NODE* clean_stopword_intree ( NODE node,
int *  ladd,
int *  radd 
)
static

Definition at line 238 of file tsquery_cleanup.c.

239 {
240  /* since this function recurses, it could be driven to stack overflow. */
242 
243  /* default output parameters indicate no change in parent distance */
244  *ladd = *radd = 0;
245 
246  if (node->valnode->type == QI_VAL)
247  return node;
248  else if (node->valnode->type == QI_VALSTOP)
249  {
250  pfree(node);
251  return NULL;
252  }
253 
254  Assert(node->valnode->type == QI_OPR);
255 
256  if (node->valnode->qoperator.oper == OP_NOT)
257  {
258  /* NOT doesn't change pattern width, so just report child distances */
259  node->right = clean_stopword_intree(node->right, ladd, radd);
260  if (!node->right)
261  {
262  freetree(node);
263  return NULL;
264  }
265  }
266  else
267  {
268  NODE *res = node;
269  bool isphrase;
270  int ndistance,
271  lladd,
272  lradd,
273  rladd,
274  rradd;
275 
276  /* First, recurse */
277  node->left = clean_stopword_intree(node->left, &lladd, &lradd);
278  node->right = clean_stopword_intree(node->right, &rladd, &rradd);
279 
280  /* Check if current node is OP_PHRASE, get its distance */
281  isphrase = (node->valnode->qoperator.oper == OP_PHRASE);
282  ndistance = isphrase ? node->valnode->qoperator.distance : 0;
283 
284  if (node->left == NULL && node->right == NULL)
285  {
286  /*
287  * When we collapse out a phrase node entirely, propagate its own
288  * distance into both *ladd and *radd; it is the responsibility of
289  * the parent node to count it only once. Also, for a phrase
290  * node, distances coming from children are summed and propagated
291  * up to parent (we assume lladd == lradd and rladd == rradd, else
292  * rule was broken at a lower level). But if this isn't a phrase
293  * node, take the larger of the two child distances; that
294  * corresponds to what TS_execute will do in non-stopword cases.
295  */
296  if (isphrase)
297  *ladd = *radd = lladd + ndistance + rladd;
298  else
299  *ladd = *radd = Max(lladd, rladd);
300  freetree(node);
301  return NULL;
302  }
303  else if (node->left == NULL)
304  {
305  /* Removing this operator and left subnode */
306  /* lladd and lradd are equal/redundant, don't count both */
307  if (isphrase)
308  {
309  /* operator's own distance must propagate to left */
310  *ladd = lladd + ndistance + rladd;
311  *radd = rradd;
312  }
313  else
314  {
315  /* at non-phrase op, just forget the left subnode entirely */
316  *ladd = rladd;
317  *radd = rradd;
318  }
319  res = node->right;
320  pfree(node);
321  }
322  else if (node->right == NULL)
323  {
324  /* Removing this operator and right subnode */
325  /* rladd and rradd are equal/redundant, don't count both */
326  if (isphrase)
327  {
328  /* operator's own distance must propagate to right */
329  *ladd = lladd;
330  *radd = lradd + ndistance + rradd;
331  }
332  else
333  {
334  /* at non-phrase op, just forget the right subnode entirely */
335  *ladd = lladd;
336  *radd = lradd;
337  }
338  res = node->left;
339  pfree(node);
340  }
341  else if (isphrase)
342  {
343  /* Absorb appropriate corrections at this level */
344  node->valnode->qoperator.distance += lradd + rladd;
345  /* Propagate up any unaccounted-for corrections */
346  *ladd = lladd;
347  *radd = rradd;
348  }
349  else
350  {
351  /* We're keeping a non-phrase operator, so ladd/radd remain 0 */
352  }
353 
354  return res;
355  }
356  return node;
357 }
#define Max(x, y)
Definition: c.h:982
int16 distance
Definition: ts_type.h:196
#define QI_VALSTOP
Definition: ts_type.h:151
static NODE * clean_stopword_intree(NODE *node, int *ladd, int *radd)

References Assert(), check_stack_depth(), QueryOperator::distance, freetree(), NODE::left, Max, OP_NOT, OP_PHRASE, QueryOperator::oper, pfree(), QI_OPR, QI_VAL, QI_VALSTOP, QueryItem::qoperator, res, NODE::right, QueryItem::type, and NODE::valnode.

Referenced by cleanup_tsquery_stopwords().

◆ cleanup_tsquery_stopwords()

TSQuery cleanup_tsquery_stopwords ( TSQuery  in,
bool  noisy 
)

Definition at line 387 of file tsquery_cleanup.c.

388 {
389  int32 len,
390  lenstr,
391  commonlen,
392  i;
393  NODE *root;
394  int ladd,
395  radd;
396  TSQuery out;
397  QueryItem *items;
398  char *operands;
399 
400  if (in->size == 0)
401  return in;
402 
403  /* eliminate stop words */
404  root = clean_stopword_intree(maketree(GETQUERY(in)), &ladd, &radd);
405  if (root == NULL)
406  {
407  if (noisy)
408  ereport(NOTICE,
409  (errmsg("text-search query contains only stop words or doesn't contain lexemes, ignored")));
410  out = palloc(HDRSIZETQ);
411  out->size = 0;
412  SET_VARSIZE(out, HDRSIZETQ);
413  return out;
414  }
415 
416  /*
417  * Build TSQuery from plain view
418  */
419 
420  lenstr = calcstrlen(root);
421  items = plaintree(root, &len);
422  commonlen = COMPUTESIZE(len, lenstr);
423 
424  out = palloc(commonlen);
425  SET_VARSIZE(out, commonlen);
426  out->size = len;
427 
428  memcpy(GETQUERY(out), items, len * sizeof(QueryItem));
429 
430  items = GETQUERY(out);
431  operands = GETOPERAND(out);
432  for (i = 0; i < out->size; i++)
433  {
434  QueryOperand *op = (QueryOperand *) &items[i];
435 
436  if (op->type != QI_VAL)
437  continue;
438 
439  memcpy(operands, GETOPERAND(in) + op->distance, op->length);
440  operands[op->length] = '\0';
441  op->distance = operands - GETOPERAND(out);
442  operands += op->length + 1;
443  }
444 
445  return out;
446 }
#define COMPUTESIZE(size)
Definition: _int.h:155
#define GETQUERY(x)
Definition: _int.h:157
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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 * palloc(Size size)
Definition: mcxt.c:1226
QueryItemType type
Definition: ts_type.h:158
uint32 distance
Definition: ts_type.h:172
int32 size
Definition: ts_type.h:221
#define HDRSIZETQ
Definition: ts_type.h:227
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References calcstrlen(), clean_stopword_intree(), COMPUTESIZE, QueryOperand::distance, ereport, errmsg(), GETOPERAND, GETQUERY, HDRSIZETQ, i, len, QueryOperand::length, maketree(), NOTICE, palloc(), plaintree(), QI_VAL, SET_VARSIZE, TSQueryData::size, and QueryOperand::type.

Referenced by parse_tsquery().

◆ freetree()

static void freetree ( NODE node)
static

Definition at line 115 of file tsquery_cleanup.c.

116 {
117  /* since this function recurses, it could be driven to stack overflow. */
119 
120  if (!node)
121  return;
122  if (node->left)
123  freetree(node->left);
124  if (node->right)
125  freetree(node->right);
126  pfree(node);
127 }

References check_stack_depth(), NODE::left, pfree(), and NODE::right.

Referenced by clean_NOT_intree(), and clean_stopword_intree().

◆ maketree()

static NODE* maketree ( QueryItem in)
static

Definition at line 33 of file tsquery_cleanup.c.

34 {
35  NODE *node = (NODE *) palloc(sizeof(NODE));
36 
37  /* since this function recurses, it could be driven to stack overflow. */
39 
40  node->valnode = in;
41  node->right = node->left = NULL;
42  if (in->type == QI_OPR)
43  {
44  node->right = maketree(in + 1);
45  if (in->qoperator.oper != OP_NOT)
46  node->left = maketree(in + in->qoperator.left);
47  }
48  return node;
49 }
uint32 left
Definition: ts_type.h:197

References check_stack_depth(), NODE::left, QueryOperator::left, OP_NOT, QueryOperator::oper, palloc(), QI_OPR, QueryItem::qoperator, NODE::right, QueryItem::type, and NODE::valnode.

Referenced by clean_NOT(), and cleanup_tsquery_stopwords().

◆ plainnode()

static void plainnode ( PLAINTREE state,
NODE node 
)
static

Definition at line 62 of file tsquery_cleanup.c.

63 {
64  /* since this function recurses, it could be driven to stack overflow. */
66 
67  if (state->cur == state->len)
68  {
69  state->len *= 2;
70  state->ptr = (QueryItem *) repalloc(state->ptr, state->len * sizeof(QueryItem));
71  }
72  memcpy(&(state->ptr[state->cur]), node->valnode, sizeof(QueryItem));
73  if (node->valnode->type == QI_VAL)
74  state->cur++;
75  else if (node->valnode->qoperator.oper == OP_NOT)
76  {
77  state->ptr[state->cur].qoperator.left = 1;
78  state->cur++;
79  plainnode(state, node->right);
80  }
81  else
82  {
83  int cur = state->cur;
84 
85  state->cur++;
86  plainnode(state, node->right);
87  state->ptr[cur].qoperator.left = state->cur - cur;
88  plainnode(state, node->left);
89  }
90  pfree(node);
91 }
struct cursor * cur
Definition: ecpg.c:28
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
Definition: regguts.h:323
static void plainnode(PLAINTREE *state, NODE *node)

References check_stack_depth(), cur, NODE::left, OP_NOT, QueryOperator::oper, pfree(), QI_VAL, QueryItem::qoperator, repalloc(), NODE::right, QueryItem::type, and NODE::valnode.

Referenced by plaintree().

◆ plaintree()

static QueryItem* plaintree ( NODE root,
int *  len 
)
static

Definition at line 97 of file tsquery_cleanup.c.

98 {
99  PLAINTREE pl;
100 
101  pl.cur = 0;
102  pl.len = 16;
103  if (root && (root->valnode->type == QI_VAL || root->valnode->type == QI_OPR))
104  {
105  pl.ptr = (QueryItem *) palloc(pl.len * sizeof(QueryItem));
106  plainnode(&pl, root);
107  }
108  else
109  pl.ptr = NULL;
110  *len = pl.cur;
111  return pl.ptr;
112 }
QueryItem * ptr

References PLAINTREE::cur, PLAINTREE::len, len, palloc(), plainnode(), PLAINTREE::ptr, QI_OPR, QI_VAL, QueryItem::type, and NODE::valnode.

Referenced by clean_NOT(), and cleanup_tsquery_stopwords().