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}
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
static pg_noinline void Size size
Definition: slab.c:607
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, calcstrlen(), NODE::left, QueryOperand::length, OP_NOT, QueryOperator::oper, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, NODE::right, size, QueryItem::type, and NODE::valnode.

Referenced by calcstrlen(), and 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
195}
const void size_t len
tree ctl root
Definition: radixtree.h:1857
Definition: _int_bool.c:26
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(), plaintree(), and root.

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:1521
void check_stack_depth(void)
Definition: stack_depth.c:95
#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(), clean_NOT_intree(), 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(), and clean_NOT_intree().

◆ 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:955
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(), clean_stopword_intree(), 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 clean_stopword_intree(), and 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;
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)
409 (errmsg("text-search query contains only stop words or doesn't contain lexemes, ignored")));
410 out = palloc(HDRSIZETQ);
411 out->size = 0;
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:1070
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:72
#define GETOPERAND(x)
Definition: ltree.h:165
void * palloc(Size size)
Definition: mcxt.c:1317
QueryItemType type
Definition: ts_type.h:158
uint32 distance
Definition: ts_type.h:172
int32 size
Definition: ts_type.h:221
static ItemArray items
Definition: test_tidstore.c:48
#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, items, len, QueryOperand::length, maketree(), NOTICE, palloc(), plaintree(), QI_VAL, root, 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(), freetree(), NODE::left, pfree(), and NODE::right.

Referenced by clean_NOT_intree(), clean_stopword_intree(), and freetree().

◆ 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, maketree(), OP_NOT, QueryOperator::oper, palloc(), QI_OPR, QueryItem::qoperator, NODE::right, QueryItem::type, and NODE::valnode.

Referenced by clean_NOT(), cleanup_tsquery_stopwords(), and maketree().

◆ 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:29
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
Definition: regguts.h:323
static void plainnode(PLAINTREE *state, NODE *node)

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

Referenced by plainnode(), and 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, and root.

Referenced by clean_NOT(), and cleanup_tsquery_stopwords().