Properly access a buffer's LSN using existing access macros instead of abusing
[PostgreSQL.git] / src / backend / utils / adt / tsquery_cleanup.c
blob6b848157de09a1114fa2d8d4b74594abedd03aad
1 /*-------------------------------------------------------------------------
3 * tsquery_cleanup.c
4 * Cleanup query from NOT values and/or stopword
5 * Utility functions to correct work.
7 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "tsearch/ts_type.h"
19 #include "tsearch/ts_utils.h"
20 #include "miscadmin.h"
22 typedef struct NODE
24 struct NODE *left;
25 struct NODE *right;
26 QueryItem *valnode;
27 } NODE;
30 * make query tree from plain view of query
32 static NODE *
33 maketree(QueryItem *in)
35 NODE *node = (NODE *) palloc(sizeof(NODE));
37 node->valnode = in;
38 node->right = node->left = NULL;
39 if (in->type == QI_OPR)
41 node->right = maketree(in + 1);
42 if (in->operator.oper != OP_NOT)
43 node->left = maketree(in + in->operator.left);
45 return node;
49 * Internal state for plaintree and plainnode
51 typedef struct
53 QueryItem *ptr;
54 int len; /* allocated size of ptr */
55 int cur; /* number of elements in ptr */
56 } PLAINTREE;
58 static void
59 plainnode(PLAINTREE *state, NODE *node)
61 /* since this function recurses, it could be driven to stack overflow. */
62 check_stack_depth();
64 if (state->cur == state->len)
66 state->len *= 2;
67 state->ptr = (QueryItem *) repalloc((void *) state->ptr, state->len * sizeof(QueryItem));
69 memcpy((void *) &(state->ptr[state->cur]), (void *) node->valnode, sizeof(QueryItem));
70 if (node->valnode->type == QI_VAL)
71 state->cur++;
72 else if (node->valnode->operator.oper == OP_NOT)
74 state->ptr[state->cur].operator.left = 1;
75 state->cur++;
76 plainnode(state, node->right);
78 else
80 int cur = state->cur;
82 state->cur++;
83 plainnode(state, node->right);
84 state->ptr[cur].operator.left = state->cur - cur;
85 plainnode(state, node->left);
87 pfree(node);
91 * make plain view of tree from a NODE-tree representation
93 static QueryItem *
94 plaintree(NODE *root, int *len)
96 PLAINTREE pl;
98 pl.cur = 0;
99 pl.len = 16;
100 if (root && (root->valnode->type == QI_VAL || root->valnode->type == QI_OPR))
102 pl.ptr = (QueryItem *) palloc(pl.len * sizeof(QueryItem));
103 plainnode(&pl, root);
105 else
106 pl.ptr = NULL;
107 *len = pl.cur;
108 return pl.ptr;
111 static void
112 freetree(NODE *node)
114 /* since this function recurses, it could be driven to stack overflow. */
115 check_stack_depth();
117 if (!node)
118 return;
119 if (node->left)
120 freetree(node->left);
121 if (node->right)
122 freetree(node->right);
123 pfree(node);
127 * clean tree for ! operator.
128 * It's usefull for debug, but in
129 * other case, such view is used with search in index.
130 * Operator ! always return TRUE
132 static NODE *
133 clean_NOT_intree(NODE *node)
135 /* since this function recurses, it could be driven to stack overflow. */
136 check_stack_depth();
138 if (node->valnode->type == QI_VAL)
139 return node;
141 if (node->valnode->operator.oper == OP_NOT)
143 freetree(node);
144 return NULL;
147 /* operator & or | */
148 if (node->valnode->operator.oper == OP_OR)
150 if ((node->left = clean_NOT_intree(node->left)) == NULL ||
151 (node->right = clean_NOT_intree(node->right)) == NULL)
153 freetree(node);
154 return NULL;
157 else
159 NODE *res = node;
161 Assert(node->valnode->operator.oper == OP_AND);
163 node->left = clean_NOT_intree(node->left);
164 node->right = clean_NOT_intree(node->right);
165 if (node->left == NULL && node->right == NULL)
167 pfree(node);
168 res = NULL;
170 else if (node->left == NULL)
172 res = node->right;
173 pfree(node);
175 else if (node->right == NULL)
177 res = node->left;
178 pfree(node);
180 return res;
182 return node;
185 QueryItem *
186 clean_NOT(QueryItem *ptr, int *len)
188 NODE *root = maketree(ptr);
190 return plaintree(clean_NOT_intree(root), len);
194 #ifdef V_UNKNOWN /* exists in Windows headers */
195 #undef V_UNKNOWN
196 #endif
197 #ifdef V_FALSE /* exists in Solaris headers */
198 #undef V_FALSE
199 #endif
202 * output values for result output parameter of clean_fakeval_intree
204 #define V_UNKNOWN 0 /* the expression can't be evaluated
205 * statically */
206 #define V_TRUE 1 /* the expression is always true (not
207 * implemented) */
208 #define V_FALSE 2 /* the expression is always false (not
209 * implemented) */
210 #define V_STOP 3 /* the expression is a stop word */
213 * Clean query tree from values which is always in
214 * text (stopword)
216 static NODE *
217 clean_fakeval_intree(NODE *node, char *result)
219 char lresult = V_UNKNOWN,
220 rresult = V_UNKNOWN;
222 /* since this function recurses, it could be driven to stack overflow. */
223 check_stack_depth();
225 if (node->valnode->type == QI_VAL)
226 return node;
227 else if (node->valnode->type == QI_VALSTOP)
229 pfree(node);
230 *result = V_STOP;
231 return NULL;
234 Assert(node->valnode->type == QI_OPR);
236 if (node->valnode->operator.oper == OP_NOT)
238 node->right = clean_fakeval_intree(node->right, &rresult);
239 if (!node->right)
241 *result = V_STOP;
242 freetree(node);
243 return NULL;
246 else
248 NODE *res = node;
250 node->left = clean_fakeval_intree(node->left, &lresult);
251 node->right = clean_fakeval_intree(node->right, &rresult);
253 if (lresult == V_STOP && rresult == V_STOP)
255 freetree(node);
256 *result = V_STOP;
257 return NULL;
259 else if (lresult == V_STOP)
261 res = node->right;
262 pfree(node);
264 else if (rresult == V_STOP)
266 res = node->left;
267 pfree(node);
269 return res;
271 return node;
274 QueryItem *
275 clean_fakeval(QueryItem *ptr, int *len)
277 NODE *root = maketree(ptr);
278 char result = V_UNKNOWN;
279 NODE *resroot;
281 resroot = clean_fakeval_intree(root, &result);
282 if (result != V_UNKNOWN)
284 ereport(NOTICE,
285 (errmsg("text-search query contains only stop words or doesn't contain lexemes, ignored")));
286 *len = 0;
287 return NULL;
290 return plaintree(resroot, len);