]> granicus.if.org Git - postgresql/blob - contrib/ltree/ltree_io.c
Suppress signed-vs-unsigned-char warnings in contrib.
[postgresql] / contrib / ltree / ltree_io.c
1 /*
2  * in/out function for ltree and lquery
3  * Teodor Sigaev <teodor@stack.net>
4  */
5
6 #include "ltree.h"
7 #include <ctype.h>
8 #include "crc32.h"
9
10 PG_FUNCTION_INFO_V1(ltree_in);
11 Datum           ltree_in(PG_FUNCTION_ARGS);
12
13 PG_FUNCTION_INFO_V1(ltree_out);
14 Datum           ltree_out(PG_FUNCTION_ARGS);
15
16 PG_FUNCTION_INFO_V1(lquery_in);
17 Datum           lquery_in(PG_FUNCTION_ARGS);
18
19 PG_FUNCTION_INFO_V1(lquery_out);
20 Datum           lquery_out(PG_FUNCTION_ARGS);
21
22
23 #define UNCHAR ereport(ERROR, \
24                                            (errcode(ERRCODE_SYNTAX_ERROR), \
25                                                 errmsg("syntax error at position %d near \"%c\"", \
26                                                 (int)(ptr-buf), *ptr)));
27
28
29 typedef struct
30 {
31         char       *start;
32         int                     len;
33         int                     flag;
34 }       nodeitem;
35
36 #define LTPRS_WAITNAME  0
37 #define LTPRS_WAITDELIM 1
38
39 Datum
40 ltree_in(PG_FUNCTION_ARGS)
41 {
42         char       *buf = (char *) PG_GETARG_POINTER(0);
43         char       *ptr;
44         nodeitem   *list,
45                            *lptr;
46         int                     num = 0,
47                                 totallen = 0;
48         int                     state = LTPRS_WAITNAME;
49         ltree      *result;
50         ltree_level *curlevel;
51
52         ptr = buf;
53         while (*ptr)
54         {
55                 if (*ptr == '.')
56                         num++;
57                 ptr++;
58         }
59
60         list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
61         ptr = buf;
62         while (*ptr)
63         {
64                 if (state == LTPRS_WAITNAME)
65                 {
66                         if (ISALNUM(*ptr))
67                         {
68                                 lptr->start = ptr;
69                                 state = LTPRS_WAITDELIM;
70                         }
71                         else
72                                 UNCHAR;
73                 }
74                 else if (state == LTPRS_WAITDELIM)
75                 {
76                         if (*ptr == '.')
77                         {
78                                 lptr->len = ptr - lptr->start;
79                                 if (lptr->len > 255)
80                                         ereport(ERROR,
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))));
86
87                                 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
88                                 lptr++;
89                                 state = LTPRS_WAITNAME;
90                         }
91                         else if (!ISALNUM(*ptr))
92                                 UNCHAR;
93                 }
94                 else
95                         /* internal error */
96                         elog(ERROR, "internal error in parser");
97                 ptr++;
98         }
99
100         if (state == LTPRS_WAITDELIM)
101         {
102                 lptr->len = ptr - lptr->start;
103                 if (lptr->len > 255)
104                         ereport(ERROR,
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))));
110
111                 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
112                 lptr++;
113         }
114         else if (!(state == LTPRS_WAITNAME && lptr == list))
115                 ereport(ERROR,
116                                 (errcode(ERRCODE_SYNTAX_ERROR),
117                                  errmsg("syntax error"),
118                                  errdetail("Unexpected end of line.")));
119
120         result = (ltree *) palloc(LTREE_HDRSIZE + totallen);
121         result->len = LTREE_HDRSIZE + totallen;
122         result->numlevel = lptr - list;
123         curlevel = LTREE_FIRST(result);
124         lptr = list;
125         while (lptr - list < result->numlevel)
126         {
127                 curlevel->len = (uint8) lptr->len;
128                 memcpy(curlevel->name, lptr->start, lptr->len);
129                 curlevel = LEVEL_NEXT(curlevel);
130                 lptr++;
131         }
132
133         pfree(list);
134         PG_RETURN_POINTER(result);
135 }
136
137 Datum
138 ltree_out(PG_FUNCTION_ARGS)
139 {
140         ltree      *in = PG_GETARG_LTREE(0);
141         char       *buf,
142                            *ptr;
143         int                     i;
144         ltree_level *curlevel;
145
146         ptr = buf = (char *) palloc(in->len);
147         curlevel = LTREE_FIRST(in);
148         for (i = 0; i < in->numlevel; i++)
149         {
150                 if (i != 0)
151                 {
152                         *ptr = '.';
153                         ptr++;
154                 }
155                 memcpy(ptr, curlevel->name, curlevel->len);
156                 ptr += curlevel->len;
157                 curlevel = LEVEL_NEXT(curlevel);
158         }
159
160         *ptr = '\0';
161         PG_FREE_IF_COPY(in, 0);
162
163         PG_RETURN_POINTER(buf);
164 }
165
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
175
176
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) )
180
181 Datum
182 lquery_in(PG_FUNCTION_ARGS)
183 {
184         char       *buf = (char *) PG_GETARG_POINTER(0);
185         char       *ptr;
186         int                     num = 0,
187                                 totallen = 0,
188                                 numOR = 0;
189         int                     state = LQPRS_WAITLEVEL;
190         lquery     *result;
191         nodeitem   *lptr = NULL;
192         lquery_level *cur,
193                            *curqlevel,
194                            *tmpql;
195         lquery_variant *lrptr = NULL;
196         bool            hasnot = false;
197         bool            wasbad = false;
198
199         ptr = buf;
200         while (*ptr)
201         {
202                 if (*ptr == '.')
203                         num++;
204                 else if (*ptr == '|')
205                         numOR++;
206                 ptr++;
207         }
208
209         num++;
210         curqlevel = tmpql = (lquery_level *) palloc(ITEMSIZE * num);
211         memset((void *) tmpql, 0, ITEMSIZE * num);
212         ptr = buf;
213         while (*ptr)
214         {
215                 if (state == LQPRS_WAITLEVEL)
216                 {
217                         if (ISALNUM(*ptr))
218                         {
219                                 GETVAR(curqlevel) = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (numOR + 1));
220                                 memset((void *) GETVAR(curqlevel), 0, sizeof(nodeitem) * (numOR + 1));
221                                 lptr->start = ptr;
222                                 state = LQPRS_WAITDELIM;
223                                 curqlevel->numvar = 1;
224                         }
225                         else if (*ptr == '!')
226                         {
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;
233                                 hasnot = true;
234                         }
235                         else if (*ptr == '*')
236                                 state = LQPRS_WAITOPEN;
237                         else
238                                 UNCHAR;
239                 }
240                 else if (state == LQPRS_WAITVAR)
241                 {
242                         if (ISALNUM(*ptr))
243                         {
244                                 lptr++;
245                                 lptr->start = ptr;
246                                 state = LQPRS_WAITDELIM;
247                                 curqlevel->numvar++;
248                         }
249                         else
250                                 UNCHAR;
251                 }
252                 else if (state == LQPRS_WAITDELIM)
253                 {
254                         if (*ptr == '@')
255                         {
256                                 if (lptr->start == ptr)
257                                         UNCHAR;
258                                 lptr->flag |= LVAR_INCASE;
259                                 curqlevel->flag |= LVAR_INCASE;
260                         }
261                         else if (*ptr == '*')
262                         {
263                                 if (lptr->start == ptr)
264                                         UNCHAR;
265                                 lptr->flag |= LVAR_ANYEND;
266                                 curqlevel->flag |= LVAR_ANYEND;
267                         }
268                         else if (*ptr == '%')
269                         {
270                                 if (lptr->start == ptr)
271                                         UNCHAR;
272                                 lptr->flag |= LVAR_SUBLEXEM;
273                                 curqlevel->flag |= LVAR_SUBLEXEM;
274                         }
275                         else if (*ptr == '|')
276                         {
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);
281                                 if (lptr->len > 255)
282                                         ereport(ERROR,
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))));
288
289                                 state = LQPRS_WAITVAR;
290                         }
291                         else if (*ptr == '.')
292                         {
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);
297                                 if (lptr->len > 255)
298                                         ereport(ERROR,
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))));
304
305                                 state = LQPRS_WAITLEVEL;
306                                 curqlevel = NEXTLEV(curqlevel);
307                         }
308                         else if (ISALNUM(*ptr))
309                         {
310                                 if (lptr->flag)
311                                         UNCHAR;
312                         }
313                         else
314                                 UNCHAR;
315                 }
316                 else if (state == LQPRS_WAITOPEN)
317                 {
318                         if (*ptr == '{')
319                                 state = LQPRS_WAITFNUM;
320                         else if (*ptr == '.')
321                         {
322                                 curqlevel->low = 0;
323                                 curqlevel->high = 0xffff;
324                                 curqlevel = NEXTLEV(curqlevel);
325                                 state = LQPRS_WAITLEVEL;
326                         }
327                         else
328                                 UNCHAR;
329                 }
330                 else if (state == LQPRS_WAITFNUM)
331                 {
332                         if (*ptr == ',')
333                                 state = LQPRS_WAITSNUM;
334                         else if (isdigit((unsigned int) *ptr))
335                         {
336                                 curqlevel->low = atoi(ptr);
337                                 state = LQPRS_WAITND;
338                         }
339                         else
340                                 UNCHAR;
341                 }
342                 else if (state == LQPRS_WAITSNUM)
343                 {
344                         if (isdigit((unsigned int) *ptr))
345                         {
346                                 curqlevel->high = atoi(ptr);
347                                 state = LQPRS_WAITCLOSE;
348                         }
349                         else if (*ptr == '}')
350                         {
351                                 curqlevel->high = 0xffff;
352                                 state = LQPRS_WAITEND;
353                         }
354                         else
355                                 UNCHAR;
356                 }
357                 else if (state == LQPRS_WAITCLOSE)
358                 {
359                         if (*ptr == '}')
360                                 state = LQPRS_WAITEND;
361                         else if (!isdigit((unsigned int) *ptr))
362                                 UNCHAR;
363                 }
364                 else if (state == LQPRS_WAITND)
365                 {
366                         if (*ptr == '}')
367                         {
368                                 curqlevel->high = curqlevel->low;
369                                 state = LQPRS_WAITEND;
370                         }
371                         else if (*ptr == ',')
372                                 state = LQPRS_WAITSNUM;
373                         else if (!isdigit((unsigned int) *ptr))
374                                 UNCHAR;
375                 }
376                 else if (state == LQPRS_WAITEND)
377                 {
378                         if (*ptr == '.')
379                         {
380                                 state = LQPRS_WAITLEVEL;
381                                 curqlevel = NEXTLEV(curqlevel);
382                         }
383                         else
384                                 UNCHAR;
385                 }
386                 else
387                         /* internal error */
388                         elog(ERROR, "internal error in parser");
389                 ptr++;
390         }
391
392         if (state == LQPRS_WAITDELIM)
393         {
394                 if (lptr->start == ptr)
395                         ereport(ERROR,
396                                         (errcode(ERRCODE_SYNTAX_ERROR),
397                                          errmsg("syntax error"),
398                                          errdetail("Unexpected end of line.")));
399
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);
404                 if (lptr->len == 0)
405                         ereport(ERROR,
406                                         (errcode(ERRCODE_SYNTAX_ERROR),
407                                          errmsg("syntax error"),
408                                          errdetail("Unexpected end of line.")));
409
410                 if (lptr->len > 255)
411                         ereport(ERROR,
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))));
417         }
418         else if (state == LQPRS_WAITOPEN)
419                 curqlevel->high = 0xffff;
420         else if (state != LQPRS_WAITEND)
421                 ereport(ERROR,
422                                 (errcode(ERRCODE_SYNTAX_ERROR),
423                                  errmsg("syntax error"),
424                                  errdetail("Unexpected end of line.")));
425
426         curqlevel = tmpql;
427         totallen = LQUERY_HDRSIZE;
428         while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
429         {
430                 totallen += LQL_HDRSIZE;
431                 if (curqlevel->numvar)
432                 {
433                         lptr = GETVAR(curqlevel);
434                         while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
435                         {
436                                 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
437                                 lptr++;
438                         }
439                 }
440                 else if (curqlevel->low > curqlevel->high)
441                         ereport(ERROR,
442                                         (errcode(ERRCODE_SYNTAX_ERROR),
443                                          errmsg("syntax error"),
444                                          errdetail("Low limit(%d) is greater than upper(%d).",
445                                                            curqlevel->low, curqlevel->high)));
446
447                 curqlevel = NEXTLEV(curqlevel);
448         }
449
450         result = (lquery *) palloc(totallen);
451         result->len = totallen;
452         result->numlevel = num;
453         result->firstgood = 0;
454         result->flag = 0;
455         if (hasnot)
456                 result->flag |= LQUERY_HASNOT;
457         cur = LQUERY_FIRST(result);
458         curqlevel = tmpql;
459         while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
460         {
461                 memcpy(cur, curqlevel, LQL_HDRSIZE);
462                 cur->totallen = LQL_HDRSIZE;
463                 if (curqlevel->numvar)
464                 {
465                         lrptr = LQL_FIRST(cur);
466                         lptr = GETVAR(curqlevel);
467                         while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
468                         {
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);
474                                 lptr++;
475                                 lrptr = LVAR_NEXT(lrptr);
476                         }
477                         pfree(GETVAR(curqlevel));
478                         if (cur->numvar > 1 || cur->flag != 0)
479                                 wasbad = true;
480                         else if (wasbad == false)
481                                 (result->firstgood)++;
482                 }
483                 else
484                         wasbad = true;
485                 curqlevel = NEXTLEV(curqlevel);
486                 cur = LQL_NEXT(cur);
487         }
488
489         pfree(tmpql);
490         PG_RETURN_POINTER(result);
491 }
492
493 Datum
494 lquery_out(PG_FUNCTION_ARGS)
495 {
496         lquery     *in = PG_GETARG_LQUERY(0);
497         char       *buf,
498                            *ptr;
499         int                     i,
500                                 j,
501                                 totallen = 1;
502         lquery_level *curqlevel;
503         lquery_variant *curtlevel;
504
505         curqlevel = LQUERY_FIRST(in);
506         for (i = 0; i < in->numlevel; i++)
507         {
508                 totallen++;
509                 if (curqlevel->numvar)
510                         totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
511                 else
512                         totallen += 2 * 11 + 4;
513                 curqlevel = LQL_NEXT(curqlevel);
514         }
515
516         ptr = buf = (char *) palloc(totallen);
517         curqlevel = LQUERY_FIRST(in);
518         for (i = 0; i < in->numlevel; i++)
519         {
520                 if (i != 0)
521                 {
522                         *ptr = '.';
523                         ptr++;
524                 }
525                 if (curqlevel->numvar)
526                 {
527                         if (curqlevel->flag & LQL_NOT)
528                         {
529                                 *ptr = '!';
530                                 ptr++;
531                         }
532                         curtlevel = LQL_FIRST(curqlevel);
533                         for (j = 0; j < curqlevel->numvar; j++)
534                         {
535                                 if (j != 0)
536                                 {
537                                         *ptr = '|';
538                                         ptr++;
539                                 }
540                                 memcpy(ptr, curtlevel->name, curtlevel->len);
541                                 ptr += curtlevel->len;
542                                 if ((curtlevel->flag & LVAR_SUBLEXEM))
543                                 {
544                                         *ptr = '%';
545                                         ptr++;
546                                 }
547                                 if ((curtlevel->flag & LVAR_INCASE))
548                                 {
549                                         *ptr = '@';
550                                         ptr++;
551                                 }
552                                 if ((curtlevel->flag & LVAR_ANYEND))
553                                 {
554                                         *ptr = '*';
555                                         ptr++;
556                                 }
557                                 curtlevel = LVAR_NEXT(curtlevel);
558                         }
559                 }
560                 else
561                 {
562                         if (curqlevel->low == curqlevel->high)
563                         {
564                                 sprintf(ptr, "*{%d}", curqlevel->low);
565                         }
566                         else if (curqlevel->low == 0)
567                         {
568                                 if (curqlevel->high == 0xffff)
569                                 {
570                                         *ptr = '*';
571                                         *(ptr + 1) = '\0';
572                                 }
573                                 else
574                                         sprintf(ptr, "*{,%d}", curqlevel->high);
575                         }
576                         else if (curqlevel->high == 0xffff)
577                         {
578                                 sprintf(ptr, "*{%d,}", curqlevel->low);
579                         }
580                         else
581                                 sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
582                         ptr = strchr(ptr, '\0');
583                 }
584
585                 curqlevel = LQL_NEXT(curqlevel);
586         }
587
588         *ptr = '\0';
589         PG_FREE_IF_COPY(in, 0);
590
591         PG_RETURN_POINTER(buf);
592 }