PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tsquery_util.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * tsquery_util.c
4  * Utilities for tsquery datatype
5  *
6  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7  *
8  *
9  * IDENTIFICATION
10  * src/backend/utils/adt/tsquery_util.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "tsearch/ts_utils.h"
18 #include "miscadmin.h"
19 
20 QTNode *
21 QT2QTN(QueryItem *in, char *operand)
22 {
23  QTNode *node = (QTNode *) palloc0(sizeof(QTNode));
24 
25  /* since this function recurses, it could be driven to stack overflow. */
27 
28  node->valnode = in;
29 
30  if (in->type == QI_OPR)
31  {
32  node->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
33  node->child[0] = QT2QTN(in + 1, operand);
34  node->sign = node->child[0]->sign;
35  if (in->qoperator.oper == OP_NOT)
36  node->nchild = 1;
37  else
38  {
39  node->nchild = 2;
40  node->child[1] = QT2QTN(in + in->qoperator.left, operand);
41  node->sign |= node->child[1]->sign;
42  }
43  }
44  else if (operand)
45  {
46  node->word = operand + in->qoperand.distance;
47  node->sign = ((uint32) 1) << (((unsigned int) in->qoperand.valcrc) % 32);
48  }
49 
50  return node;
51 }
52 
53 void
55 {
56  if (!in)
57  return;
58 
59  /* since this function recurses, it could be driven to stack overflow. */
61 
62  if (in->valnode->type == QI_VAL && in->word && (in->flags & QTN_WORDFREE) != 0)
63  pfree(in->word);
64 
65  if (in->child)
66  {
67  if (in->valnode)
68  {
69  if (in->valnode->type == QI_OPR && in->nchild > 0)
70  {
71  int i;
72 
73  for (i = 0; i < in->nchild; i++)
74  QTNFree(in->child[i]);
75  }
76  if (in->flags & QTN_NEEDFREE)
77  pfree(in->valnode);
78  }
79  pfree(in->child);
80  }
81 
82  pfree(in);
83 }
84 
85 int
87 {
88  /* since this function recurses, it could be driven to stack overflow. */
90 
91  if (an->valnode->type != bn->valnode->type)
92  return (an->valnode->type > bn->valnode->type) ? -1 : 1;
93 
94  if (an->valnode->type == QI_OPR)
95  {
96  QueryOperator *ao = &an->valnode->qoperator;
97  QueryOperator *bo = &bn->valnode->qoperator;
98 
99  if (ao->oper != bo->oper)
100  return (ao->oper > bo->oper) ? -1 : 1;
101 
102  if (an->nchild != bn->nchild)
103  return (an->nchild > bn->nchild) ? -1 : 1;
104 
105  {
106  int i,
107  res;
108 
109  for (i = 0; i < an->nchild; i++)
110  if ((res = QTNodeCompare(an->child[i], bn->child[i])) != 0)
111  return res;
112  }
113 
114  if (ao->oper == OP_PHRASE && ao->distance != bo->distance)
115  return (ao->distance > bo->distance) ? -1 : 1;
116 
117  return 0;
118  }
119  else if (an->valnode->type == QI_VAL)
120  {
121  QueryOperand *ao = &an->valnode->qoperand;
122  QueryOperand *bo = &bn->valnode->qoperand;
123 
124  if (ao->valcrc != bo->valcrc)
125  {
126  return (ao->valcrc > bo->valcrc) ? -1 : 1;
127  }
128 
129  return tsCompareString(an->word, ao->length, bn->word, bo->length, false);
130  }
131  else
132  {
133  elog(ERROR, "unrecognized QueryItem type: %d", an->valnode->type);
134  return 0; /* keep compiler quiet */
135  }
136 }
137 
138 static int
139 cmpQTN(const void *a, const void *b)
140 {
141  return QTNodeCompare(*(QTNode *const *) a, *(QTNode *const *) b);
142 }
143 
144 void
146 {
147  int i;
148 
149  /* since this function recurses, it could be driven to stack overflow. */
151 
152  if (in->valnode->type != QI_OPR)
153  return;
154 
155  for (i = 0; i < in->nchild; i++)
156  QTNSort(in->child[i]);
157  if (in->nchild > 1 && in->valnode->qoperator.oper != OP_PHRASE)
158  qsort((void *) in->child, in->nchild, sizeof(QTNode *), cmpQTN);
159 }
160 
161 bool
163 {
164  uint32 sign = a->sign & b->sign;
165 
166  if (!(sign == a->sign && sign == b->sign))
167  return 0;
168 
169  return (QTNodeCompare(a, b) == 0) ? true : false;
170 }
171 
172 /*
173  * Remove unnecessary intermediate nodes. For example:
174  *
175  * OR OR
176  * a OR -> a b c
177  * b c
178  */
179 void
181 {
182  int i;
183 
184  /* since this function recurses, it could be driven to stack overflow. */
186 
187  if (in->valnode->type != QI_OPR)
188  return;
189 
190  for (i = 0; i < in->nchild; i++)
191  QTNTernary(in->child[i]);
192 
193  for (i = 0; i < in->nchild; i++)
194  {
195  QTNode *cc = in->child[i];
196 
197  /* OP_Phrase isn't associative */
198  if (cc->valnode->type == QI_OPR &&
199  in->valnode->qoperator.oper == cc->valnode->qoperator.oper &&
201  {
202  int oldnchild = in->nchild;
203 
204  in->nchild += cc->nchild - 1;
205  in->child = (QTNode **) repalloc(in->child, in->nchild * sizeof(QTNode *));
206 
207  if (i + 1 != oldnchild)
208  memmove(in->child + i + cc->nchild, in->child + i + 1,
209  (oldnchild - i - 1) * sizeof(QTNode *));
210 
211  memcpy(in->child + i, cc->child, cc->nchild * sizeof(QTNode *));
212  i += cc->nchild - 1;
213 
214  if (cc->flags & QTN_NEEDFREE)
215  pfree(cc->valnode);
216  pfree(cc);
217  }
218  }
219 }
220 
221 /*
222  * Convert a tree to binary tree by inserting intermediate nodes.
223  * (Opposite of QTNTernary)
224  */
225 void
227 {
228  int i;
229 
230  /* since this function recurses, it could be driven to stack overflow. */
232 
233  if (in->valnode->type != QI_OPR)
234  return;
235 
236  for (i = 0; i < in->nchild; i++)
237  QTNBinary(in->child[i]);
238 
239  if (in->nchild <= 2)
240  return;
241 
242  while (in->nchild > 2)
243  {
244  QTNode *nn = (QTNode *) palloc0(sizeof(QTNode));
245 
246  nn->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
247  nn->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
248 
249  nn->nchild = 2;
250  nn->flags = QTN_NEEDFREE;
251 
252  nn->child[0] = in->child[0];
253  nn->child[1] = in->child[1];
254  nn->sign = nn->child[0]->sign | nn->child[1]->sign;
255 
256  nn->valnode->type = in->valnode->type;
258 
259  in->child[0] = nn;
260  in->child[1] = in->child[in->nchild - 1];
261  in->nchild--;
262  }
263 }
264 
265 /*
266  * Count the total length of operand string in tree, including '\0'-
267  * terminators.
268  */
269 static void
270 cntsize(QTNode *in, int *sumlen, int *nnode)
271 {
272  /* since this function recurses, it could be driven to stack overflow. */
274 
275  *nnode += 1;
276  if (in->valnode->type == QI_OPR)
277  {
278  int i;
279 
280  for (i = 0; i < in->nchild; i++)
281  cntsize(in->child[i], sumlen, nnode);
282  }
283  else
284  {
285  *sumlen += in->valnode->qoperand.length + 1;
286  }
287 }
288 
289 typedef struct
290 {
292  char *operand;
293  char *curoperand;
294 } QTN2QTState;
295 
296 static void
298 {
299  /* since this function recurses, it could be driven to stack overflow. */
301 
302  if (in->valnode->type == QI_VAL)
303  {
304  memcpy(state->curitem, in->valnode, sizeof(QueryOperand));
305 
306  memcpy(state->curoperand, in->word, in->valnode->qoperand.length);
307  state->curitem->qoperand.distance = state->curoperand - state->operand;
308  state->curoperand[in->valnode->qoperand.length] = '\0';
309  state->curoperand += in->valnode->qoperand.length + 1;
310  state->curitem++;
311  }
312  else
313  {
314  QueryItem *curitem = state->curitem;
315 
316  Assert(in->valnode->type == QI_OPR);
317 
318  memcpy(state->curitem, in->valnode, sizeof(QueryOperator));
319 
320  Assert(in->nchild <= 2);
321  state->curitem++;
322 
323  fillQT(state, in->child[0]);
324 
325  if (in->nchild == 2)
326  {
327  curitem->qoperator.left = state->curitem - curitem;
328  fillQT(state, in->child[1]);
329  }
330  }
331 }
332 
333 TSQuery
335 {
336  TSQuery out;
337  int len;
338  int sumlen = 0,
339  nnode = 0;
341 
342  cntsize(in, &sumlen, &nnode);
343 
344  if (TSQUERY_TOO_BIG(nnode, sumlen))
345  ereport(ERROR,
346  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
347  errmsg("tsquery is too large")));
348  len = COMPUTESIZE(nnode, sumlen);
349 
350  out = (TSQuery) palloc0(len);
351  SET_VARSIZE(out, len);
352  out->size = nnode;
353 
354  state.curitem = GETQUERY(out);
355  state.operand = state.curoperand = GETOPERAND(out);
356 
357  fillQT(&state, in);
358  return out;
359 }
360 
361 QTNode *
363 {
364  QTNode *out;
365 
366  /* since this function recurses, it could be driven to stack overflow. */
368 
369  out = (QTNode *) palloc(sizeof(QTNode));
370 
371  *out = *in;
372  out->valnode = (QueryItem *) palloc(sizeof(QueryItem));
373  *(out->valnode) = *(in->valnode);
374  out->flags |= QTN_NEEDFREE;
375 
376  if (in->valnode->type == QI_VAL)
377  {
378  out->word = palloc(in->valnode->qoperand.length + 1);
379  memcpy(out->word, in->word, in->valnode->qoperand.length);
380  out->word[in->valnode->qoperand.length] = '\0';
381  out->flags |= QTN_WORDFREE;
382  }
383  else
384  {
385  int i;
386 
387  out->child = (QTNode **) palloc(sizeof(QTNode *) * in->nchild);
388 
389  for (i = 0; i < in->nchild; i++)
390  out->child[i] = QTNCopy(in->child[i]);
391  }
392 
393  return out;
394 }
395 
396 void
398 {
399  /* since this function recurses, it could be driven to stack overflow. */
401 
402  in->flags &= ~flags;
403 
404  if (in->valnode->type != QI_VAL)
405  {
406  int i;
407 
408  for (i = 0; i < in->nchild; i++)
409  QTNClearFlags(in->child[i], flags);
410  }
411 }
void QTNTernary(QTNode *in)
Definition: tsquery_util.c:180
QueryOperator qoperator
Definition: ts_type.h:266
#define TSQUERY_TOO_BIG(size, lenofoperand)
Definition: ts_type.h:290
char * word
Definition: ts_utils.h:188
void QTNBinary(QTNode *in)
Definition: tsquery_util.c:226
void QTNFree(QTNode *in)
Definition: tsquery_util.c:54
uint32 sign
Definition: ts_utils.h:189
QTNode * QT2QTN(QueryItem *in, char *operand)
Definition: tsquery_util.c:21
QTNode * QTNCopy(QTNode *in)
Definition: tsquery_util.c:362
TSQueryData * TSQuery
Definition: ts_type.h:282
int errcode(int sqlerrcode)
Definition: elog.c:575
#define QI_VAL
Definition: ts_type.h:189
uint32 distance
Definition: ts_type.h:213
int16 distance
Definition: ts_type.h:253
static void fillQT(QTN2QTState *state, QTNode *in)
Definition: tsquery_util.c:297
#define GETQUERY(x)
Definition: _int.h:142
QueryItem * curitem
Definition: tsquery_util.c:291
#define GETOPERAND(x)
Definition: ltree.h:118
void pfree(void *pointer)
Definition: mcxt.c:995
#define ERROR
Definition: elog.h:43
char sign
Definition: informix.c:693
#define memmove(d, s, c)
Definition: c.h:1038
void check_stack_depth(void)
Definition: postgres.c:3095
int32 valcrc
Definition: ts_type.h:206
TSQuery QTN2QT(QTNode *in)
Definition: tsquery_util.c:334
unsigned int uint32
Definition: c.h:265
char * curoperand
Definition: tsquery_util.c:293
#define ereport(elevel, rest)
Definition: elog.h:122
void QTNSort(QTNode *in)
Definition: tsquery_util.c:145
void QTNClearFlags(QTNode *in, uint32 flags)
Definition: tsquery_util.c:397
#define QI_OPR
Definition: ts_type.h:190
QueryItemType type
Definition: ts_type.h:265
void * palloc0(Size size)
Definition: mcxt.c:923
#define COMPUTESIZE(size)
Definition: _int.h:140
#define Assert(condition)
Definition: c.h:667
Definition: regguts.h:313
#define OP_PHRASE
Definition: ts_type.h:228
bool QTNEq(QTNode *a, QTNode *b)
Definition: tsquery_util.c:162
#define QTN_WORDFREE
Definition: ts_utils.h:196
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1090
struct QTNode ** child
Definition: ts_utils.h:190
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1024
#define QTN_NEEDFREE
Definition: ts_utils.h:194
uint32 length
Definition: ts_type.h:213
char * operand
Definition: tsquery_util.c:292
uint32 left
Definition: ts_type.h:254
QueryItem * valnode
Definition: ts_utils.h:185
int32 nchild
Definition: ts_utils.h:187
void * palloc(Size size)
Definition: mcxt.c:894
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 size
Definition: ts_type.h:278
int i
int QTNodeCompare(QTNode *an, QTNode *bn)
Definition: tsquery_util.c:86
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:330
#define elog
Definition: elog.h:218
QueryOperand qoperand
Definition: ts_type.h:267
#define qsort(a, b, c, d)
Definition: port.h:438
static void cntsize(QTNode *in, int *sumlen, int *nnode)
Definition: tsquery_util.c:270
static int cmpQTN(const void *a, const void *b)
Definition: tsquery_util.c:139
uint32 flags
Definition: ts_utils.h:186
#define OP_NOT
Definition: ts_type.h:225