~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to contrib/tsearch2/query.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
 * IO definitions for tsquery and mtsquery. This type
 
3
 * are identical, but for parsing mtsquery used parser for text
 
4
 * and also morphology is used.
 
5
 * Internal structure:
 
6
 * query tree, then string with original value.
 
7
 * Query tree with plain view. It's means that in array of nodes
 
8
 * right child is always next and left position = item+item->left
 
9
 * Teodor Sigaev <teodor@sigaev.ru>
 
10
 */
 
11
#include "postgres.h"
 
12
 
 
13
#include <float.h>
 
14
#include <ctype.h>
 
15
 
 
16
#include "access/gist.h"
 
17
#include "access/itup.h"
 
18
#include "access/rtree.h"
 
19
#include "utils/array.h"
 
20
#include "utils/builtins.h"
 
21
#include "storage/bufpage.h"
 
22
 
 
23
#include "ts_cfg.h"
 
24
#include "tsvector.h"
 
25
#include "crc32.h"
 
26
#include "query.h"
 
27
#include "rewrite.h"
 
28
#include "common.h"
 
29
 
 
30
 
 
31
PG_FUNCTION_INFO_V1(tsquery_in);
 
32
Datum           tsquery_in(PG_FUNCTION_ARGS);
 
33
 
 
34
PG_FUNCTION_INFO_V1(tsquery_out);
 
35
Datum           tsquery_out(PG_FUNCTION_ARGS);
 
36
 
 
37
PG_FUNCTION_INFO_V1(exectsq);
 
38
Datum           exectsq(PG_FUNCTION_ARGS);
 
39
 
 
40
PG_FUNCTION_INFO_V1(rexectsq);
 
41
Datum           rexectsq(PG_FUNCTION_ARGS);
 
42
 
 
43
PG_FUNCTION_INFO_V1(tsquerytree);
 
44
Datum           tsquerytree(PG_FUNCTION_ARGS);
 
45
 
 
46
PG_FUNCTION_INFO_V1(to_tsquery);
 
47
Datum           to_tsquery(PG_FUNCTION_ARGS);
 
48
 
 
49
PG_FUNCTION_INFO_V1(to_tsquery_name);
 
50
Datum           to_tsquery_name(PG_FUNCTION_ARGS);
 
51
 
 
52
PG_FUNCTION_INFO_V1(to_tsquery_current);
 
53
Datum           to_tsquery_current(PG_FUNCTION_ARGS);
 
54
 
 
55
/* parser's states */
 
56
#define WAITOPERAND 1
 
57
#define WAITOPERATOR    2
 
58
 
 
59
/*
 
60
 * node of query tree, also used
 
61
 * for storing polish notation in parser
 
62
 */
 
63
typedef struct NODE
 
64
{
 
65
        int2            weight;
 
66
        int2            type;
 
67
        int4            val;
 
68
        int2            distance;
 
69
        int2            length;
 
70
        struct NODE *next;
 
71
}       NODE;
 
72
 
 
73
typedef struct
 
74
{
 
75
        char       *buf;
 
76
        int4            state;
 
77
        int4            count;
 
78
        /* reverse polish notation in list (for temprorary usage) */
 
79
        NODE       *str;
 
80
        /* number in str */
 
81
        int4            num;
 
82
 
 
83
        /* user-friendly operand */
 
84
        int4            lenop;
 
85
        int4            sumlen;
 
86
        char       *op;
 
87
        char       *curop;
 
88
 
 
89
        /* state for value's parser */
 
90
        TI_IN_STATE valstate;
 
91
 
 
92
        /* tscfg */
 
93
        int                     cfg_id;
 
94
}       QPRS_STATE;
 
95
 
 
96
static char *
 
97
get_weight(char *buf, int2 *weight)
 
98
{
 
99
        *weight = 0;
 
100
 
 
101
        if (*buf != ':')
 
102
                return buf;
 
103
 
 
104
        buf++;
 
105
        while (*buf)
 
106
        {
 
107
                switch (tolower(*buf))
 
108
                {
 
109
                        case 'a':
 
110
                                *weight |= 1 << 3;
 
111
                                break;
 
112
                        case 'b':
 
113
                                *weight |= 1 << 2;
 
114
                                break;
 
115
                        case 'c':
 
116
                                *weight |= 1 << 1;
 
117
                                break;
 
118
                        case 'd':
 
119
                                *weight |= 1;
 
120
                                break;
 
121
                        default:
 
122
                                return buf;
 
123
                }
 
124
                buf++;
 
125
        }
 
126
 
 
127
        return buf;
 
128
}
 
129
 
 
130
/*
 
131
 * get token from query string
 
132
 */
 
133
static int4
 
134
gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2 *weight)
 
135
{
 
136
        while (1)
 
137
        {
 
138
                switch (state->state)
 
139
                {
 
140
                        case WAITOPERAND:
 
141
                                if (*(state->buf) == '!')
 
142
                                {
 
143
                                        (state->buf)++;
 
144
                                        *val = (int4) '!';
 
145
                                        return OPR;
 
146
                                }
 
147
                                else if (*(state->buf) == '(')
 
148
                                {
 
149
                                        state->count++;
 
150
                                        (state->buf)++;
 
151
                                        return OPEN;
 
152
                                }
 
153
                                else if (*(state->buf) == ':')
 
154
                                {
 
155
                                        ereport(ERROR,
 
156
                                                        (errcode(ERRCODE_SYNTAX_ERROR),
 
157
                                                         errmsg("error at start of operand")));
 
158
                                }
 
159
                                else if (*(state->buf) != ' ')
 
160
                                {
 
161
                                        state->valstate.prsbuf = state->buf;
 
162
                                        state->state = WAITOPERATOR;
 
163
                                        if (gettoken_tsvector(&(state->valstate)))
 
164
                                        {
 
165
                                                *strval = state->valstate.word;
 
166
                                                *lenval = state->valstate.curpos - state->valstate.word;
 
167
                                                state->buf = get_weight(state->valstate.prsbuf, weight);
 
168
                                                return VAL;
 
169
                                        }
 
170
                                        else
 
171
                                                ereport(ERROR,
 
172
                                                                (errcode(ERRCODE_SYNTAX_ERROR),
 
173
                                                                 errmsg("no operand")));
 
174
                                }
 
175
                                break;
 
176
                        case WAITOPERATOR:
 
177
                                if (*(state->buf) == '&' || *(state->buf) == '|')
 
178
                                {
 
179
                                        state->state = WAITOPERAND;
 
180
                                        *val = (int4) *(state->buf);
 
181
                                        (state->buf)++;
 
182
                                        return OPR;
 
183
                                }
 
184
                                else if (*(state->buf) == ')')
 
185
                                {
 
186
                                        (state->buf)++;
 
187
                                        state->count--;
 
188
                                        return (state->count < 0) ? ERR : CLOSE;
 
189
                                }
 
190
                                else if (*(state->buf) == '\0')
 
191
                                        return (state->count) ? ERR : END;
 
192
                                else if (*(state->buf) != ' ')
 
193
                                        return ERR;
 
194
                                break;
 
195
                        default:
 
196
                                return ERR;
 
197
                                break;
 
198
                }
 
199
                (state->buf)++;
 
200
        }
 
201
        return END;
 
202
}
 
203
 
 
204
/*
 
205
 * push new one in polish notation reverse view
 
206
 */
 
207
static void
 
208
pushquery(QPRS_STATE * state, int4 type, int4 val, int4 distance, int4 lenval, int2 weight)
 
209
{
 
210
        NODE       *tmp = (NODE *) palloc(sizeof(NODE));
 
211
 
 
212
        tmp->weight = weight;
 
213
        tmp->type = type;
 
214
        tmp->val = val;
 
215
        if (distance >= MAXSTRPOS)
 
216
                ereport(ERROR,
 
217
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
218
                                 errmsg("value is too big")));
 
219
        if (lenval >= MAXSTRLEN)
 
220
                ereport(ERROR,
 
221
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
222
                                 errmsg("operand is too long")));
 
223
        tmp->distance = distance;
 
224
        tmp->length = lenval;
 
225
        tmp->next = state->str;
 
226
        state->str = tmp;
 
227
        state->num++;
 
228
}
 
229
 
 
230
/*
 
231
 * This function is used for tsquery parsing
 
232
 */
 
233
static void
 
234
pushval_asis(QPRS_STATE * state, int type, char *strval, int lenval, int2 weight)
 
235
{
 
236
        if (lenval >= MAXSTRLEN)
 
237
                ereport(ERROR,
 
238
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
239
                                 errmsg("word is too long")));
 
240
 
 
241
        pushquery(state, type, crc32_sz((uint8 *) strval, lenval),
 
242
                          state->curop - state->op, lenval, weight);
 
243
 
 
244
        while (state->curop - state->op + lenval + 1 >= state->lenop)
 
245
        {
 
246
                int4            tmp = state->curop - state->op;
 
247
 
 
248
                state->lenop *= 2;
 
249
                state->op = (char *) repalloc((void *) state->op, state->lenop);
 
250
                state->curop = state->op + tmp;
 
251
        }
 
252
        memcpy((void *) state->curop, (void *) strval, lenval);
 
253
        state->curop += lenval;
 
254
        *(state->curop) = '\0';
 
255
        state->curop++;
 
256
        state->sumlen += lenval + 1;
 
257
        return;
 
258
}
 
259
 
 
260
/*
 
261
 * This function is used for morph parsing
 
262
 */
 
263
static void
 
264
pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 weight)
 
265
{
 
266
        int4            count = 0;
 
267
        PRSTEXT         prs;
 
268
 
 
269
        prs.lenwords = 32;
 
270
        prs.curwords = 0;
 
271
        prs.pos = 0;
 
272
        prs.words = (TSWORD *) palloc(sizeof(TSWORD) * prs.lenwords);
 
273
 
 
274
        parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
 
275
 
 
276
        for (count = 0; count < prs.curwords; count++)
 
277
        {
 
278
                pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
 
279
                pfree(prs.words[count].word);
 
280
                if (count)
 
281
                        pushquery(state, OPR, (int4) '&', 0, 0, 0);
 
282
        }
 
283
        pfree(prs.words);
 
284
 
 
285
        /* XXX */
 
286
        if (prs.curwords == 0)
 
287
                pushval_asis(state, VALSTOP, NULL, 0, 0);
 
288
}
 
289
 
 
290
#define STACKDEPTH      32
 
291
/*
 
292
 * make polish notaion of query
 
293
 */
 
294
static int4
 
295
makepol(QPRS_STATE * state, void (*pushval) (QPRS_STATE *, int, char *, int, int2))
 
296
{
 
297
        int4            val,
 
298
                                type;
 
299
        int4            lenval;
 
300
        char       *strval;
 
301
        int4            stack[STACKDEPTH];
 
302
        int4            lenstack = 0;
 
303
        int2            weight;
 
304
 
 
305
        while ((type = gettoken_query(state, &val, &lenval, &strval, &weight)) != END)
 
306
        {
 
307
                switch (type)
 
308
                {
 
309
                        case VAL:
 
310
                                (*pushval) (state, VAL, strval, lenval, weight);
 
311
                                while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
 
312
                                                                        stack[lenstack - 1] == (int4) '!'))
 
313
                                {
 
314
                                        lenstack--;
 
315
                                        pushquery(state, OPR, stack[lenstack], 0, 0, 0);
 
316
                                }
 
317
                                break;
 
318
                        case OPR:
 
319
                                if (lenstack && val == (int4) '|')
 
320
                                        pushquery(state, OPR, val, 0, 0, 0);
 
321
                                else
 
322
                                {
 
323
                                        if (lenstack == STACKDEPTH)
 
324
                                                /* internal error */
 
325
                                                elog(ERROR, "stack too short");
 
326
                                        stack[lenstack] = val;
 
327
                                        lenstack++;
 
328
                                }
 
329
                                break;
 
330
                        case OPEN:
 
331
                                if (makepol(state, pushval) == ERR)
 
332
                                        return ERR;
 
333
                                if (lenstack && (stack[lenstack - 1] == (int4) '&' ||
 
334
                                                                 stack[lenstack - 1] == (int4) '!'))
 
335
                                {
 
336
                                        lenstack--;
 
337
                                        pushquery(state, OPR, stack[lenstack], 0, 0, 0);
 
338
                                }
 
339
                                break;
 
340
                        case CLOSE:
 
341
                                while (lenstack)
 
342
                                {
 
343
                                        lenstack--;
 
344
                                        pushquery(state, OPR, stack[lenstack], 0, 0, 0);
 
345
                                };
 
346
                                return END;
 
347
                                break;
 
348
                        case ERR:
 
349
                        default:
 
350
                                ereport(ERROR,
 
351
                                                (errcode(ERRCODE_SYNTAX_ERROR),
 
352
                                                 errmsg("syntax error")));
 
353
                                return ERR;
 
354
 
 
355
                }
 
356
        }
 
357
        while (lenstack)
 
358
        {
 
359
                lenstack--;
 
360
                pushquery(state, OPR, stack[lenstack], 0, 0, 0);
 
361
        };
 
362
        return END;
 
363
}
 
364
 
 
365
typedef struct
 
366
{
 
367
        WordEntry  *arrb;
 
368
        WordEntry  *arre;
 
369
        char       *values;
 
370
        char       *operand;
 
371
}       CHKVAL;
 
372
 
 
373
/*
 
374
 * compare 2 string values
 
375
 */
 
376
static int4
 
377
ValCompare(CHKVAL * chkval, WordEntry * ptr, ITEM * item)
 
378
{
 
379
        if (ptr->len == item->length)
 
380
                return strncmp(
 
381
                                           &(chkval->values[ptr->pos]),
 
382
                                           &(chkval->operand[item->distance]),
 
383
                                           item->length);
 
384
 
 
385
        return (ptr->len > item->length) ? 1 : -1;
 
386
}
 
387
 
 
388
/*
 
389
 * check weight info
 
390
 */
 
391
static bool
 
392
checkclass_str(CHKVAL * chkval, WordEntry * val, ITEM * item)
 
393
{
 
394
        WordEntryPos *ptr = (WordEntryPos *) (chkval->values + val->pos + SHORTALIGN(val->len) + sizeof(uint16));
 
395
        uint16          len = *((uint16 *) (chkval->values + val->pos + SHORTALIGN(val->len)));
 
396
 
 
397
        while (len--)
 
398
        {
 
399
                if (item->weight & (1 << ptr->weight))
 
400
                        return true;
 
401
                ptr++;
 
402
        }
 
403
        return false;
 
404
}
 
405
 
 
406
/*
 
407
 * is there value 'val' in array or not ?
 
408
 */
 
409
static bool
 
410
checkcondition_str(void *checkval, ITEM * val)
 
411
{
 
412
        WordEntry  *StopLow = ((CHKVAL *) checkval)->arrb;
 
413
        WordEntry  *StopHigh = ((CHKVAL *) checkval)->arre;
 
414
        WordEntry  *StopMiddle;
 
415
        int                     difference;
 
416
 
 
417
        /* Loop invariant: StopLow <= val < StopHigh */
 
418
 
 
419
        while (StopLow < StopHigh)
 
420
        {
 
421
                StopMiddle = StopLow + (StopHigh - StopLow) / 2;
 
422
                difference = ValCompare((CHKVAL *) checkval, StopMiddle, val);
 
423
                if (difference == 0)
 
424
                        return (val->weight && StopMiddle->haspos) ?
 
425
                                checkclass_str((CHKVAL *) checkval, StopMiddle, val) : true;
 
426
                else if (difference < 0)
 
427
                        StopLow = StopMiddle + 1;
 
428
                else
 
429
                        StopHigh = StopMiddle;
 
430
        }
 
431
 
 
432
        return (false);
 
433
}
 
434
 
 
435
/*
 
436
 * check for boolean condition
 
437
 */
 
438
bool
 
439
TS_execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM * val))
 
440
{
 
441
        if (curitem->type == VAL)
 
442
                return (*chkcond) (checkval, curitem);
 
443
        else if (curitem->val == (int4) '!')
 
444
        {
 
445
                return (calcnot) ?
 
446
                        ((TS_execute(curitem + 1, checkval, calcnot, chkcond)) ? false : true)
 
447
                        : true;
 
448
        }
 
449
        else if (curitem->val == (int4) '&')
 
450
        {
 
451
                if (TS_execute(curitem + curitem->left, checkval, calcnot, chkcond))
 
452
                        return TS_execute(curitem + 1, checkval, calcnot, chkcond);
 
453
                else
 
454
                        return false;
 
455
        }
 
456
        else
 
457
        {                                                       /* |-operator */
 
458
                if (TS_execute(curitem + curitem->left, checkval, calcnot, chkcond))
 
459
                        return true;
 
460
                else
 
461
                        return TS_execute(curitem + 1, checkval, calcnot, chkcond);
 
462
        }
 
463
        return false;
 
464
}
 
465
 
 
466
/*
 
467
 * boolean operations
 
468
 */
 
469
Datum
 
470
rexectsq(PG_FUNCTION_ARGS)
 
471
{
 
472
        SET_FUNCOID();
 
473
        return DirectFunctionCall2(
 
474
                                                           exectsq,
 
475
                                                           PG_GETARG_DATUM(1),
 
476
                                                           PG_GETARG_DATUM(0)
 
477
                );
 
478
}
 
479
 
 
480
Datum
 
481
exectsq(PG_FUNCTION_ARGS)
 
482
{
 
483
        tsvector   *val = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
 
484
        QUERYTYPE  *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
 
485
        CHKVAL          chkval;
 
486
        bool            result;
 
487
 
 
488
        SET_FUNCOID();
 
489
        if (!val->size || !query->size)
 
490
        {
 
491
                PG_FREE_IF_COPY(val, 0);
 
492
                PG_FREE_IF_COPY(query, 1);
 
493
                PG_RETURN_BOOL(false);
 
494
        }
 
495
 
 
496
        chkval.arrb = ARRPTR(val);
 
497
        chkval.arre = chkval.arrb + val->size;
 
498
        chkval.values = STRPTR(val);
 
499
        chkval.operand = GETOPERAND(query);
 
500
        result = TS_execute(
 
501
                                                GETQUERY(query),
 
502
                                                &chkval,
 
503
                                                true,
 
504
                                                checkcondition_str
 
505
                );
 
506
 
 
507
        PG_FREE_IF_COPY(val, 0);
 
508
        PG_FREE_IF_COPY(query, 1);
 
509
        PG_RETURN_BOOL(result);
 
510
}
 
511
 
 
512
/*
 
513
 * find left operand in polish notation view
 
514
 */
 
515
static void
 
516
findoprnd(ITEM * ptr, int4 *pos)
 
517
{
 
518
#ifdef BS_DEBUG
 
519
        elog(DEBUG3, (ptr[*pos].type == OPR) ?
 
520
                 "%d  %c" : "%d  %d", *pos, ptr[*pos].val);
 
521
#endif
 
522
        if (ptr[*pos].type == VAL || ptr[*pos].type == VALSTOP)
 
523
        {
 
524
                ptr[*pos].left = 0;
 
525
                (*pos)++;
 
526
        }
 
527
        else if (ptr[*pos].val == (int4) '!')
 
528
        {
 
529
                ptr[*pos].left = 1;
 
530
                (*pos)++;
 
531
                findoprnd(ptr, pos);
 
532
        }
 
533
        else
 
534
        {
 
535
                ITEM       *curitem = &ptr[*pos];
 
536
                int4            tmp = *pos;
 
537
 
 
538
                (*pos)++;
 
539
                findoprnd(ptr, pos);
 
540
                curitem->left = *pos - tmp;
 
541
                findoprnd(ptr, pos);
 
542
        }
 
543
}
 
544
 
 
545
 
 
546
/*
 
547
 * input
 
548
 */
 
549
static QUERYTYPE *
 
550
                        queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id)
 
551
{
 
552
        QPRS_STATE      state;
 
553
        int4            i;
 
554
        QUERYTYPE  *query;
 
555
        int4            commonlen;
 
556
        ITEM       *ptr;
 
557
        NODE       *tmp;
 
558
        int4            pos = 0;
 
559
 
 
560
#ifdef BS_DEBUG
 
561
        char            pbuf[16384],
 
562
                           *cur;
 
563
#endif
 
564
 
 
565
        /* init state */
 
566
        state.buf = buf;
 
567
        state.state = WAITOPERAND;
 
568
        state.count = 0;
 
569
        state.num = 0;
 
570
        state.str = NULL;
 
571
        state.cfg_id = cfg_id;
 
572
 
 
573
        /* init value parser's state */
 
574
        state.valstate.oprisdelim = true;
 
575
        state.valstate.len = 32;
 
576
        state.valstate.word = (char *) palloc(state.valstate.len);
 
577
 
 
578
        /* init list of operand */
 
579
        state.sumlen = 0;
 
580
        state.lenop = 64;
 
581
        state.curop = state.op = (char *) palloc(state.lenop);
 
582
        *(state.curop) = '\0';
 
583
 
 
584
        /* parse query & make polish notation (postfix, but in reverse order) */
 
585
        makepol(&state, pushval);
 
586
        pfree(state.valstate.word);
 
587
        if (!state.num)
 
588
                ereport(ERROR,
 
589
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
590
                                 errmsg("empty query")));
 
591
 
 
592
        /* make finish struct */
 
593
        commonlen = COMPUTESIZE(state.num, state.sumlen);
 
594
        query = (QUERYTYPE *) palloc(commonlen);
 
595
        query->len = commonlen;
 
596
        query->size = state.num;
 
597
        ptr = GETQUERY(query);
 
598
 
 
599
        /* set item in polish notation */
 
600
        for (i = 0; i < state.num; i++)
 
601
        {
 
602
                ptr[i].weight = state.str->weight;
 
603
                ptr[i].type = state.str->type;
 
604
                ptr[i].val = state.str->val;
 
605
                ptr[i].distance = state.str->distance;
 
606
                ptr[i].length = state.str->length;
 
607
                tmp = state.str->next;
 
608
                pfree(state.str);
 
609
                state.str = tmp;
 
610
        }
 
611
 
 
612
        /* set user friendly-operand view */
 
613
        memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
 
614
        pfree(state.op);
 
615
 
 
616
        /* set left operand's position for every operator */
 
617
        pos = 0;
 
618
        findoprnd(ptr, &pos);
 
619
 
 
620
#ifdef BS_DEBUG
 
621
        cur = pbuf;
 
622
        *cur = '\0';
 
623
        for (i = 0; i < query->size; i++)
 
624
        {
 
625
                if (ptr[i].type == OPR)
 
626
                        sprintf(cur, "%c(%d) ", ptr[i].val, ptr[i].left);
 
627
                else
 
628
                        sprintf(cur, "%d(%s) ", ptr[i].val, GETOPERAND(query) + ptr[i].distance);
 
629
                cur = strchr(cur, '\0');
 
630
        }
 
631
        elog(DEBUG3, "POR: %s", pbuf);
 
632
#endif
 
633
 
 
634
        return query;
 
635
}
 
636
 
 
637
/*
 
638
 * in without morphology
 
639
 */
 
640
Datum
 
641
tsquery_in(PG_FUNCTION_ARGS)
 
642
{
 
643
        SET_FUNCOID();
 
644
        PG_RETURN_POINTER(queryin((char *) PG_GETARG_POINTER(0), pushval_asis, 0));
 
645
}
 
646
 
 
647
/*
 
648
 * out function
 
649
 */
 
650
typedef struct
 
651
{
 
652
        ITEM       *curpol;
 
653
        char       *buf;
 
654
        char       *cur;
 
655
        char       *op;
 
656
        int4            buflen;
 
657
}       INFIX;
 
658
 
 
659
#define RESIZEBUF(inf,addsize) \
 
660
while( ( inf->cur - inf->buf ) + addsize + 1 >= inf->buflen ) \
 
661
{ \
 
662
        int4 len = inf->cur - inf->buf; \
 
663
        inf->buflen *= 2; \
 
664
        inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
 
665
        inf->cur = inf->buf + len; \
 
666
}
 
667
 
 
668
/*
 
669
 * recursive walk on tree and print it in
 
670
 * infix (human-readable) view
 
671
 */
 
672
static void
 
673
infix(INFIX * in, bool first)
 
674
{
 
675
        if (in->curpol->type == VAL)
 
676
        {
 
677
                char       *op = in->op + in->curpol->distance;
 
678
 
 
679
                RESIZEBUF(in, in->curpol->length * 2 + 2 + 5);
 
680
                *(in->cur) = '\'';
 
681
                in->cur++;
 
682
                while (*op)
 
683
                {
 
684
                        if (*op == '\'')
 
685
                        {
 
686
                                *(in->cur) = '\\';
 
687
                                in->cur++;
 
688
                        }
 
689
                        *(in->cur) = *op;
 
690
                        op++;
 
691
                        in->cur++;
 
692
                }
 
693
                *(in->cur) = '\'';
 
694
                in->cur++;
 
695
                if (in->curpol->weight)
 
696
                {
 
697
                        *(in->cur) = ':';
 
698
                        in->cur++;
 
699
                        if (in->curpol->weight & (1 << 3))
 
700
                        {
 
701
                                *(in->cur) = 'A';
 
702
                                in->cur++;
 
703
                        }
 
704
                        if (in->curpol->weight & (1 << 2))
 
705
                        {
 
706
                                *(in->cur) = 'B';
 
707
                                in->cur++;
 
708
                        }
 
709
                        if (in->curpol->weight & (1 << 1))
 
710
                        {
 
711
                                *(in->cur) = 'C';
 
712
                                in->cur++;
 
713
                        }
 
714
                        if (in->curpol->weight & 1)
 
715
                        {
 
716
                                *(in->cur) = 'D';
 
717
                                in->cur++;
 
718
                        }
 
719
                }
 
720
                *(in->cur) = '\0';
 
721
                in->curpol++;
 
722
        }
 
723
        else if (in->curpol->val == (int4) '!')
 
724
        {
 
725
                bool            isopr = false;
 
726
 
 
727
                RESIZEBUF(in, 1);
 
728
                *(in->cur) = '!';
 
729
                in->cur++;
 
730
                *(in->cur) = '\0';
 
731
                in->curpol++;
 
732
                if (in->curpol->type == OPR)
 
733
                {
 
734
                        isopr = true;
 
735
                        RESIZEBUF(in, 2);
 
736
                        sprintf(in->cur, "( ");
 
737
                        in->cur = strchr(in->cur, '\0');
 
738
                }
 
739
                infix(in, isopr);
 
740
                if (isopr)
 
741
                {
 
742
                        RESIZEBUF(in, 2);
 
743
                        sprintf(in->cur, " )");
 
744
                        in->cur = strchr(in->cur, '\0');
 
745
                }
 
746
        }
 
747
        else
 
748
        {
 
749
                int4            op = in->curpol->val;
 
750
                INFIX           nrm;
 
751
 
 
752
                in->curpol++;
 
753
                if (op == (int4) '|' && !first)
 
754
                {
 
755
                        RESIZEBUF(in, 2);
 
756
                        sprintf(in->cur, "( ");
 
757
                        in->cur = strchr(in->cur, '\0');
 
758
                }
 
759
 
 
760
                nrm.curpol = in->curpol;
 
761
                nrm.op = in->op;
 
762
                nrm.buflen = 16;
 
763
                nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
 
764
 
 
765
                /* get right operand */
 
766
                infix(&nrm, false);
 
767
 
 
768
                /* get & print left operand */
 
769
                in->curpol = nrm.curpol;
 
770
                infix(in, false);
 
771
 
 
772
                /* print operator & right operand */
 
773
                RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
 
774
                sprintf(in->cur, " %c %s", op, nrm.buf);
 
775
                in->cur = strchr(in->cur, '\0');
 
776
                pfree(nrm.buf);
 
777
 
 
778
                if (op == (int4) '|' && !first)
 
779
                {
 
780
                        RESIZEBUF(in, 2);
 
781
                        sprintf(in->cur, " )");
 
782
                        in->cur = strchr(in->cur, '\0');
 
783
                }
 
784
        }
 
785
}
 
786
 
 
787
 
 
788
Datum
 
789
tsquery_out(PG_FUNCTION_ARGS)
 
790
{
 
791
        QUERYTYPE  *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
 
792
        INFIX           nrm;
 
793
 
 
794
        if (query->size == 0)
 
795
        {
 
796
                char       *b = palloc(1);
 
797
 
 
798
                *b = '\0';
 
799
                PG_RETURN_POINTER(b);
 
800
        }
 
801
        nrm.curpol = GETQUERY(query);
 
802
        nrm.buflen = 32;
 
803
        nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
 
804
        *(nrm.cur) = '\0';
 
805
        nrm.op = GETOPERAND(query);
 
806
        infix(&nrm, true);
 
807
 
 
808
        PG_FREE_IF_COPY(query, 0);
 
809
        PG_RETURN_POINTER(nrm.buf);
 
810
}
 
811
 
 
812
/*
 
813
 * debug function, used only for view query
 
814
 * which will be executed in non-leaf pages in index
 
815
 */
 
816
Datum
 
817
tsquerytree(PG_FUNCTION_ARGS)
 
818
{
 
819
        QUERYTYPE  *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
 
820
        INFIX           nrm;
 
821
        text       *res;
 
822
        ITEM       *q;
 
823
        int4            len;
 
824
 
 
825
 
 
826
        if (query->size == 0)
 
827
        {
 
828
                res = (text *) palloc(VARHDRSZ);
 
829
                VARATT_SIZEP(res) = VARHDRSZ;
 
830
                PG_RETURN_POINTER(res);
 
831
        }
 
832
 
 
833
        q = clean_NOT_v2(GETQUERY(query), &len);
 
834
 
 
835
        if (!q)
 
836
        {
 
837
                res = (text *) palloc(1 + VARHDRSZ);
 
838
                VARATT_SIZEP(res) = 1 + VARHDRSZ;
 
839
                *((char *) VARDATA(res)) = 'T';
 
840
        }
 
841
        else
 
842
        {
 
843
                nrm.curpol = q;
 
844
                nrm.buflen = 32;
 
845
                nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
 
846
                *(nrm.cur) = '\0';
 
847
                nrm.op = GETOPERAND(query);
 
848
                infix(&nrm, true);
 
849
 
 
850
                res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ);
 
851
                VARATT_SIZEP(res) = nrm.cur - nrm.buf + VARHDRSZ;
 
852
                strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf);
 
853
                pfree(q);
 
854
        }
 
855
 
 
856
        PG_FREE_IF_COPY(query, 0);
 
857
 
 
858
        PG_RETURN_POINTER(res);
 
859
}
 
860
 
 
861
Datum
 
862
to_tsquery(PG_FUNCTION_ARGS)
 
863
{
 
864
        text       *in = PG_GETARG_TEXT_P(1);
 
865
        char       *str;
 
866
        QUERYTYPE  *query;
 
867
        ITEM       *res;
 
868
        int4            len;
 
869
 
 
870
        SET_FUNCOID();
 
871
 
 
872
        str = text2char(in);
 
873
        PG_FREE_IF_COPY(in, 1);
 
874
 
 
875
        query = queryin(str, pushval_morph, PG_GETARG_INT32(0));
 
876
        res = clean_fakeval_v2(GETQUERY(query), &len);
 
877
        if (!res)
 
878
        {
 
879
                query->len = HDRSIZEQT;
 
880
                query->size = 0;
 
881
                PG_RETURN_POINTER(query);
 
882
        }
 
883
        memcpy((void *) GETQUERY(query), (void *) res, len * sizeof(ITEM));
 
884
        pfree(res);
 
885
        PG_RETURN_POINTER(query);
 
886
}
 
887
 
 
888
Datum
 
889
to_tsquery_name(PG_FUNCTION_ARGS)
 
890
{
 
891
        text       *name = PG_GETARG_TEXT_P(0);
 
892
        Datum           res;
 
893
 
 
894
        SET_FUNCOID();
 
895
        res = DirectFunctionCall2(to_tsquery,
 
896
                                                          Int32GetDatum(name2id_cfg(name)),
 
897
                                                          PG_GETARG_DATUM(1));
 
898
 
 
899
        PG_FREE_IF_COPY(name, 0);
 
900
        PG_RETURN_DATUM(res);
 
901
}
 
902
 
 
903
Datum
 
904
to_tsquery_current(PG_FUNCTION_ARGS)
 
905
{
 
906
        SET_FUNCOID();
 
907
        PG_RETURN_DATUM(DirectFunctionCall2(to_tsquery,
 
908
                                                                                Int32GetDatum(get_currcfg()),
 
909
                                                                                PG_GETARG_DATUM(0)));
 
910
}