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);
12 PG_FUNCTION_INFO_V1(ltree_out);
13 Datum ltree_out(PG_FUNCTION_ARGS);
15 PG_FUNCTION_INFO_V1(lquery_in);
16 Datum lquery_in(PG_FUNCTION_ARGS);
17 PG_FUNCTION_INFO_V1(lquery_out);
18 Datum lquery_out(PG_FUNCTION_ARGS);
21 #define UNCHAR elog(ERROR,"Syntax error in position %d near '%c'", (int)(ptr-buf), *ptr)
29 #define LTPRS_WAITNAME 0
30 #define LTPRS_WAITDELIM 1
33 ltree_in(PG_FUNCTION_ARGS) {
34 char *buf = (char *) PG_GETARG_POINTER(0);
36 nodeitem *list, *lptr;
37 int num=0, totallen = 0;
38 int state = LTPRS_WAITNAME;
40 ltree_level *curlevel;
49 list = lptr = (nodeitem*) palloc( sizeof(nodeitem)*(num+1) );
52 if ( state == LTPRS_WAITNAME ) {
53 if ( ISALNUM(*ptr) ) {
55 state = LTPRS_WAITDELIM;
58 } else if ( state == LTPRS_WAITDELIM ) {
60 lptr->len = ptr - lptr->start;
61 if ( lptr->len > 255 )
62 elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
63 lptr->len, (int)(lptr->start - buf));
64 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
66 state = LTPRS_WAITNAME;
67 } else if ( !ISALNUM(*ptr) )
70 elog(ERROR,"Inner error in parser");
74 if ( state == LTPRS_WAITDELIM ) {
75 lptr->len = ptr - lptr->start;
76 if ( lptr->len > 255 )
77 elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
78 lptr->len, (int)(lptr->start - buf));
79 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
81 } else if ( ! (state == LTPRS_WAITNAME && lptr == list) )
82 elog(ERROR,"Unexpected end of line");
84 result = (ltree*)palloc( LTREE_HDRSIZE + totallen );
85 result->len = LTREE_HDRSIZE + totallen;
86 result->numlevel = lptr-list;
87 curlevel = LTREE_FIRST(result);
89 while( lptr-list < result->numlevel ) {
90 curlevel->len = (uint8) lptr->len;
91 memcpy( curlevel->name, lptr->start, lptr->len);
92 curlevel = LEVEL_NEXT(curlevel);
97 PG_RETURN_POINTER(result);
101 ltree_out(PG_FUNCTION_ARGS) {
102 ltree *in = PG_GETARG_LTREE(0);
105 ltree_level *curlevel;
107 ptr = buf = (char*)palloc( in->len );
108 curlevel = LTREE_FIRST(in);
109 for(i=0;i<in->numlevel;i++) {
114 memcpy( ptr, curlevel->name, curlevel->len );
116 curlevel = LEVEL_NEXT(curlevel);
120 PG_FREE_IF_COPY(in,0);
122 PG_RETURN_POINTER(buf);
125 #define LQPRS_WAITLEVEL 0
126 #define LQPRS_WAITDELIM 1
127 #define LQPRS_WAITOPEN 2
128 #define LQPRS_WAITFNUM 3
129 #define LQPRS_WAITSNUM 4
130 #define LQPRS_WAITND 5
131 #define LQPRS_WAITCLOSE 6
132 #define LQPRS_WAITEND 7
133 #define LQPRS_WAITVAR 8
136 #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
137 #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
138 #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
141 lquery_in(PG_FUNCTION_ARGS) {
142 char *buf = (char *) PG_GETARG_POINTER(0);
144 int num=0, totallen = 0, numOR=0;
145 int state = LQPRS_WAITLEVEL;
148 lquery_level *cur,*curqlevel, *tmpql;
149 lquery_variant *lrptr=NULL;
157 else if ( *ptr == '|' )
163 curqlevel = tmpql = (lquery_level*) palloc( ITEMSIZE*num );
164 memset((void*)tmpql,0, ITEMSIZE*num );
167 if ( state==LQPRS_WAITLEVEL ) {
168 if ( ISALNUM(*ptr) ) {
169 GETVAR(curqlevel) = lptr = (nodeitem*)palloc( sizeof(nodeitem)*(numOR+1) );
170 memset((void*)GETVAR(curqlevel), 0,sizeof(nodeitem)*(numOR+1) );
172 state = LQPRS_WAITDELIM;
173 curqlevel->numvar = 1;
174 } else if ( *ptr == '!' ) {
175 GETVAR(curqlevel) = lptr = (nodeitem*)palloc( sizeof(nodeitem)*(numOR+1) );
176 memset((void*)GETVAR(curqlevel), 0,sizeof(nodeitem)*(numOR+1) );
178 state = LQPRS_WAITDELIM;
179 curqlevel->numvar = 1;
180 curqlevel->flag |= LQL_NOT;
182 } else if ( *ptr == '*' ) {
183 state = LQPRS_WAITOPEN;
186 } else if ( state==LQPRS_WAITVAR ) {
187 if ( ISALNUM(*ptr) ) {
190 state = LQPRS_WAITDELIM;
194 } else if ( state==LQPRS_WAITDELIM ) {
196 if ( lptr->start == ptr )
198 lptr->flag |= LVAR_INCASE;
199 curqlevel->flag |= LVAR_INCASE;
200 } else if ( *ptr == '*' ) {
201 if ( lptr->start == ptr )
203 lptr->flag |= LVAR_ANYEND;
204 curqlevel->flag |= LVAR_ANYEND;
205 } else if ( *ptr == '%' ) {
206 if ( lptr->start == ptr )
208 lptr->flag |= LVAR_SUBLEXEM;
209 curqlevel->flag |= LVAR_SUBLEXEM;
210 } else if ( *ptr == '|' ) {
211 lptr->len = ptr - lptr->start -
212 ( ( lptr->flag & LVAR_SUBLEXEM ) ? 1 : 0 ) -
213 ( ( lptr->flag & LVAR_INCASE ) ? 1 : 0 ) -
214 ( ( lptr->flag & LVAR_ANYEND ) ? 1 : 0 );
215 if ( lptr->len > 255 )
216 elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
217 lptr->len, (int)(lptr->start - buf));
218 state = LQPRS_WAITVAR;
219 } else if ( *ptr == '.' ) {
220 lptr->len = ptr - lptr->start -
221 ( ( lptr->flag & LVAR_SUBLEXEM ) ? 1 : 0 ) -
222 ( ( lptr->flag & LVAR_INCASE ) ? 1 : 0 ) -
223 ( ( lptr->flag & LVAR_ANYEND ) ? 1 : 0 );
224 if ( lptr->len > 255 )
225 elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
226 lptr->len, (int)(lptr->start - buf));
227 state = LQPRS_WAITLEVEL;
228 curqlevel = NEXTLEV(curqlevel);
229 } else if ( ISALNUM(*ptr) ) {
234 } else if ( state == LQPRS_WAITOPEN ) {
236 state = LQPRS_WAITFNUM;
237 } else if ( *ptr == '.' ) {
239 curqlevel->high=0xffff;
240 curqlevel = NEXTLEV(curqlevel);
241 state = LQPRS_WAITLEVEL;
244 } else if ( state == LQPRS_WAITFNUM ) {
246 state = LQPRS_WAITSNUM;
247 } else if ( isdigit((unsigned int)*ptr) ) {
248 curqlevel->low = atoi( ptr );
249 state = LQPRS_WAITND;
252 } else if ( state == LQPRS_WAITSNUM ) {
253 if ( isdigit((unsigned int)*ptr) ) {
254 curqlevel->high = atoi( ptr );
255 state = LQPRS_WAITCLOSE;
256 } else if ( *ptr == '}' ) {
257 curqlevel->high = 0xffff;
258 state = LQPRS_WAITEND;
261 } else if ( state == LQPRS_WAITCLOSE ) {
263 state = LQPRS_WAITEND;
264 else if ( !isdigit((unsigned int)*ptr) )
266 } else if ( state == LQPRS_WAITND ) {
268 curqlevel->high = curqlevel->low;
269 state = LQPRS_WAITEND;
270 } else if ( *ptr == ',' )
271 state = LQPRS_WAITSNUM;
272 else if ( !isdigit((unsigned int)*ptr) )
274 } else if ( state == LQPRS_WAITEND ) {
276 state = LQPRS_WAITLEVEL;
277 curqlevel = NEXTLEV(curqlevel);
281 elog(ERROR,"Inner error in parser");
285 if ( state==LQPRS_WAITDELIM ) {
286 if ( lptr->start == ptr )
287 elog(ERROR,"Unexpected end of line");
288 lptr->len = ptr - lptr->start -
289 ( ( lptr->flag & LVAR_SUBLEXEM ) ? 1 : 0 ) -
290 ( ( lptr->flag & LVAR_INCASE ) ? 1 : 0 ) -
291 ( ( lptr->flag & LVAR_ANYEND ) ? 1 : 0 );
293 elog(ERROR,"Unexpected end of line");
294 if ( lptr->len > 255 )
295 elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
296 lptr->len, (int)(lptr->start - buf));
297 } else if ( state == LQPRS_WAITOPEN ) {
298 curqlevel->high = 0xffff;
299 } else if ( state != LQPRS_WAITEND )
300 elog(ERROR,"Unexpected end of line");
303 totallen = LQUERY_HDRSIZE;
304 while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
305 totallen += LQL_HDRSIZE;
306 if ( curqlevel->numvar ) {
307 lptr = GETVAR(curqlevel);
308 while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
309 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
312 } else if ( curqlevel->low > curqlevel->high )
313 elog(ERROR,"Low limit(%d) is greater than upper(%d)",curqlevel->low,curqlevel->high );
314 curqlevel = NEXTLEV(curqlevel);
317 result = (lquery*)palloc( totallen );
318 result->len = totallen;
319 result->numlevel = num;
320 result->firstgood = 0;
323 result->flag |= LQUERY_HASNOT;
324 cur = LQUERY_FIRST(result);
326 while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
327 memcpy(cur,curqlevel,LQL_HDRSIZE);
328 cur->totallen=LQL_HDRSIZE;
329 if ( curqlevel->numvar ) {
330 lrptr = LQL_FIRST(cur);
331 lptr = GETVAR(curqlevel);
332 while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
333 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
334 lrptr->len = lptr->len;
335 lrptr->flag = lptr->flag;
336 lrptr->val = ltree_crc32_sz((uint8 *) lptr->start, lptr->len);
337 memcpy( lrptr->name, lptr->start, lptr->len);
339 lrptr = LVAR_NEXT( lrptr );
341 pfree( GETVAR(curqlevel) );
342 if ( cur->numvar > 1 || cur->flag != 0 )
344 else if ( wasbad==false )
345 (result->firstgood)++;
348 curqlevel = NEXTLEV(curqlevel);
353 PG_RETURN_POINTER(result);
357 lquery_out(PG_FUNCTION_ARGS) {
358 lquery *in = PG_GETARG_LQUERY(0);
361 lquery_level *curqlevel;
362 lquery_variant *curtlevel;
364 curqlevel = LQUERY_FIRST(in);
365 for(i=0;i<in->numlevel;i++) {
366 if ( curqlevel->numvar )
367 totallen = (curqlevel->numvar*4) + 1 + curqlevel->totallen;
371 curqlevel = LQL_NEXT(curqlevel);
375 ptr = buf = (char*)palloc( totallen );
376 curqlevel = LQUERY_FIRST(in);
377 for(i=0;i<in->numlevel;i++) {
382 if ( curqlevel->numvar ) {
383 if ( curqlevel->flag & LQL_NOT ) {
387 curtlevel = LQL_FIRST(curqlevel);
388 for(j=0;j<curqlevel->numvar;j++) {
393 memcpy( ptr, curtlevel->name, curtlevel->len );
395 if ( (curtlevel->flag & LVAR_SUBLEXEM) ) {
399 if ( (curtlevel->flag & LVAR_INCASE) ) {
403 if ( (curtlevel->flag & LVAR_ANYEND) ) {
407 curtlevel = LVAR_NEXT(curtlevel);
410 if ( curqlevel->low == curqlevel->high ) {
411 sprintf(ptr,"*{%d}",curqlevel->low);
412 } else if ( curqlevel->low == 0 ) {
413 if ( curqlevel->high == 0xffff ) {
417 sprintf(ptr,"*{,%d}",curqlevel->high);
418 } else if ( curqlevel->high == 0xffff ) {
419 sprintf(ptr,"*{%d,}",curqlevel->low);
421 sprintf(ptr,"*{%d,%d}", curqlevel->low, curqlevel->high);
422 ptr = strchr(ptr,'\0');
425 curqlevel = LQL_NEXT(curqlevel);
429 PG_FREE_IF_COPY(in,0);
431 PG_RETURN_POINTER(buf);