~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to contrib/tsearch/rewrite.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Rewrite routines of query tree
 
3
 * Teodor Sigaev <teodor@stack.net>
 
4
 */
 
5
 
 
6
#include "postgres.h"
 
7
 
 
8
#include <float.h>
 
9
 
 
10
#include "access/gist.h"
 
11
#include "access/itup.h"
 
12
#include "access/rtree.h"
 
13
#include "utils/array.h"
 
14
#include "utils/builtins.h"
 
15
#include "storage/bufpage.h"
 
16
 
 
17
#include "query.h"
 
18
#include "rewrite.h"
 
19
 
 
20
typedef struct NODE
 
21
{
 
22
        struct NODE *left;
 
23
        struct NODE *right;
 
24
        ITEM       *valnode;
 
25
}       NODE;
 
26
 
 
27
/*
 
28
 * make query tree from plain view of query
 
29
 */
 
30
static NODE *
 
31
maketree(ITEM * in)
 
32
{
 
33
        NODE       *node = (NODE *) palloc(sizeof(NODE));
 
34
 
 
35
        node->valnode = in;
 
36
        node->right = node->left = NULL;
 
37
        if (in->type == OPR)
 
38
        {
 
39
                node->right = maketree(in + 1);
 
40
                if (in->val != (int4) '!')
 
41
                        node->left = maketree(in + in->left);
 
42
        }
 
43
        return node;
 
44
}
 
45
 
 
46
typedef struct
 
47
{
 
48
        ITEM       *ptr;
 
49
        int4            len;
 
50
        int4            cur;
 
51
}       PLAINTREE;
 
52
 
 
53
static void
 
54
plainnode(PLAINTREE * state, NODE * node)
 
55
{
 
56
        if (state->cur == state->len)
 
57
        {
 
58
                state->len *= 2;
 
59
                state->ptr = (ITEM *) repalloc((void *) state->ptr, state->len * sizeof(ITEM));
 
60
        }
 
61
        memcpy((void *) &(state->ptr[state->cur]), (void *) node->valnode, sizeof(ITEM));
 
62
        if (node->valnode->type == VAL)
 
63
                state->cur++;
 
64
        else if (node->valnode->val == (int4) '!')
 
65
        {
 
66
                state->ptr[state->cur].left = 1;
 
67
                state->cur++;
 
68
                plainnode(state, node->right);
 
69
        }
 
70
        else
 
71
        {
 
72
                int4            cur = state->cur;
 
73
 
 
74
                state->cur++;
 
75
                plainnode(state, node->right);
 
76
                state->ptr[cur].left = state->cur - cur;
 
77
                plainnode(state, node->left);
 
78
        }
 
79
        pfree(node);
 
80
}
 
81
 
 
82
/*
 
83
 * make plain view of tree from 'normal' view of tree
 
84
 */
 
85
static ITEM *
 
86
plaintree(NODE * root, int4 *len)
 
87
{
 
88
        PLAINTREE       pl;
 
89
 
 
90
        pl.cur = 0;
 
91
        pl.len = 16;
 
92
        if (root && (root->valnode->type == VAL || root->valnode->type == OPR))
 
93
        {
 
94
                pl.ptr = (ITEM *) palloc(pl.len * sizeof(ITEM));
 
95
                plainnode(&pl, root);
 
96
        }
 
97
        else
 
98
                pl.ptr = NULL;
 
99
        *len = pl.cur;
 
100
        return pl.ptr;
 
101
}
 
102
 
 
103
static void
 
104
freetree(NODE * node)
 
105
{
 
106
        if (!node)
 
107
                return;
 
108
        if (node->left)
 
109
                freetree(node->left);
 
110
        if (node->right)
 
111
                freetree(node->right);
 
112
        pfree(node);
 
113
}
 
114
 
 
115
/*
 
116
 * clean tree for ! operator.
 
117
 * It's useful for debug, but in
 
118
 * other case, such view is used with search in index.
 
119
 * Operator ! always return TRUE
 
120
 */
 
121
static NODE *
 
122
clean_NOT_intree(NODE * node)
 
123
{
 
124
        if (node->valnode->type == VAL)
 
125
                return node;
 
126
 
 
127
        if (node->valnode->val == (int4) '!')
 
128
        {
 
129
                freetree(node);
 
130
                return NULL;
 
131
        }
 
132
 
 
133
        /* operator & or | */
 
134
        if (node->valnode->val == (int4) '|')
 
135
        {
 
136
                if ((node->left = clean_NOT_intree(node->left)) == NULL ||
 
137
                        (node->right = clean_NOT_intree(node->right)) == NULL)
 
138
                {
 
139
                        freetree(node);
 
140
                        return NULL;
 
141
                }
 
142
        }
 
143
        else
 
144
        {
 
145
                NODE       *res = node;
 
146
 
 
147
                node->left = clean_NOT_intree(node->left);
 
148
                node->right = clean_NOT_intree(node->right);
 
149
                if (node->left == NULL && node->right == NULL)
 
150
                {
 
151
                        pfree(node);
 
152
                        res = NULL;
 
153
                }
 
154
                else if (node->left == NULL)
 
155
                {
 
156
                        res = node->right;
 
157
                        pfree(node);
 
158
                }
 
159
                else if (node->right == NULL)
 
160
                {
 
161
                        res = node->left;
 
162
                        pfree(node);
 
163
                }
 
164
                return res;
 
165
        }
 
166
        return node;
 
167
}
 
168
 
 
169
ITEM *
 
170
clean_NOT(ITEM * ptr, int4 *len)
 
171
{
 
172
        NODE       *root = maketree(ptr);
 
173
 
 
174
        return plaintree(clean_NOT_intree(root), len);
 
175
}
 
176
 
 
177
#ifdef V_UNKNOWN                                /* apparently Windows defines this :-( */
 
178
#undef V_UNKNOWN
 
179
#endif
 
180
#define V_UNKNOWN       0
 
181
#define V_TRUE          1
 
182
#define V_FALSE         2
 
183
 
 
184
/*
 
185
 * Clean query tree from values which is always in
 
186
 * text (stopword)
 
187
 */
 
188
static NODE *
 
189
clean_fakeval_intree(NODE * node, char *result)
 
190
{
 
191
        char            lresult = V_UNKNOWN,
 
192
                                rresult = V_UNKNOWN;
 
193
 
 
194
        if (node->valnode->type == VAL)
 
195
                return node;
 
196
        else if (node->valnode->type == VALTRUE)
 
197
        {
 
198
                pfree(node);
 
199
                *result = V_TRUE;
 
200
                return NULL;
 
201
        }
 
202
 
 
203
 
 
204
        if (node->valnode->val == (int4) '!')
 
205
        {
 
206
                node->right = clean_fakeval_intree(node->right, &rresult);
 
207
                if (!node->right)
 
208
                {
 
209
                        *result = (rresult == V_TRUE) ? V_FALSE : V_TRUE;
 
210
                        freetree(node);
 
211
                        return NULL;
 
212
                }
 
213
        }
 
214
        else if (node->valnode->val == (int4) '|')
 
215
        {
 
216
                NODE       *res = node;
 
217
 
 
218
                node->left = clean_fakeval_intree(node->left, &lresult);
 
219
                node->right = clean_fakeval_intree(node->right, &rresult);
 
220
                if (lresult == V_TRUE || rresult == V_TRUE)
 
221
                {
 
222
                        freetree(node);
 
223
                        *result = V_TRUE;
 
224
                        return NULL;
 
225
                }
 
226
                else if (lresult == V_FALSE && rresult == V_FALSE)
 
227
                {
 
228
                        freetree(node);
 
229
                        *result = V_FALSE;
 
230
                        return NULL;
 
231
                }
 
232
                else if (lresult == V_FALSE)
 
233
                {
 
234
                        res = node->right;
 
235
                        pfree(node);
 
236
                }
 
237
                else if (rresult == V_FALSE)
 
238
                {
 
239
                        res = node->left;
 
240
                        pfree(node);
 
241
                }
 
242
                return res;
 
243
        }
 
244
        else
 
245
        {
 
246
                NODE       *res = node;
 
247
 
 
248
                node->left = clean_fakeval_intree(node->left, &lresult);
 
249
                node->right = clean_fakeval_intree(node->right, &rresult);
 
250
                if (lresult == V_FALSE || rresult == V_FALSE)
 
251
                {
 
252
                        freetree(node);
 
253
                        *result = V_FALSE;
 
254
                        return NULL;
 
255
                }
 
256
                else if (lresult == V_TRUE && rresult == V_TRUE)
 
257
                {
 
258
                        freetree(node);
 
259
                        *result = V_TRUE;
 
260
                        return NULL;
 
261
                }
 
262
                else if (lresult == V_TRUE)
 
263
                {
 
264
                        res = node->right;
 
265
                        pfree(node);
 
266
                }
 
267
                else if (rresult == V_TRUE)
 
268
                {
 
269
                        res = node->left;
 
270
                        pfree(node);
 
271
                }
 
272
                return res;
 
273
        }
 
274
        return node;
 
275
}
 
276
 
 
277
ITEM *
 
278
clean_fakeval(ITEM * ptr, int4 *len)
 
279
{
 
280
        NODE       *root = maketree(ptr);
 
281
        char            result = V_UNKNOWN;
 
282
        NODE       *resroot;
 
283
 
 
284
        resroot = clean_fakeval_intree(root, &result);
 
285
        if (result != V_UNKNOWN)
 
286
        {
 
287
                elog(NOTICE, "query contains only stopword(s) or doesn't contain lexeme(s), ignored");
 
288
                *len = 0;
 
289
                return NULL;
 
290
        }
 
291
 
 
292
        return plaintree(resroot, len);
 
293
}