More sensible character_octet_length
[PostgreSQL.git] / contrib / ltree / ltree_io.c
blobee6ee568e3e47cd38e06c91908945bba3aff16dd
1 /*
2 * in/out function for ltree and lquery
3 * Teodor Sigaev <teodor@stack.net>
4 * $PostgreSQL$
5 */
6 #include "postgres.h"
8 #include <ctype.h>
10 #include "ltree.h"
11 #include "crc32.h"
13 PG_FUNCTION_INFO_V1(ltree_in);
14 Datum ltree_in(PG_FUNCTION_ARGS);
16 PG_FUNCTION_INFO_V1(ltree_out);
17 Datum ltree_out(PG_FUNCTION_ARGS);
19 PG_FUNCTION_INFO_V1(lquery_in);
20 Datum lquery_in(PG_FUNCTION_ARGS);
22 PG_FUNCTION_INFO_V1(lquery_out);
23 Datum lquery_out(PG_FUNCTION_ARGS);
26 #define UNCHAR ereport(ERROR, \
27 (errcode(ERRCODE_SYNTAX_ERROR), \
28 errmsg("syntax error at position %d", \
29 pos)));
32 typedef struct
34 char *start;
35 int len; /* length in bytes */
36 int flag;
37 int wlen; /* length in characters */
38 } nodeitem;
40 #define LTPRS_WAITNAME 0
41 #define LTPRS_WAITDELIM 1
43 Datum
44 ltree_in(PG_FUNCTION_ARGS)
46 char *buf = (char *) PG_GETARG_POINTER(0);
47 char *ptr;
48 nodeitem *list,
49 *lptr;
50 int num = 0,
51 totallen = 0;
52 int state = LTPRS_WAITNAME;
53 ltree *result;
54 ltree_level *curlevel;
55 int charlen;
56 int pos = 0;
58 ptr = buf;
59 while (*ptr)
61 charlen = pg_mblen(ptr);
62 if (charlen == 1 && t_iseq(ptr, '.'))
63 num++;
64 ptr += charlen;
67 list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
68 ptr = buf;
69 while (*ptr)
71 charlen = pg_mblen(ptr);
73 if (state == LTPRS_WAITNAME)
75 if (ISALNUM(ptr))
77 lptr->start = ptr;
78 lptr->wlen = 0;
79 state = LTPRS_WAITDELIM;
81 else
82 UNCHAR;
84 else if (state == LTPRS_WAITDELIM)
86 if (charlen == 1 && t_iseq(ptr, '.'))
88 lptr->len = ptr - lptr->start;
89 if (lptr->wlen > 255)
90 ereport(ERROR,
91 (errcode(ERRCODE_NAME_TOO_LONG),
92 errmsg("name of level is too long"),
93 errdetail("Name length is %d, must "
94 "be < 256, in position %d.",
95 lptr->wlen, pos)));
97 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
98 lptr++;
99 state = LTPRS_WAITNAME;
101 else if (!ISALNUM(ptr))
102 UNCHAR;
104 else
105 /* internal error */
106 elog(ERROR, "internal error in parser");
108 ptr += charlen;
109 lptr->wlen++;
110 pos++;
113 if (state == LTPRS_WAITDELIM)
115 lptr->len = ptr - lptr->start;
116 if (lptr->wlen > 255)
117 ereport(ERROR,
118 (errcode(ERRCODE_NAME_TOO_LONG),
119 errmsg("name of level is too long"),
120 errdetail("Name length is %d, must "
121 "be < 256, in position %d.",
122 lptr->wlen, pos)));
124 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
125 lptr++;
127 else if (!(state == LTPRS_WAITNAME && lptr == list))
128 ereport(ERROR,
129 (errcode(ERRCODE_SYNTAX_ERROR),
130 errmsg("syntax error"),
131 errdetail("Unexpected end of line.")));
133 result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
134 SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
135 result->numlevel = lptr - list;
136 curlevel = LTREE_FIRST(result);
137 lptr = list;
138 while (lptr - list < result->numlevel)
140 curlevel->len = (uint16) lptr->len;
141 memcpy(curlevel->name, lptr->start, lptr->len);
142 curlevel = LEVEL_NEXT(curlevel);
143 lptr++;
146 pfree(list);
147 PG_RETURN_POINTER(result);
150 Datum
151 ltree_out(PG_FUNCTION_ARGS)
153 ltree *in = PG_GETARG_LTREE(0);
154 char *buf,
155 *ptr;
156 int i;
157 ltree_level *curlevel;
159 ptr = buf = (char *) palloc(VARSIZE(in));
160 curlevel = LTREE_FIRST(in);
161 for (i = 0; i < in->numlevel; i++)
163 if (i != 0)
165 *ptr = '.';
166 ptr++;
168 memcpy(ptr, curlevel->name, curlevel->len);
169 ptr += curlevel->len;
170 curlevel = LEVEL_NEXT(curlevel);
173 *ptr = '\0';
174 PG_FREE_IF_COPY(in, 0);
176 PG_RETURN_POINTER(buf);
179 #define LQPRS_WAITLEVEL 0
180 #define LQPRS_WAITDELIM 1
181 #define LQPRS_WAITOPEN 2
182 #define LQPRS_WAITFNUM 3
183 #define LQPRS_WAITSNUM 4
184 #define LQPRS_WAITND 5
185 #define LQPRS_WAITCLOSE 6
186 #define LQPRS_WAITEND 7
187 #define LQPRS_WAITVAR 8
190 #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
191 #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
192 #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
194 Datum
195 lquery_in(PG_FUNCTION_ARGS)
197 char *buf = (char *) PG_GETARG_POINTER(0);
198 char *ptr;
199 int num = 0,
200 totallen = 0,
201 numOR = 0;
202 int state = LQPRS_WAITLEVEL;
203 lquery *result;
204 nodeitem *lptr = NULL;
205 lquery_level *cur,
206 *curqlevel,
207 *tmpql;
208 lquery_variant *lrptr = NULL;
209 bool hasnot = false;
210 bool wasbad = false;
211 int charlen;
212 int pos = 0;
214 ptr = buf;
215 while (*ptr)
217 charlen = pg_mblen(ptr);
219 if (charlen == 1)
221 if (t_iseq(ptr, '.'))
222 num++;
223 else if (t_iseq(ptr, '|'))
224 numOR++;
227 ptr += charlen;
230 num++;
231 curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
232 ptr = buf;
233 while (*ptr)
235 charlen = pg_mblen(ptr);
237 if (state == LQPRS_WAITLEVEL)
239 if (ISALNUM(ptr))
241 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
242 lptr->start = ptr;
243 state = LQPRS_WAITDELIM;
244 curqlevel->numvar = 1;
246 else if (charlen == 1 && t_iseq(ptr, '!'))
248 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
249 lptr->start = ptr + 1;
250 state = LQPRS_WAITDELIM;
251 curqlevel->numvar = 1;
252 curqlevel->flag |= LQL_NOT;
253 hasnot = true;
255 else if (charlen == 1 && t_iseq(ptr, '*'))
256 state = LQPRS_WAITOPEN;
257 else
258 UNCHAR;
260 else if (state == LQPRS_WAITVAR)
262 if (ISALNUM(ptr))
264 lptr++;
265 lptr->start = ptr;
266 state = LQPRS_WAITDELIM;
267 curqlevel->numvar++;
269 else
270 UNCHAR;
272 else if (state == LQPRS_WAITDELIM)
274 if (charlen == 1 && t_iseq(ptr, '@'))
276 if (lptr->start == ptr)
277 UNCHAR;
278 lptr->flag |= LVAR_INCASE;
279 curqlevel->flag |= LVAR_INCASE;
281 else if (charlen == 1 && t_iseq(ptr, '*'))
283 if (lptr->start == ptr)
284 UNCHAR;
285 lptr->flag |= LVAR_ANYEND;
286 curqlevel->flag |= LVAR_ANYEND;
288 else if (charlen == 1 && t_iseq(ptr, '%'))
290 if (lptr->start == ptr)
291 UNCHAR;
292 lptr->flag |= LVAR_SUBLEXEME;
293 curqlevel->flag |= LVAR_SUBLEXEME;
295 else if (charlen == 1 && t_iseq(ptr, '|'))
297 lptr->len = ptr - lptr->start -
298 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
299 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
300 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
301 if (lptr->wlen > 255)
302 ereport(ERROR,
303 (errcode(ERRCODE_NAME_TOO_LONG),
304 errmsg("name of level is too long"),
305 errdetail("Name length is %d, must "
306 "be < 256, in position %d.",
307 lptr->wlen, pos)));
309 state = LQPRS_WAITVAR;
311 else if (charlen == 1 && t_iseq(ptr, '.'))
313 lptr->len = ptr - lptr->start -
314 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
315 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
316 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
317 if (lptr->wlen > 255)
318 ereport(ERROR,
319 (errcode(ERRCODE_NAME_TOO_LONG),
320 errmsg("name of level is too long"),
321 errdetail("Name length is %d, must "
322 "be < 256, in position %d.",
323 lptr->wlen, pos)));
325 state = LQPRS_WAITLEVEL;
326 curqlevel = NEXTLEV(curqlevel);
328 else if (ISALNUM(ptr))
330 if (lptr->flag)
331 UNCHAR;
333 else
334 UNCHAR;
336 else if (state == LQPRS_WAITOPEN)
338 if (charlen == 1 && t_iseq(ptr, '{'))
339 state = LQPRS_WAITFNUM;
340 else if (charlen == 1 && t_iseq(ptr, '.'))
342 curqlevel->low = 0;
343 curqlevel->high = 0xffff;
344 curqlevel = NEXTLEV(curqlevel);
345 state = LQPRS_WAITLEVEL;
347 else
348 UNCHAR;
350 else if (state == LQPRS_WAITFNUM)
352 if (charlen == 1 && t_iseq(ptr, ','))
353 state = LQPRS_WAITSNUM;
354 else if (t_isdigit(ptr))
356 curqlevel->low = atoi(ptr);
357 state = LQPRS_WAITND;
359 else
360 UNCHAR;
362 else if (state == LQPRS_WAITSNUM)
364 if (t_isdigit(ptr))
366 curqlevel->high = atoi(ptr);
367 state = LQPRS_WAITCLOSE;
369 else if (charlen == 1 && t_iseq(ptr, '}'))
371 curqlevel->high = 0xffff;
372 state = LQPRS_WAITEND;
374 else
375 UNCHAR;
377 else if (state == LQPRS_WAITCLOSE)
379 if (charlen == 1 && t_iseq(ptr, '}'))
380 state = LQPRS_WAITEND;
381 else if (!t_isdigit(ptr))
382 UNCHAR;
384 else if (state == LQPRS_WAITND)
386 if (charlen == 1 && t_iseq(ptr, '}'))
388 curqlevel->high = curqlevel->low;
389 state = LQPRS_WAITEND;
391 else if (charlen == 1 && t_iseq(ptr, ','))
392 state = LQPRS_WAITSNUM;
393 else if (!t_isdigit(ptr))
394 UNCHAR;
396 else if (state == LQPRS_WAITEND)
398 if (charlen == 1 && t_iseq(ptr, '.'))
400 state = LQPRS_WAITLEVEL;
401 curqlevel = NEXTLEV(curqlevel);
403 else
404 UNCHAR;
406 else
407 /* internal error */
408 elog(ERROR, "internal error in parser");
410 ptr += charlen;
411 if (state == LQPRS_WAITDELIM)
412 lptr->wlen++;
413 pos++;
416 if (state == LQPRS_WAITDELIM)
418 if (lptr->start == ptr)
419 ereport(ERROR,
420 (errcode(ERRCODE_SYNTAX_ERROR),
421 errmsg("syntax error"),
422 errdetail("Unexpected end of line.")));
424 lptr->len = ptr - lptr->start -
425 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
426 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
427 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
428 if (lptr->len == 0)
429 ereport(ERROR,
430 (errcode(ERRCODE_SYNTAX_ERROR),
431 errmsg("syntax error"),
432 errdetail("Unexpected end of line.")));
434 if (lptr->wlen > 255)
435 ereport(ERROR,
436 (errcode(ERRCODE_NAME_TOO_LONG),
437 errmsg("name of level is too long"),
438 errdetail("Name length is %d, must "
439 "be < 256, in position %d.",
440 lptr->wlen, pos)));
442 else if (state == LQPRS_WAITOPEN)
443 curqlevel->high = 0xffff;
444 else if (state != LQPRS_WAITEND)
445 ereport(ERROR,
446 (errcode(ERRCODE_SYNTAX_ERROR),
447 errmsg("syntax error"),
448 errdetail("Unexpected end of line.")));
450 curqlevel = tmpql;
451 totallen = LQUERY_HDRSIZE;
452 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
454 totallen += LQL_HDRSIZE;
455 if (curqlevel->numvar)
457 lptr = GETVAR(curqlevel);
458 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
460 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
461 lptr++;
464 else if (curqlevel->low > curqlevel->high)
465 ereport(ERROR,
466 (errcode(ERRCODE_SYNTAX_ERROR),
467 errmsg("syntax error"),
468 errdetail("Low limit(%d) is greater than upper(%d).",
469 curqlevel->low, curqlevel->high)));
471 curqlevel = NEXTLEV(curqlevel);
474 result = (lquery *) palloc0(totallen);
475 SET_VARSIZE(result, totallen);
476 result->numlevel = num;
477 result->firstgood = 0;
478 result->flag = 0;
479 if (hasnot)
480 result->flag |= LQUERY_HASNOT;
481 cur = LQUERY_FIRST(result);
482 curqlevel = tmpql;
483 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
485 memcpy(cur, curqlevel, LQL_HDRSIZE);
486 cur->totallen = LQL_HDRSIZE;
487 if (curqlevel->numvar)
489 lrptr = LQL_FIRST(cur);
490 lptr = GETVAR(curqlevel);
491 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
493 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
494 lrptr->len = lptr->len;
495 lrptr->flag = lptr->flag;
496 lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
497 memcpy(lrptr->name, lptr->start, lptr->len);
498 lptr++;
499 lrptr = LVAR_NEXT(lrptr);
501 pfree(GETVAR(curqlevel));
502 if (cur->numvar > 1 || cur->flag != 0)
503 wasbad = true;
504 else if (wasbad == false)
505 (result->firstgood)++;
507 else
508 wasbad = true;
509 curqlevel = NEXTLEV(curqlevel);
510 cur = LQL_NEXT(cur);
513 pfree(tmpql);
514 PG_RETURN_POINTER(result);
517 Datum
518 lquery_out(PG_FUNCTION_ARGS)
520 lquery *in = PG_GETARG_LQUERY(0);
521 char *buf,
522 *ptr;
523 int i,
525 totallen = 1;
526 lquery_level *curqlevel;
527 lquery_variant *curtlevel;
529 curqlevel = LQUERY_FIRST(in);
530 for (i = 0; i < in->numlevel; i++)
532 totallen++;
533 if (curqlevel->numvar)
534 totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
535 else
536 totallen += 2 * 11 + 4;
537 curqlevel = LQL_NEXT(curqlevel);
540 ptr = buf = (char *) palloc(totallen);
541 curqlevel = LQUERY_FIRST(in);
542 for (i = 0; i < in->numlevel; i++)
544 if (i != 0)
546 *ptr = '.';
547 ptr++;
549 if (curqlevel->numvar)
551 if (curqlevel->flag & LQL_NOT)
553 *ptr = '!';
554 ptr++;
556 curtlevel = LQL_FIRST(curqlevel);
557 for (j = 0; j < curqlevel->numvar; j++)
559 if (j != 0)
561 *ptr = '|';
562 ptr++;
564 memcpy(ptr, curtlevel->name, curtlevel->len);
565 ptr += curtlevel->len;
566 if ((curtlevel->flag & LVAR_SUBLEXEME))
568 *ptr = '%';
569 ptr++;
571 if ((curtlevel->flag & LVAR_INCASE))
573 *ptr = '@';
574 ptr++;
576 if ((curtlevel->flag & LVAR_ANYEND))
578 *ptr = '*';
579 ptr++;
581 curtlevel = LVAR_NEXT(curtlevel);
584 else
586 if (curqlevel->low == curqlevel->high)
588 sprintf(ptr, "*{%d}", curqlevel->low);
590 else if (curqlevel->low == 0)
592 if (curqlevel->high == 0xffff)
594 *ptr = '*';
595 *(ptr + 1) = '\0';
597 else
598 sprintf(ptr, "*{,%d}", curqlevel->high);
600 else if (curqlevel->high == 0xffff)
602 sprintf(ptr, "*{%d,}", curqlevel->low);
604 else
605 sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
606 ptr = strchr(ptr, '\0');
609 curqlevel = LQL_NEXT(curqlevel);
612 *ptr = '\0';
613 PG_FREE_IF_COPY(in, 0);
615 PG_RETURN_POINTER(buf);