2 * in/out function for ltree and lquery
3 * Teodor Sigaev <teodor@stack.net>
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", \
35 int len
; /* length in bytes */
37 int wlen
; /* length in characters */
40 #define LTPRS_WAITNAME 0
41 #define LTPRS_WAITDELIM 1
44 ltree_in(PG_FUNCTION_ARGS
)
46 char *buf
= (char *) PG_GETARG_POINTER(0);
52 int state
= LTPRS_WAITNAME
;
54 ltree_level
*curlevel
;
61 charlen
= pg_mblen(ptr
);
62 if (charlen
== 1 && t_iseq(ptr
, '.'))
67 list
= lptr
= (nodeitem
*) palloc(sizeof(nodeitem
) * (num
+ 1));
71 charlen
= pg_mblen(ptr
);
73 if (state
== LTPRS_WAITNAME
)
79 state
= LTPRS_WAITDELIM
;
84 else if (state
== LTPRS_WAITDELIM
)
86 if (charlen
== 1 && t_iseq(ptr
, '.'))
88 lptr
->len
= ptr
- lptr
->start
;
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.",
97 totallen
+= MAXALIGN(lptr
->len
+ LEVEL_HDRSIZE
);
99 state
= LTPRS_WAITNAME
;
101 else if (!ISALNUM(ptr
))
106 elog(ERROR
, "internal error in parser");
113 if (state
== LTPRS_WAITDELIM
)
115 lptr
->len
= ptr
- lptr
->start
;
116 if (lptr
->wlen
> 255)
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.",
124 totallen
+= MAXALIGN(lptr
->len
+ LEVEL_HDRSIZE
);
127 else if (!(state
== LTPRS_WAITNAME
&& lptr
== list
))
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
);
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
);
147 PG_RETURN_POINTER(result
);
151 ltree_out(PG_FUNCTION_ARGS
)
153 ltree
*in
= PG_GETARG_LTREE(0);
157 ltree_level
*curlevel
;
159 ptr
= buf
= (char *) palloc(VARSIZE(in
));
160 curlevel
= LTREE_FIRST(in
);
161 for (i
= 0; i
< in
->numlevel
; i
++)
168 memcpy(ptr
, curlevel
->name
, curlevel
->len
);
169 ptr
+= curlevel
->len
;
170 curlevel
= LEVEL_NEXT(curlevel
);
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) )
195 lquery_in(PG_FUNCTION_ARGS
)
197 char *buf
= (char *) PG_GETARG_POINTER(0);
202 int state
= LQPRS_WAITLEVEL
;
204 nodeitem
*lptr
= NULL
;
208 lquery_variant
*lrptr
= NULL
;
217 charlen
= pg_mblen(ptr
);
221 if (t_iseq(ptr
, '.'))
223 else if (t_iseq(ptr
, '|'))
231 curqlevel
= tmpql
= (lquery_level
*) palloc0(ITEMSIZE
* num
);
235 charlen
= pg_mblen(ptr
);
237 if (state
== LQPRS_WAITLEVEL
)
241 GETVAR(curqlevel
) = lptr
= (nodeitem
*) palloc0(sizeof(nodeitem
) * (numOR
+ 1));
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
;
255 else if (charlen
== 1 && t_iseq(ptr
, '*'))
256 state
= LQPRS_WAITOPEN
;
260 else if (state
== LQPRS_WAITVAR
)
266 state
= LQPRS_WAITDELIM
;
272 else if (state
== LQPRS_WAITDELIM
)
274 if (charlen
== 1 && t_iseq(ptr
, '@'))
276 if (lptr
->start
== ptr
)
278 lptr
->flag
|= LVAR_INCASE
;
279 curqlevel
->flag
|= LVAR_INCASE
;
281 else if (charlen
== 1 && t_iseq(ptr
, '*'))
283 if (lptr
->start
== ptr
)
285 lptr
->flag
|= LVAR_ANYEND
;
286 curqlevel
->flag
|= LVAR_ANYEND
;
288 else if (charlen
== 1 && t_iseq(ptr
, '%'))
290 if (lptr
->start
== ptr
)
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)
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.",
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)
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.",
325 state
= LQPRS_WAITLEVEL
;
326 curqlevel
= NEXTLEV(curqlevel
);
328 else if (ISALNUM(ptr
))
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
, '.'))
343 curqlevel
->high
= 0xffff;
344 curqlevel
= NEXTLEV(curqlevel
);
345 state
= LQPRS_WAITLEVEL
;
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
;
362 else if (state
== LQPRS_WAITSNUM
)
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
;
377 else if (state
== LQPRS_WAITCLOSE
)
379 if (charlen
== 1 && t_iseq(ptr
, '}'))
380 state
= LQPRS_WAITEND
;
381 else if (!t_isdigit(ptr
))
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
))
396 else if (state
== LQPRS_WAITEND
)
398 if (charlen
== 1 && t_iseq(ptr
, '.'))
400 state
= LQPRS_WAITLEVEL
;
401 curqlevel
= NEXTLEV(curqlevel
);
408 elog(ERROR
, "internal error in parser");
411 if (state
== LQPRS_WAITDELIM
)
416 if (state
== LQPRS_WAITDELIM
)
418 if (lptr
->start
== ptr
)
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);
430 (errcode(ERRCODE_SYNTAX_ERROR
),
431 errmsg("syntax error"),
432 errdetail("Unexpected end of line.")));
434 if (lptr
->wlen
> 255)
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.",
442 else if (state
== LQPRS_WAITOPEN
)
443 curqlevel
->high
= 0xffff;
444 else if (state
!= LQPRS_WAITEND
)
446 (errcode(ERRCODE_SYNTAX_ERROR
),
447 errmsg("syntax error"),
448 errdetail("Unexpected end of line.")));
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
);
464 else if (curqlevel
->low
> curqlevel
->high
)
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;
480 result
->flag
|= LQUERY_HASNOT
;
481 cur
= LQUERY_FIRST(result
);
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
);
499 lrptr
= LVAR_NEXT(lrptr
);
501 pfree(GETVAR(curqlevel
));
502 if (cur
->numvar
> 1 || cur
->flag
!= 0)
504 else if (wasbad
== false)
505 (result
->firstgood
)++;
509 curqlevel
= NEXTLEV(curqlevel
);
514 PG_RETURN_POINTER(result
);
518 lquery_out(PG_FUNCTION_ARGS
)
520 lquery
*in
= PG_GETARG_LQUERY(0);
526 lquery_level
*curqlevel
;
527 lquery_variant
*curtlevel
;
529 curqlevel
= LQUERY_FIRST(in
);
530 for (i
= 0; i
< in
->numlevel
; i
++)
533 if (curqlevel
->numvar
)
534 totallen
+= 1 + (curqlevel
->numvar
* 4) + curqlevel
->totallen
;
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
++)
549 if (curqlevel
->numvar
)
551 if (curqlevel
->flag
& LQL_NOT
)
556 curtlevel
= LQL_FIRST(curqlevel
);
557 for (j
= 0; j
< curqlevel
->numvar
; j
++)
564 memcpy(ptr
, curtlevel
->name
, curtlevel
->len
);
565 ptr
+= curtlevel
->len
;
566 if ((curtlevel
->flag
& LVAR_SUBLEXEME
))
571 if ((curtlevel
->flag
& LVAR_INCASE
))
576 if ((curtlevel
->flag
& LVAR_ANYEND
))
581 curtlevel
= LVAR_NEXT(curtlevel
);
586 if (curqlevel
->low
== curqlevel
->high
)
588 sprintf(ptr
, "*{%d}", curqlevel
->low
);
590 else if (curqlevel
->low
== 0)
592 if (curqlevel
->high
== 0xffff)
598 sprintf(ptr
, "*{,%d}", curqlevel
->high
);
600 else if (curqlevel
->high
== 0xffff)
602 sprintf(ptr
, "*{%d,}", curqlevel
->low
);
605 sprintf(ptr
, "*{%d,%d}", curqlevel
->low
, curqlevel
->high
);
606 ptr
= strchr(ptr
, '\0');
609 curqlevel
= LQL_NEXT(curqlevel
);
613 PG_FREE_IF_COPY(in
, 0);
615 PG_RETURN_POINTER(buf
);