~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to contrib/ltree/lquery_op.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
 * op function for ltree and lquery
 
3
 * Teodor Sigaev <teodor@stack.net>
 
4
 */
 
5
 
 
6
#include "ltree.h"
 
7
#include <ctype.h>
 
8
#include "utils/array.h"
 
9
 
 
10
PG_FUNCTION_INFO_V1(ltq_regex);
 
11
PG_FUNCTION_INFO_V1(ltq_rregex);
 
12
 
 
13
PG_FUNCTION_INFO_V1(lt_q_regex);
 
14
PG_FUNCTION_INFO_V1(lt_q_rregex);
 
15
 
 
16
#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
 
17
 
 
18
typedef struct
 
19
{
 
20
        lquery_level *q;
 
21
        int                     nq;
 
22
        ltree_level *t;
 
23
        int                     nt;
 
24
        int                     posq;
 
25
        int                     post;
 
26
}       FieldNot;
 
27
 
 
28
static char *
 
29
getlexem(char *start, char *end, int *len)
 
30
{
 
31
        char       *ptr;
 
32
 
 
33
        while (start < end && *start == '_')
 
34
                start++;
 
35
 
 
36
        ptr = start;
 
37
        if (ptr == end)
 
38
                return NULL;
 
39
 
 
40
        while (ptr < end && *ptr != '_')
 
41
                ptr++;
 
42
 
 
43
        *len = ptr - start;
 
44
        return start;
 
45
}
 
46
 
 
47
bool
 
48
                        compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
 
49
{
 
50
        char       *endt = t->name + t->len;
 
51
        char       *endq = qn + len;
 
52
        char       *tn;
 
53
        int                     lent,
 
54
                                lenq;
 
55
        bool            isok;
 
56
 
 
57
        while ((qn = getlexem(qn, endq, &lenq)) != NULL)
 
58
        {
 
59
                tn = t->name;
 
60
                isok = false;
 
61
                while ((tn = getlexem(tn, endt, &lent)) != NULL)
 
62
                {
 
63
                        if (
 
64
                                (
 
65
                                 lent == lenq ||
 
66
                                 (lent > lenq && anyend)
 
67
                                 ) &&
 
68
                                (*cmpptr) (qn, tn, lenq) == 0)
 
69
                        {
 
70
 
 
71
                                isok = true;
 
72
                                break;
 
73
                        }
 
74
                        tn += lent;
 
75
                }
 
76
 
 
77
                if (!isok)
 
78
                        return false;
 
79
                qn += lenq;
 
80
        }
 
81
 
 
82
        return true;
 
83
}
 
84
 
 
85
static bool
 
86
checkLevel(lquery_level * curq, ltree_level * curt)
 
87
{
 
88
        int                     (*cmpptr) (const char *, const char *, size_t);
 
89
        lquery_variant *curvar = LQL_FIRST(curq);
 
90
        int                     i;
 
91
 
 
92
        for (i = 0; i < curq->numvar; i++)
 
93
        {
 
94
                cmpptr = (curvar->flag & LVAR_INCASE) ? pg_strncasecmp : strncmp;
 
95
 
 
96
                if (curvar->flag & LVAR_SUBLEXEM)
 
97
                {
 
98
                        if (compare_subnode(curt, curvar->name, curvar->len, cmpptr, (curvar->flag & LVAR_ANYEND)))
 
99
                                return true;
 
100
                }
 
101
                else if (
 
102
                                 (
 
103
                                  curvar->len == curt->len ||
 
104
                                (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))
 
105
                                  ) &&
 
106
                                 (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
 
107
                {
 
108
 
 
109
                        return true;
 
110
                }
 
111
                curvar = LVAR_NEXT(curvar);
 
112
        }
 
113
        return false;
 
114
}
 
115
 
 
116
/*
 
117
void
 
118
printFieldNot(FieldNot *fn ) {
 
119
        while(fn->q) {
 
120
                elog(NOTICE,"posQ:%d lenQ:%d posT:%d lenT:%d", fn->posq,fn->nq,fn->post,fn->nt);
 
121
                fn++;
 
122
        }
 
123
}
 
124
*/
 
125
 
 
126
static struct
 
127
{
 
128
        bool            muse;
 
129
        uint32          high_pos;
 
130
}       SomeStack =
 
131
 
 
132
{
 
133
        false, 0,
 
134
};
 
135
 
 
136
static bool
 
137
checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr)
 
138
{
 
139
        uint32          low_pos = 0,
 
140
                                high_pos = 0,
 
141
                                cur_tpos = 0;
 
142
        int                     tlen = tree_numlevel,
 
143
                                qlen = query_numlevel;
 
144
        int                     isok;
 
145
        lquery_level *prevq = NULL;
 
146
        ltree_level *prevt = NULL;
 
147
 
 
148
        if (SomeStack.muse)
 
149
        {
 
150
                high_pos = SomeStack.high_pos;
 
151
                qlen--;
 
152
                prevq = curq;
 
153
                curq = LQL_NEXT(curq);
 
154
                SomeStack.muse = false;
 
155
        }
 
156
 
 
157
        while (tlen > 0 && qlen > 0)
 
158
        {
 
159
                if (curq->numvar)
 
160
                {
 
161
                        prevt = curt;
 
162
                        while (cur_tpos < low_pos)
 
163
                        {
 
164
                                curt = LEVEL_NEXT(curt);
 
165
                                tlen--;
 
166
                                cur_tpos++;
 
167
                                if (tlen == 0)
 
168
                                        return false;
 
169
                                if (ptr && ptr->q)
 
170
                                        ptr->nt++;
 
171
                        }
 
172
 
 
173
                        if (ptr && curq->flag & LQL_NOT)
 
174
                        {
 
175
                                if (!(prevq && prevq->numvar == 0))
 
176
                                        prevq = curq;
 
177
                                if (ptr->q == NULL)
 
178
                                {
 
179
                                        ptr->t = prevt;
 
180
                                        ptr->q = prevq;
 
181
                                        ptr->nt = 1;
 
182
                                        ptr->nq = 1 + ((prevq == curq) ? 0 : 1);
 
183
                                        ptr->posq = query_numlevel - qlen - ((prevq == curq) ? 0 : 1);
 
184
                                        ptr->post = cur_tpos;
 
185
                                }
 
186
                                else
 
187
                                {
 
188
                                        ptr->nt++;
 
189
                                        ptr->nq++;
 
190
                                }
 
191
 
 
192
                                if (qlen == 1 && ptr->q->numvar == 0)
 
193
                                        ptr->nt = tree_numlevel - ptr->post;
 
194
                                curt = LEVEL_NEXT(curt);
 
195
                                tlen--;
 
196
                                cur_tpos++;
 
197
                                if (high_pos < cur_tpos)
 
198
                                        high_pos++;
 
199
                        }
 
200
                        else
 
201
                        {
 
202
                                isok = false;
 
203
                                while (cur_tpos <= high_pos && tlen > 0 && !isok)
 
204
                                {
 
205
                                        isok = checkLevel(curq, curt);
 
206
                                        curt = LEVEL_NEXT(curt);
 
207
                                        tlen--;
 
208
                                        cur_tpos++;
 
209
                                        if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos)
 
210
                                        {
 
211
                                                FieldNot        tmpptr;
 
212
 
 
213
                                                if (ptr)
 
214
                                                        memcpy(&tmpptr, ptr, sizeof(FieldNot));
 
215
                                                SomeStack.high_pos = high_pos - cur_tpos;
 
216
                                                SomeStack.muse = true;
 
217
                                                if (checkCond(prevq, qlen + 1, curt, tlen, (ptr) ? &tmpptr : NULL))
 
218
                                                        return true;
 
219
                                        }
 
220
                                        if (!isok && ptr)
 
221
                                                ptr->nt++;
 
222
                                }
 
223
                                if (!isok)
 
224
                                        return false;
 
225
 
 
226
                                if (ptr && ptr->q)
 
227
                                {
 
228
                                        if (checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
 
229
                                                return false;
 
230
                                        ptr->q = NULL;
 
231
                                }
 
232
                                low_pos = cur_tpos;
 
233
                                high_pos = cur_tpos;
 
234
                        }
 
235
                }
 
236
                else
 
237
                {
 
238
                        low_pos = cur_tpos + curq->low;
 
239
                        high_pos = cur_tpos + curq->high;
 
240
                        if (ptr && ptr->q)
 
241
                        {
 
242
                                ptr->nq++;
 
243
                                if (qlen == 1)
 
244
                                        ptr->nt = tree_numlevel - ptr->post;
 
245
                        }
 
246
                }
 
247
 
 
248
                prevq = curq;
 
249
                curq = LQL_NEXT(curq);
 
250
                qlen--;
 
251
        }
 
252
 
 
253
        if (low_pos > tree_numlevel || tree_numlevel > high_pos)
 
254
                return false;
 
255
 
 
256
        while (qlen > 0)
 
257
        {
 
258
                if (curq->numvar)
 
259
                {
 
260
                        if (!(curq->flag & LQL_NOT))
 
261
                                return false;
 
262
                }
 
263
                else
 
264
                {
 
265
                        low_pos = cur_tpos + curq->low;
 
266
                        high_pos = cur_tpos + curq->high;
 
267
                }
 
268
 
 
269
                curq = LQL_NEXT(curq);
 
270
                qlen--;
 
271
        }
 
272
 
 
273
        if (low_pos > tree_numlevel || tree_numlevel > high_pos)
 
274
                return false;
 
275
 
 
276
        if (ptr && ptr->q && checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
 
277
                return false;
 
278
 
 
279
        return true;
 
280
}
 
281
 
 
282
Datum
 
283
ltq_regex(PG_FUNCTION_ARGS)
 
284
{
 
285
        ltree      *tree = PG_GETARG_LTREE(0);
 
286
        lquery     *query = PG_GETARG_LQUERY(1);
 
287
        bool            res = false;
 
288
 
 
289
        if (query->flag & LQUERY_HASNOT)
 
290
        {
 
291
                FieldNot        fn;
 
292
 
 
293
                fn.q = NULL;
 
294
 
 
295
                res = checkCond(LQUERY_FIRST(query), query->numlevel,
 
296
                                                LTREE_FIRST(tree), tree->numlevel, &fn);
 
297
        }
 
298
        else
 
299
        {
 
300
                res = checkCond(LQUERY_FIRST(query), query->numlevel,
 
301
                                                LTREE_FIRST(tree), tree->numlevel, NULL);
 
302
        }
 
303
 
 
304
        PG_FREE_IF_COPY(tree, 0);
 
305
        PG_FREE_IF_COPY(query, 1);
 
306
        PG_RETURN_BOOL(res);
 
307
}
 
308
 
 
309
Datum
 
310
ltq_rregex(PG_FUNCTION_ARGS)
 
311
{
 
312
        PG_RETURN_DATUM(DirectFunctionCall2(ltq_regex,
 
313
                                                                                PG_GETARG_DATUM(1),
 
314
                                                                                PG_GETARG_DATUM(0)
 
315
                                                                                ));
 
316
}
 
317
 
 
318
Datum
 
319
lt_q_regex(PG_FUNCTION_ARGS)
 
320
{
 
321
        ltree      *tree = PG_GETARG_LTREE(0);
 
322
        ArrayType  *_query = PG_GETARG_ARRAYTYPE_P(1);
 
323
        lquery     *query = (lquery *) ARR_DATA_PTR(_query);
 
324
        bool            res = false;
 
325
        int                     num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
 
326
 
 
327
        if (ARR_NDIM(_query) != 1)
 
328
                ereport(ERROR,
 
329
                                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
 
330
                                 errmsg("array must be one-dimensional")));
 
331
 
 
332
        while (num > 0)
 
333
        {
 
334
                if (DatumGetBool(DirectFunctionCall2(ltq_regex,
 
335
                                                 PointerGetDatum(tree), PointerGetDatum(query))))
 
336
                {
 
337
 
 
338
                        res = true;
 
339
                        break;
 
340
                }
 
341
                num--;
 
342
                query = NEXTVAL(query);
 
343
        }
 
344
 
 
345
        PG_FREE_IF_COPY(tree, 0);
 
346
        PG_FREE_IF_COPY(_query, 1);
 
347
        PG_RETURN_BOOL(res);
 
348
}
 
349
 
 
350
Datum
 
351
lt_q_rregex(PG_FUNCTION_ARGS)
 
352
{
 
353
        PG_RETURN_DATUM(DirectFunctionCall2(lt_q_regex,
 
354
                                                                                PG_GETARG_DATUM(1),
 
355
                                                                                PG_GETARG_DATUM(0)
 
356
                                                                                ));
 
357
}