1 /*-------------------------------------------------------------------------
4 * Cleanup query from NOT values and/or stopword
5 * Utility functions to correct work.
7 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
11 * src/backend/utils/adt/tsquery_cleanup.c
13 *-------------------------------------------------------------------------
18 #include "tsearch/ts_utils.h"
19 #include "miscadmin.h"
29 * make query tree from plain view of query
32 maketree(QueryItem *in)
34 NODE *node = (NODE *) palloc(sizeof(NODE));
36 /* since this function recurses, it could be driven to stack overflow. */
40 node->right = node->left = NULL;
41 if (in->type == QI_OPR)
43 node->right = maketree(in + 1);
44 if (in->qoperator.oper != OP_NOT)
45 node->left = maketree(in + in->qoperator.left);
51 * Internal state for plaintree and plainnode
56 int len; /* allocated size of ptr */
57 int cur; /* number of elements in ptr */
61 plainnode(PLAINTREE *state, NODE *node)
63 /* since this function recurses, it could be driven to stack overflow. */
66 if (state->cur == state->len)
69 state->ptr = (QueryItem *) repalloc((void *) state->ptr, state->len * sizeof(QueryItem));
71 memcpy((void *) &(state->ptr[state->cur]), (void *) node->valnode, sizeof(QueryItem));
72 if (node->valnode->type == QI_VAL)
74 else if (node->valnode->qoperator.oper == OP_NOT)
76 state->ptr[state->cur].qoperator.left = 1;
78 plainnode(state, node->right);
85 plainnode(state, node->right);
86 state->ptr[cur].qoperator.left = state->cur - cur;
87 plainnode(state, node->left);
93 * make plain view of tree from a NODE-tree representation
96 plaintree(NODE *root, int *len)
102 if (root && (root->valnode->type == QI_VAL || root->valnode->type == QI_OPR))
104 pl.ptr = (QueryItem *) palloc(pl.len * sizeof(QueryItem));
105 plainnode(&pl, root);
116 /* since this function recurses, it could be driven to stack overflow. */
122 freetree(node->left);
124 freetree(node->right);
129 * clean tree for ! operator.
130 * It's useful for debug, but in
131 * other case, such view is used with search in index.
132 * Operator ! always return TRUE
135 clean_NOT_intree(NODE *node)
137 /* since this function recurses, it could be driven to stack overflow. */
140 if (node->valnode->type == QI_VAL)
143 if (node->valnode->qoperator.oper == OP_NOT)
149 /* operator & or | */
150 if (node->valnode->qoperator.oper == OP_OR)
152 if ((node->left = clean_NOT_intree(node->left)) == NULL ||
153 (node->right = clean_NOT_intree(node->right)) == NULL)
163 Assert(node->valnode->qoperator.oper == OP_AND);
165 node->left = clean_NOT_intree(node->left);
166 node->right = clean_NOT_intree(node->right);
167 if (node->left == NULL && node->right == NULL)
172 else if (node->left == NULL)
177 else if (node->right == NULL)
188 clean_NOT(QueryItem *ptr, int *len)
190 NODE *root = maketree(ptr);
192 return plaintree(clean_NOT_intree(root), len);
196 #ifdef V_UNKNOWN /* exists in Windows headers */
199 #ifdef V_FALSE /* exists in Solaris headers */
204 * output values for result output parameter of clean_fakeval_intree
206 #define V_UNKNOWN 0 /* the expression can't be evaluated
208 #define V_TRUE 1 /* the expression is always true (not
210 #define V_FALSE 2 /* the expression is always false (not
212 #define V_STOP 3 /* the expression is a stop word */
215 * Clean query tree from values which is always in
219 clean_fakeval_intree(NODE *node, char *result)
221 char lresult = V_UNKNOWN,
224 /* since this function recurses, it could be driven to stack overflow. */
227 if (node->valnode->type == QI_VAL)
229 else if (node->valnode->type == QI_VALSTOP)
236 Assert(node->valnode->type == QI_OPR);
238 if (node->valnode->qoperator.oper == OP_NOT)
240 node->right = clean_fakeval_intree(node->right, &rresult);
252 node->left = clean_fakeval_intree(node->left, &lresult);
253 node->right = clean_fakeval_intree(node->right, &rresult);
255 if (lresult == V_STOP && rresult == V_STOP)
261 else if (lresult == V_STOP)
266 else if (rresult == V_STOP)
277 clean_fakeval(QueryItem *ptr, int *len)
279 NODE *root = maketree(ptr);
280 char result = V_UNKNOWN;
283 resroot = clean_fakeval_intree(root, &result);
284 if (result != V_UNKNOWN)
287 (errmsg("text-search query contains only stop words or doesn't contain lexemes, ignored")));
292 return plaintree(resroot, len);