3
* Teodor Sigaev <teodor@stack.net>
4
* contrib/ltree/ltxtquery_io.c
13
PG_FUNCTION_INFO_V1(ltxtq_in);
14
Datum ltxtq_in(PG_FUNCTION_ARGS);
16
PG_FUNCTION_INFO_V1(ltxtq_out);
17
Datum ltxtq_out(PG_FUNCTION_ARGS);
23
#define WAITOPERATOR 3
26
* node of query tree, also used
27
* for storing polish notation in parser
44
/* reverse polish notation in list (for temporary usage) */
49
/* user-friendly operand */
57
* get token from query string
60
gettoken_query(QPRS_STATE *state, int4 *val, int4 *lenval, char **strval, uint16 *flag)
66
charlen = pg_mblen(state->buf);
71
if (charlen == 1 && t_iseq(state->buf, '!'))
77
else if (charlen == 1 && t_iseq(state->buf, '('))
83
else if (ISALNUM(state->buf))
85
state->state = INOPERAND;
90
else if (!t_isspace(state->buf))
92
(errcode(ERRCODE_SYNTAX_ERROR),
93
errmsg("operand syntax error")));
96
if (ISALNUM(state->buf))
100
(errcode(ERRCODE_SYNTAX_ERROR),
101
errmsg("modificators syntax error")));
104
else if (charlen == 1 && t_iseq(state->buf, '%'))
105
*flag |= LVAR_SUBLEXEME;
106
else if (charlen == 1 && t_iseq(state->buf, '@'))
107
*flag |= LVAR_INCASE;
108
else if (charlen == 1 && t_iseq(state->buf, '*'))
109
*flag |= LVAR_ANYEND;
112
state->state = WAITOPERATOR;
117
if (charlen == 1 && (t_iseq(state->buf, '&') || t_iseq(state->buf, '|')))
119
state->state = WAITOPERAND;
120
*val = (int4) *(state->buf);
124
else if (charlen == 1 && t_iseq(state->buf, ')'))
128
return (state->count < 0) ? ERR : CLOSE;
130
else if (*(state->buf) == '\0')
131
return (state->count) ? ERR : END;
132
else if (charlen == 1 && !t_iseq(state->buf, ' '))
140
state->buf += charlen;
146
* push new one in polish notation reverse view
149
pushquery(QPRS_STATE *state, int4 type, int4 val, int4 distance, int4 lenval, uint16 flag)
151
NODE *tmp = (NODE *) palloc(sizeof(NODE));
156
if (distance > 0xffff)
158
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
159
errmsg("value is too big")));
162
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
163
errmsg("operand is too long")));
164
tmp->distance = distance;
165
tmp->length = lenval;
166
tmp->next = state->str;
172
* This function is used for query_txt parsing
175
pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
179
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
180
errmsg("word is too long")));
182
pushquery(state, type, ltree_crc32_sz(strval, lenval),
183
state->curop - state->op, lenval, flag);
185
while (state->curop - state->op + lenval + 1 >= state->lenop)
187
int4 tmp = state->curop - state->op;
190
state->op = (char *) repalloc((void *) state->op, state->lenop);
191
state->curop = state->op + tmp;
193
memcpy((void *) state->curop, (void *) strval, lenval);
194
state->curop += lenval;
195
*(state->curop) = '\0';
197
state->sumlen += lenval + 1;
201
#define STACKDEPTH 32
203
* make polish notaion of query
206
makepol(QPRS_STATE *state)
212
int4 stack[STACKDEPTH];
216
while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
221
pushval_asis(state, VAL, strval, lenval, flag);
222
while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
223
stack[lenstack - 1] == (int4) '!'))
226
pushquery(state, OPR, stack[lenstack], 0, 0, 0);
230
if (lenstack && val == (int4) '|')
231
pushquery(state, OPR, val, 0, 0, 0);
234
if (lenstack == STACKDEPTH)
236
elog(ERROR, "stack too short");
237
stack[lenstack] = val;
242
if (makepol(state) == ERR)
244
while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
245
stack[lenstack - 1] == (int4) '!'))
248
pushquery(state, OPR, stack[lenstack], 0, 0, 0);
255
pushquery(state, OPR, stack[lenstack], 0, 0, 0);
262
(errcode(ERRCODE_SYNTAX_ERROR),
263
errmsg("syntax error")));
272
pushquery(state, OPR, stack[lenstack], 0, 0, 0);
278
findoprnd(ITEM *ptr, int4 *pos)
280
if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
285
else if (ptr[*pos].val == (int4) '!')
293
ITEM *curitem = &ptr[*pos];
298
curitem->left = *pos - tmp;
325
state.state = WAITOPERAND;
330
/* init list of operand */
333
state.curop = state.op = (char *) palloc(state.lenop);
334
*(state.curop) = '\0';
336
/* parse query & make polish notation (postfix, but in reverse order) */
340
(errcode(ERRCODE_SYNTAX_ERROR),
341
errmsg("syntax error"),
342
errdetail("Empty query.")));
344
/* make finish struct */
345
commonlen = COMPUTESIZE(state.num, state.sumlen);
346
query = (ltxtquery *) palloc(commonlen);
347
SET_VARSIZE(query, commonlen);
348
query->size = state.num;
349
ptr = GETQUERY(query);
351
/* set item in polish notation */
352
for (i = 0; i < state.num; i++)
354
ptr[i].type = state.str->type;
355
ptr[i].val = state.str->val;
356
ptr[i].distance = state.str->distance;
357
ptr[i].length = state.str->length;
358
ptr[i].flag = state.str->flag;
359
tmp = state.str->next;
364
/* set user friendly-operand view */
365
memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
368
/* set left operand's position for every operator */
370
findoprnd(ptr, &pos);
376
* in without morphology
379
ltxtq_in(PG_FUNCTION_ARGS)
381
PG_RETURN_POINTER(queryin((char *) PG_GETARG_POINTER(0)));
396
#define RESIZEBUF(inf,addsize) \
397
while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
399
int4 len = (inf)->cur - (inf)->buf; \
400
(inf)->buflen *= 2; \
401
(inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
402
(inf)->cur = (inf)->buf + len; \
406
* recursive walk on tree and print it in
407
* infix (human-readable) view
410
infix(INFIX *in, bool first)
412
if (in->curpol->type == VAL)
414
char *op = in->op + in->curpol->distance;
416
RESIZEBUF(in, in->curpol->length * 2 + 5);
423
if (in->curpol->flag & LVAR_SUBLEXEME)
428
if (in->curpol->flag & LVAR_INCASE)
433
if (in->curpol->flag & LVAR_ANYEND)
441
else if (in->curpol->val == (int4) '!')
450
if (in->curpol->type == OPR)
454
sprintf(in->cur, "( ");
455
in->cur = strchr(in->cur, '\0');
461
sprintf(in->cur, " )");
462
in->cur = strchr(in->cur, '\0');
467
int4 op = in->curpol->val;
471
if (op == (int4) '|' && !first)
474
sprintf(in->cur, "( ");
475
in->cur = strchr(in->cur, '\0');
478
nrm.curpol = in->curpol;
481
nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
483
/* get right operand */
486
/* get & print left operand */
487
in->curpol = nrm.curpol;
490
/* print operator & right operand */
491
RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
492
sprintf(in->cur, " %c %s", op, nrm.buf);
493
in->cur = strchr(in->cur, '\0');
496
if (op == (int4) '|' && !first)
499
sprintf(in->cur, " )");
500
in->cur = strchr(in->cur, '\0');
506
ltxtq_out(PG_FUNCTION_ARGS)
508
ltxtquery *query = PG_GETARG_LTXTQUERY(0);
511
if (query->size == 0)
513
(errcode(ERRCODE_SYNTAX_ERROR),
514
errmsg("syntax error"),
515
errdetail("Empty query.")));
517
nrm.curpol = GETQUERY(query);
519
nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
521
nrm.op = GETOPERAND(query);
524
PG_FREE_IF_COPY(query, 0);
525
PG_RETURN_POINTER(nrm.buf);