2 * in/out function for ltree and lquery
3 * Teodor Sigaev <teodor@stack.net>
10 PG_FUNCTION_INFO_V1(ltree_in);
11 Datum ltree_in(PG_FUNCTION_ARGS);
13 PG_FUNCTION_INFO_V1(ltree_out);
14 Datum ltree_out(PG_FUNCTION_ARGS);
16 PG_FUNCTION_INFO_V1(lquery_in);
17 Datum lquery_in(PG_FUNCTION_ARGS);
19 PG_FUNCTION_INFO_V1(lquery_out);
20 Datum lquery_out(PG_FUNCTION_ARGS);
23 #define UNCHAR ereport(ERROR, \
24 (errcode(ERRCODE_SYNTAX_ERROR), \
25 errmsg("syntax error at position %d near \"%c\"", \
26 (int)(ptr-buf), *ptr)));
36 #define LTPRS_WAITNAME 0
37 #define LTPRS_WAITDELIM 1
40 ltree_in(PG_FUNCTION_ARGS)
42 char *buf = (char *) PG_GETARG_POINTER(0);
48 int state = LTPRS_WAITNAME;
50 ltree_level *curlevel;
60 list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
64 if (state == LTPRS_WAITNAME)
69 state = LTPRS_WAITDELIM;
74 else if (state == LTPRS_WAITDELIM)
78 lptr->len = ptr - lptr->start;
81 (errcode(ERRCODE_NAME_TOO_LONG),
82 errmsg("name of level is too long"),
83 errdetail("name length is %d, must " \
84 "be < 256, in position %d",
85 lptr->len, (int) (lptr->start - buf))));
87 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
89 state = LTPRS_WAITNAME;
91 else if (!ISALNUM(*ptr))
96 elog(ERROR, "internal error in parser");
100 if (state == LTPRS_WAITDELIM)
102 lptr->len = ptr - lptr->start;
105 (errcode(ERRCODE_NAME_TOO_LONG),
106 errmsg("name of level is too long"),
107 errdetail("name length is %d, must " \
108 "be < 256, in position %d",
109 lptr->len, (int) (lptr->start - buf))));
111 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
114 else if (!(state == LTPRS_WAITNAME && lptr == list))
116 (errcode(ERRCODE_SYNTAX_ERROR),
117 errmsg("syntax error"),
118 errdetail("Unexpected end of line.")));
120 result = (ltree *) palloc(LTREE_HDRSIZE + totallen);
121 result->len = LTREE_HDRSIZE + totallen;
122 result->numlevel = lptr - list;
123 curlevel = LTREE_FIRST(result);
125 while (lptr - list < result->numlevel)
127 curlevel->len = (uint8) lptr->len;
128 memcpy(curlevel->name, lptr->start, lptr->len);
129 curlevel = LEVEL_NEXT(curlevel);
134 PG_RETURN_POINTER(result);
138 ltree_out(PG_FUNCTION_ARGS)
140 ltree *in = PG_GETARG_LTREE(0);
144 ltree_level *curlevel;
146 ptr = buf = (char *) palloc(in->len);
147 curlevel = LTREE_FIRST(in);
148 for (i = 0; i < in->numlevel; i++)
155 memcpy(ptr, curlevel->name, curlevel->len);
156 ptr += curlevel->len;
157 curlevel = LEVEL_NEXT(curlevel);
161 PG_FREE_IF_COPY(in, 0);
163 PG_RETURN_POINTER(buf);
166 #define LQPRS_WAITLEVEL 0
167 #define LQPRS_WAITDELIM 1
168 #define LQPRS_WAITOPEN 2
169 #define LQPRS_WAITFNUM 3
170 #define LQPRS_WAITSNUM 4
171 #define LQPRS_WAITND 5
172 #define LQPRS_WAITCLOSE 6
173 #define LQPRS_WAITEND 7
174 #define LQPRS_WAITVAR 8
177 #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
178 #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
179 #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
182 lquery_in(PG_FUNCTION_ARGS)
184 char *buf = (char *) PG_GETARG_POINTER(0);
189 int state = LQPRS_WAITLEVEL;
191 nodeitem *lptr = NULL;
195 lquery_variant *lrptr = NULL;
204 else if (*ptr == '|')
210 curqlevel = tmpql = (lquery_level *) palloc(ITEMSIZE * num);
211 memset((void *) tmpql, 0, ITEMSIZE * num);
215 if (state == LQPRS_WAITLEVEL)
219 GETVAR(curqlevel) = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (numOR + 1));
220 memset((void *) GETVAR(curqlevel), 0, sizeof(nodeitem) * (numOR + 1));
222 state = LQPRS_WAITDELIM;
223 curqlevel->numvar = 1;
225 else if (*ptr == '!')
227 GETVAR(curqlevel) = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (numOR + 1));
228 memset((void *) GETVAR(curqlevel), 0, sizeof(nodeitem) * (numOR + 1));
229 lptr->start = ptr + 1;
230 state = LQPRS_WAITDELIM;
231 curqlevel->numvar = 1;
232 curqlevel->flag |= LQL_NOT;
235 else if (*ptr == '*')
236 state = LQPRS_WAITOPEN;
240 else if (state == LQPRS_WAITVAR)
246 state = LQPRS_WAITDELIM;
252 else if (state == LQPRS_WAITDELIM)
256 if (lptr->start == ptr)
258 lptr->flag |= LVAR_INCASE;
259 curqlevel->flag |= LVAR_INCASE;
261 else if (*ptr == '*')
263 if (lptr->start == ptr)
265 lptr->flag |= LVAR_ANYEND;
266 curqlevel->flag |= LVAR_ANYEND;
268 else if (*ptr == '%')
270 if (lptr->start == ptr)
272 lptr->flag |= LVAR_SUBLEXEM;
273 curqlevel->flag |= LVAR_SUBLEXEM;
275 else if (*ptr == '|')
277 lptr->len = ptr - lptr->start -
278 ((lptr->flag & LVAR_SUBLEXEM) ? 1 : 0) -
279 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
280 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
283 (errcode(ERRCODE_NAME_TOO_LONG),
284 errmsg("name of level is too long"),
285 errdetail("name length is %d, must " \
286 "be < 256, in position %d",
287 lptr->len, (int) (lptr->start - buf))));
289 state = LQPRS_WAITVAR;
291 else if (*ptr == '.')
293 lptr->len = ptr - lptr->start -
294 ((lptr->flag & LVAR_SUBLEXEM) ? 1 : 0) -
295 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
296 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
299 (errcode(ERRCODE_NAME_TOO_LONG),
300 errmsg("name of level is too long"),
301 errdetail("name length is %d, must " \
302 "be < 256, in position %d",
303 lptr->len, (int) (lptr->start - buf))));
305 state = LQPRS_WAITLEVEL;
306 curqlevel = NEXTLEV(curqlevel);
308 else if (ISALNUM(*ptr))
316 else if (state == LQPRS_WAITOPEN)
319 state = LQPRS_WAITFNUM;
320 else if (*ptr == '.')
323 curqlevel->high = 0xffff;
324 curqlevel = NEXTLEV(curqlevel);
325 state = LQPRS_WAITLEVEL;
330 else if (state == LQPRS_WAITFNUM)
333 state = LQPRS_WAITSNUM;
334 else if (isdigit((unsigned int) *ptr))
336 curqlevel->low = atoi(ptr);
337 state = LQPRS_WAITND;
342 else if (state == LQPRS_WAITSNUM)
344 if (isdigit((unsigned int) *ptr))
346 curqlevel->high = atoi(ptr);
347 state = LQPRS_WAITCLOSE;
349 else if (*ptr == '}')
351 curqlevel->high = 0xffff;
352 state = LQPRS_WAITEND;
357 else if (state == LQPRS_WAITCLOSE)
360 state = LQPRS_WAITEND;
361 else if (!isdigit((unsigned int) *ptr))
364 else if (state == LQPRS_WAITND)
368 curqlevel->high = curqlevel->low;
369 state = LQPRS_WAITEND;
371 else if (*ptr == ',')
372 state = LQPRS_WAITSNUM;
373 else if (!isdigit((unsigned int) *ptr))
376 else if (state == LQPRS_WAITEND)
380 state = LQPRS_WAITLEVEL;
381 curqlevel = NEXTLEV(curqlevel);
388 elog(ERROR, "internal error in parser");
392 if (state == LQPRS_WAITDELIM)
394 if (lptr->start == ptr)
396 (errcode(ERRCODE_SYNTAX_ERROR),
397 errmsg("syntax error"),
398 errdetail("Unexpected end of line.")));
400 lptr->len = ptr - lptr->start -
401 ((lptr->flag & LVAR_SUBLEXEM) ? 1 : 0) -
402 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
403 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
406 (errcode(ERRCODE_SYNTAX_ERROR),
407 errmsg("syntax error"),
408 errdetail("Unexpected end of line.")));
412 (errcode(ERRCODE_NAME_TOO_LONG),
413 errmsg("name of level is too long"),
414 errdetail("name length is %d, must " \
415 "be < 256, in position %d",
416 lptr->len, (int) (lptr->start - buf))));
418 else if (state == LQPRS_WAITOPEN)
419 curqlevel->high = 0xffff;
420 else if (state != LQPRS_WAITEND)
422 (errcode(ERRCODE_SYNTAX_ERROR),
423 errmsg("syntax error"),
424 errdetail("Unexpected end of line.")));
427 totallen = LQUERY_HDRSIZE;
428 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
430 totallen += LQL_HDRSIZE;
431 if (curqlevel->numvar)
433 lptr = GETVAR(curqlevel);
434 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
436 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
440 else if (curqlevel->low > curqlevel->high)
442 (errcode(ERRCODE_SYNTAX_ERROR),
443 errmsg("syntax error"),
444 errdetail("Low limit(%d) is greater than upper(%d).",
445 curqlevel->low, curqlevel->high)));
447 curqlevel = NEXTLEV(curqlevel);
450 result = (lquery *) palloc(totallen);
451 result->len = totallen;
452 result->numlevel = num;
453 result->firstgood = 0;
456 result->flag |= LQUERY_HASNOT;
457 cur = LQUERY_FIRST(result);
459 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
461 memcpy(cur, curqlevel, LQL_HDRSIZE);
462 cur->totallen = LQL_HDRSIZE;
463 if (curqlevel->numvar)
465 lrptr = LQL_FIRST(cur);
466 lptr = GETVAR(curqlevel);
467 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
469 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
470 lrptr->len = lptr->len;
471 lrptr->flag = lptr->flag;
472 lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
473 memcpy(lrptr->name, lptr->start, lptr->len);
475 lrptr = LVAR_NEXT(lrptr);
477 pfree(GETVAR(curqlevel));
478 if (cur->numvar > 1 || cur->flag != 0)
480 else if (wasbad == false)
481 (result->firstgood)++;
485 curqlevel = NEXTLEV(curqlevel);
490 PG_RETURN_POINTER(result);
494 lquery_out(PG_FUNCTION_ARGS)
496 lquery *in = PG_GETARG_LQUERY(0);
502 lquery_level *curqlevel;
503 lquery_variant *curtlevel;
505 curqlevel = LQUERY_FIRST(in);
506 for (i = 0; i < in->numlevel; i++)
509 if (curqlevel->numvar)
510 totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
512 totallen += 2 * 11 + 4;
513 curqlevel = LQL_NEXT(curqlevel);
516 ptr = buf = (char *) palloc(totallen);
517 curqlevel = LQUERY_FIRST(in);
518 for (i = 0; i < in->numlevel; i++)
525 if (curqlevel->numvar)
527 if (curqlevel->flag & LQL_NOT)
532 curtlevel = LQL_FIRST(curqlevel);
533 for (j = 0; j < curqlevel->numvar; j++)
540 memcpy(ptr, curtlevel->name, curtlevel->len);
541 ptr += curtlevel->len;
542 if ((curtlevel->flag & LVAR_SUBLEXEM))
547 if ((curtlevel->flag & LVAR_INCASE))
552 if ((curtlevel->flag & LVAR_ANYEND))
557 curtlevel = LVAR_NEXT(curtlevel);
562 if (curqlevel->low == curqlevel->high)
564 sprintf(ptr, "*{%d}", curqlevel->low);
566 else if (curqlevel->low == 0)
568 if (curqlevel->high == 0xffff)
574 sprintf(ptr, "*{,%d}", curqlevel->high);
576 else if (curqlevel->high == 0xffff)
578 sprintf(ptr, "*{%d,}", curqlevel->low);
581 sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
582 ptr = strchr(ptr, '\0');
585 curqlevel = LQL_NEXT(curqlevel);
589 PG_FREE_IF_COPY(in, 0);
591 PG_RETURN_POINTER(buf);