00001
00002
00003
00004
00005
00006 #include "postgres.h"
00007
00008 #include <ctype.h>
00009
00010 #include "ltree.h"
00011 #include "crc32.h"
00012
00013 PG_FUNCTION_INFO_V1(ltree_in);
00014 Datum ltree_in(PG_FUNCTION_ARGS);
00015
00016 PG_FUNCTION_INFO_V1(ltree_out);
00017 Datum ltree_out(PG_FUNCTION_ARGS);
00018
00019 PG_FUNCTION_INFO_V1(lquery_in);
00020 Datum lquery_in(PG_FUNCTION_ARGS);
00021
00022 PG_FUNCTION_INFO_V1(lquery_out);
00023 Datum lquery_out(PG_FUNCTION_ARGS);
00024
00025
00026 #define UNCHAR ereport(ERROR, \
00027 (errcode(ERRCODE_SYNTAX_ERROR), \
00028 errmsg("syntax error at position %d", \
00029 pos)));
00030
00031
00032 typedef struct
00033 {
00034 char *start;
00035 int len;
00036 int flag;
00037 int wlen;
00038 } nodeitem;
00039
00040 #define LTPRS_WAITNAME 0
00041 #define LTPRS_WAITDELIM 1
00042
00043 Datum
00044 ltree_in(PG_FUNCTION_ARGS)
00045 {
00046 char *buf = (char *) PG_GETARG_POINTER(0);
00047 char *ptr;
00048 nodeitem *list,
00049 *lptr;
00050 int num = 0,
00051 totallen = 0;
00052 int state = LTPRS_WAITNAME;
00053 ltree *result;
00054 ltree_level *curlevel;
00055 int charlen;
00056 int pos = 0;
00057
00058 ptr = buf;
00059 while (*ptr)
00060 {
00061 charlen = pg_mblen(ptr);
00062 if (charlen == 1 && t_iseq(ptr, '.'))
00063 num++;
00064 ptr += charlen;
00065 }
00066
00067 list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
00068 ptr = buf;
00069 while (*ptr)
00070 {
00071 charlen = pg_mblen(ptr);
00072
00073 if (state == LTPRS_WAITNAME)
00074 {
00075 if (ISALNUM(ptr))
00076 {
00077 lptr->start = ptr;
00078 lptr->wlen = 0;
00079 state = LTPRS_WAITDELIM;
00080 }
00081 else
00082 UNCHAR;
00083 }
00084 else if (state == LTPRS_WAITDELIM)
00085 {
00086 if (charlen == 1 && t_iseq(ptr, '.'))
00087 {
00088 lptr->len = ptr - lptr->start;
00089 if (lptr->wlen > 255)
00090 ereport(ERROR,
00091 (errcode(ERRCODE_NAME_TOO_LONG),
00092 errmsg("name of level is too long"),
00093 errdetail("Name length is %d, must "
00094 "be < 256, in position %d.",
00095 lptr->wlen, pos)));
00096
00097 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
00098 lptr++;
00099 state = LTPRS_WAITNAME;
00100 }
00101 else if (!ISALNUM(ptr))
00102 UNCHAR;
00103 }
00104 else
00105
00106 elog(ERROR, "internal error in parser");
00107
00108 ptr += charlen;
00109 lptr->wlen++;
00110 pos++;
00111 }
00112
00113 if (state == LTPRS_WAITDELIM)
00114 {
00115 lptr->len = ptr - lptr->start;
00116 if (lptr->wlen > 255)
00117 ereport(ERROR,
00118 (errcode(ERRCODE_NAME_TOO_LONG),
00119 errmsg("name of level is too long"),
00120 errdetail("Name length is %d, must "
00121 "be < 256, in position %d.",
00122 lptr->wlen, pos)));
00123
00124 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
00125 lptr++;
00126 }
00127 else if (!(state == LTPRS_WAITNAME && lptr == list))
00128 ereport(ERROR,
00129 (errcode(ERRCODE_SYNTAX_ERROR),
00130 errmsg("syntax error"),
00131 errdetail("Unexpected end of line.")));
00132
00133 result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
00134 SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
00135 result->numlevel = lptr - list;
00136 curlevel = LTREE_FIRST(result);
00137 lptr = list;
00138 while (lptr - list < result->numlevel)
00139 {
00140 curlevel->len = (uint16) lptr->len;
00141 memcpy(curlevel->name, lptr->start, lptr->len);
00142 curlevel = LEVEL_NEXT(curlevel);
00143 lptr++;
00144 }
00145
00146 pfree(list);
00147 PG_RETURN_POINTER(result);
00148 }
00149
00150 Datum
00151 ltree_out(PG_FUNCTION_ARGS)
00152 {
00153 ltree *in = PG_GETARG_LTREE(0);
00154 char *buf,
00155 *ptr;
00156 int i;
00157 ltree_level *curlevel;
00158
00159 ptr = buf = (char *) palloc(VARSIZE(in));
00160 curlevel = LTREE_FIRST(in);
00161 for (i = 0; i < in->numlevel; i++)
00162 {
00163 if (i != 0)
00164 {
00165 *ptr = '.';
00166 ptr++;
00167 }
00168 memcpy(ptr, curlevel->name, curlevel->len);
00169 ptr += curlevel->len;
00170 curlevel = LEVEL_NEXT(curlevel);
00171 }
00172
00173 *ptr = '\0';
00174 PG_FREE_IF_COPY(in, 0);
00175
00176 PG_RETURN_POINTER(buf);
00177 }
00178
00179 #define LQPRS_WAITLEVEL 0
00180 #define LQPRS_WAITDELIM 1
00181 #define LQPRS_WAITOPEN 2
00182 #define LQPRS_WAITFNUM 3
00183 #define LQPRS_WAITSNUM 4
00184 #define LQPRS_WAITND 5
00185 #define LQPRS_WAITCLOSE 6
00186 #define LQPRS_WAITEND 7
00187 #define LQPRS_WAITVAR 8
00188
00189
00190 #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
00191 #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
00192 #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
00193
00194 Datum
00195 lquery_in(PG_FUNCTION_ARGS)
00196 {
00197 char *buf = (char *) PG_GETARG_POINTER(0);
00198 char *ptr;
00199 int num = 0,
00200 totallen = 0,
00201 numOR = 0;
00202 int state = LQPRS_WAITLEVEL;
00203 lquery *result;
00204 nodeitem *lptr = NULL;
00205 lquery_level *cur,
00206 *curqlevel,
00207 *tmpql;
00208 lquery_variant *lrptr = NULL;
00209 bool hasnot = false;
00210 bool wasbad = false;
00211 int charlen;
00212 int pos = 0;
00213
00214 ptr = buf;
00215 while (*ptr)
00216 {
00217 charlen = pg_mblen(ptr);
00218
00219 if (charlen == 1)
00220 {
00221 if (t_iseq(ptr, '.'))
00222 num++;
00223 else if (t_iseq(ptr, '|'))
00224 numOR++;
00225 }
00226
00227 ptr += charlen;
00228 }
00229
00230 num++;
00231 curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
00232 ptr = buf;
00233 while (*ptr)
00234 {
00235 charlen = pg_mblen(ptr);
00236
00237 if (state == LQPRS_WAITLEVEL)
00238 {
00239 if (ISALNUM(ptr))
00240 {
00241 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
00242 lptr->start = ptr;
00243 state = LQPRS_WAITDELIM;
00244 curqlevel->numvar = 1;
00245 }
00246 else if (charlen == 1 && t_iseq(ptr, '!'))
00247 {
00248 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
00249 lptr->start = ptr + 1;
00250 state = LQPRS_WAITDELIM;
00251 curqlevel->numvar = 1;
00252 curqlevel->flag |= LQL_NOT;
00253 hasnot = true;
00254 }
00255 else if (charlen == 1 && t_iseq(ptr, '*'))
00256 state = LQPRS_WAITOPEN;
00257 else
00258 UNCHAR;
00259 }
00260 else if (state == LQPRS_WAITVAR)
00261 {
00262 if (ISALNUM(ptr))
00263 {
00264 lptr++;
00265 lptr->start = ptr;
00266 state = LQPRS_WAITDELIM;
00267 curqlevel->numvar++;
00268 }
00269 else
00270 UNCHAR;
00271 }
00272 else if (state == LQPRS_WAITDELIM)
00273 {
00274 if (charlen == 1 && t_iseq(ptr, '@'))
00275 {
00276 if (lptr->start == ptr)
00277 UNCHAR;
00278 lptr->flag |= LVAR_INCASE;
00279 curqlevel->flag |= LVAR_INCASE;
00280 }
00281 else if (charlen == 1 && t_iseq(ptr, '*'))
00282 {
00283 if (lptr->start == ptr)
00284 UNCHAR;
00285 lptr->flag |= LVAR_ANYEND;
00286 curqlevel->flag |= LVAR_ANYEND;
00287 }
00288 else if (charlen == 1 && t_iseq(ptr, '%'))
00289 {
00290 if (lptr->start == ptr)
00291 UNCHAR;
00292 lptr->flag |= LVAR_SUBLEXEME;
00293 curqlevel->flag |= LVAR_SUBLEXEME;
00294 }
00295 else if (charlen == 1 && t_iseq(ptr, '|'))
00296 {
00297 lptr->len = ptr - lptr->start -
00298 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
00299 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
00300 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
00301 if (lptr->wlen > 255)
00302 ereport(ERROR,
00303 (errcode(ERRCODE_NAME_TOO_LONG),
00304 errmsg("name of level is too long"),
00305 errdetail("Name length is %d, must "
00306 "be < 256, in position %d.",
00307 lptr->wlen, pos)));
00308
00309 state = LQPRS_WAITVAR;
00310 }
00311 else if (charlen == 1 && t_iseq(ptr, '.'))
00312 {
00313 lptr->len = ptr - lptr->start -
00314 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
00315 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
00316 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
00317 if (lptr->wlen > 255)
00318 ereport(ERROR,
00319 (errcode(ERRCODE_NAME_TOO_LONG),
00320 errmsg("name of level is too long"),
00321 errdetail("Name length is %d, must "
00322 "be < 256, in position %d.",
00323 lptr->wlen, pos)));
00324
00325 state = LQPRS_WAITLEVEL;
00326 curqlevel = NEXTLEV(curqlevel);
00327 }
00328 else if (ISALNUM(ptr))
00329 {
00330 if (lptr->flag)
00331 UNCHAR;
00332 }
00333 else
00334 UNCHAR;
00335 }
00336 else if (state == LQPRS_WAITOPEN)
00337 {
00338 if (charlen == 1 && t_iseq(ptr, '{'))
00339 state = LQPRS_WAITFNUM;
00340 else if (charlen == 1 && t_iseq(ptr, '.'))
00341 {
00342 curqlevel->low = 0;
00343 curqlevel->high = 0xffff;
00344 curqlevel = NEXTLEV(curqlevel);
00345 state = LQPRS_WAITLEVEL;
00346 }
00347 else
00348 UNCHAR;
00349 }
00350 else if (state == LQPRS_WAITFNUM)
00351 {
00352 if (charlen == 1 && t_iseq(ptr, ','))
00353 state = LQPRS_WAITSNUM;
00354 else if (t_isdigit(ptr))
00355 {
00356 curqlevel->low = atoi(ptr);
00357 state = LQPRS_WAITND;
00358 }
00359 else
00360 UNCHAR;
00361 }
00362 else if (state == LQPRS_WAITSNUM)
00363 {
00364 if (t_isdigit(ptr))
00365 {
00366 curqlevel->high = atoi(ptr);
00367 state = LQPRS_WAITCLOSE;
00368 }
00369 else if (charlen == 1 && t_iseq(ptr, '}'))
00370 {
00371 curqlevel->high = 0xffff;
00372 state = LQPRS_WAITEND;
00373 }
00374 else
00375 UNCHAR;
00376 }
00377 else if (state == LQPRS_WAITCLOSE)
00378 {
00379 if (charlen == 1 && t_iseq(ptr, '}'))
00380 state = LQPRS_WAITEND;
00381 else if (!t_isdigit(ptr))
00382 UNCHAR;
00383 }
00384 else if (state == LQPRS_WAITND)
00385 {
00386 if (charlen == 1 && t_iseq(ptr, '}'))
00387 {
00388 curqlevel->high = curqlevel->low;
00389 state = LQPRS_WAITEND;
00390 }
00391 else if (charlen == 1 && t_iseq(ptr, ','))
00392 state = LQPRS_WAITSNUM;
00393 else if (!t_isdigit(ptr))
00394 UNCHAR;
00395 }
00396 else if (state == LQPRS_WAITEND)
00397 {
00398 if (charlen == 1 && t_iseq(ptr, '.'))
00399 {
00400 state = LQPRS_WAITLEVEL;
00401 curqlevel = NEXTLEV(curqlevel);
00402 }
00403 else
00404 UNCHAR;
00405 }
00406 else
00407
00408 elog(ERROR, "internal error in parser");
00409
00410 ptr += charlen;
00411 if (state == LQPRS_WAITDELIM)
00412 lptr->wlen++;
00413 pos++;
00414 }
00415
00416 if (state == LQPRS_WAITDELIM)
00417 {
00418 if (lptr->start == ptr)
00419 ereport(ERROR,
00420 (errcode(ERRCODE_SYNTAX_ERROR),
00421 errmsg("syntax error"),
00422 errdetail("Unexpected end of line.")));
00423
00424 lptr->len = ptr - lptr->start -
00425 ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
00426 ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
00427 ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
00428 if (lptr->len == 0)
00429 ereport(ERROR,
00430 (errcode(ERRCODE_SYNTAX_ERROR),
00431 errmsg("syntax error"),
00432 errdetail("Unexpected end of line.")));
00433
00434 if (lptr->wlen > 255)
00435 ereport(ERROR,
00436 (errcode(ERRCODE_NAME_TOO_LONG),
00437 errmsg("name of level is too long"),
00438 errdetail("Name length is %d, must "
00439 "be < 256, in position %d.",
00440 lptr->wlen, pos)));
00441 }
00442 else if (state == LQPRS_WAITOPEN)
00443 curqlevel->high = 0xffff;
00444 else if (state != LQPRS_WAITEND)
00445 ereport(ERROR,
00446 (errcode(ERRCODE_SYNTAX_ERROR),
00447 errmsg("syntax error"),
00448 errdetail("Unexpected end of line.")));
00449
00450 curqlevel = tmpql;
00451 totallen = LQUERY_HDRSIZE;
00452 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
00453 {
00454 totallen += LQL_HDRSIZE;
00455 if (curqlevel->numvar)
00456 {
00457 lptr = GETVAR(curqlevel);
00458 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
00459 {
00460 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
00461 lptr++;
00462 }
00463 }
00464 else if (curqlevel->low > curqlevel->high)
00465 ereport(ERROR,
00466 (errcode(ERRCODE_SYNTAX_ERROR),
00467 errmsg("syntax error"),
00468 errdetail("Low limit(%d) is greater than upper(%d).",
00469 curqlevel->low, curqlevel->high)));
00470
00471 curqlevel = NEXTLEV(curqlevel);
00472 }
00473
00474 result = (lquery *) palloc0(totallen);
00475 SET_VARSIZE(result, totallen);
00476 result->numlevel = num;
00477 result->firstgood = 0;
00478 result->flag = 0;
00479 if (hasnot)
00480 result->flag |= LQUERY_HASNOT;
00481 cur = LQUERY_FIRST(result);
00482 curqlevel = tmpql;
00483 while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
00484 {
00485 memcpy(cur, curqlevel, LQL_HDRSIZE);
00486 cur->totallen = LQL_HDRSIZE;
00487 if (curqlevel->numvar)
00488 {
00489 lrptr = LQL_FIRST(cur);
00490 lptr = GETVAR(curqlevel);
00491 while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
00492 {
00493 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
00494 lrptr->len = lptr->len;
00495 lrptr->flag = lptr->flag;
00496 lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
00497 memcpy(lrptr->name, lptr->start, lptr->len);
00498 lptr++;
00499 lrptr = LVAR_NEXT(lrptr);
00500 }
00501 pfree(GETVAR(curqlevel));
00502 if (cur->numvar > 1 || cur->flag != 0)
00503 wasbad = true;
00504 else if (wasbad == false)
00505 (result->firstgood)++;
00506 }
00507 else
00508 wasbad = true;
00509 curqlevel = NEXTLEV(curqlevel);
00510 cur = LQL_NEXT(cur);
00511 }
00512
00513 pfree(tmpql);
00514 PG_RETURN_POINTER(result);
00515 }
00516
00517 Datum
00518 lquery_out(PG_FUNCTION_ARGS)
00519 {
00520 lquery *in = PG_GETARG_LQUERY(0);
00521 char *buf,
00522 *ptr;
00523 int i,
00524 j,
00525 totallen = 1;
00526 lquery_level *curqlevel;
00527 lquery_variant *curtlevel;
00528
00529 curqlevel = LQUERY_FIRST(in);
00530 for (i = 0; i < in->numlevel; i++)
00531 {
00532 totallen++;
00533 if (curqlevel->numvar)
00534 totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
00535 else
00536 totallen += 2 * 11 + 4;
00537 curqlevel = LQL_NEXT(curqlevel);
00538 }
00539
00540 ptr = buf = (char *) palloc(totallen);
00541 curqlevel = LQUERY_FIRST(in);
00542 for (i = 0; i < in->numlevel; i++)
00543 {
00544 if (i != 0)
00545 {
00546 *ptr = '.';
00547 ptr++;
00548 }
00549 if (curqlevel->numvar)
00550 {
00551 if (curqlevel->flag & LQL_NOT)
00552 {
00553 *ptr = '!';
00554 ptr++;
00555 }
00556 curtlevel = LQL_FIRST(curqlevel);
00557 for (j = 0; j < curqlevel->numvar; j++)
00558 {
00559 if (j != 0)
00560 {
00561 *ptr = '|';
00562 ptr++;
00563 }
00564 memcpy(ptr, curtlevel->name, curtlevel->len);
00565 ptr += curtlevel->len;
00566 if ((curtlevel->flag & LVAR_SUBLEXEME))
00567 {
00568 *ptr = '%';
00569 ptr++;
00570 }
00571 if ((curtlevel->flag & LVAR_INCASE))
00572 {
00573 *ptr = '@';
00574 ptr++;
00575 }
00576 if ((curtlevel->flag & LVAR_ANYEND))
00577 {
00578 *ptr = '*';
00579 ptr++;
00580 }
00581 curtlevel = LVAR_NEXT(curtlevel);
00582 }
00583 }
00584 else
00585 {
00586 if (curqlevel->low == curqlevel->high)
00587 {
00588 sprintf(ptr, "*{%d}", curqlevel->low);
00589 }
00590 else if (curqlevel->low == 0)
00591 {
00592 if (curqlevel->high == 0xffff)
00593 {
00594 *ptr = '*';
00595 *(ptr + 1) = '\0';
00596 }
00597 else
00598 sprintf(ptr, "*{,%d}", curqlevel->high);
00599 }
00600 else if (curqlevel->high == 0xffff)
00601 {
00602 sprintf(ptr, "*{%d,}", curqlevel->low);
00603 }
00604 else
00605 sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
00606 ptr = strchr(ptr, '\0');
00607 }
00608
00609 curqlevel = LQL_NEXT(curqlevel);
00610 }
00611
00612 *ptr = '\0';
00613 PG_FREE_IF_COPY(in, 0);
00614
00615 PG_RETURN_POINTER(buf);
00616 }