PolarDB-for-PostgreSQL
638 строк · 13.7 Кб
1/*
2* in/out function for ltree and lquery
3* Teodor Sigaev <teodor@stack.net>
4* contrib/ltree/ltree_io.c
5*/
6#include "postgres.h"7
8#include <ctype.h>9
10#include "ltree.h"11#include "utils/memutils.h"12#include "crc32.h"13
14PG_FUNCTION_INFO_V1(ltree_in);15PG_FUNCTION_INFO_V1(ltree_out);16PG_FUNCTION_INFO_V1(lquery_in);17PG_FUNCTION_INFO_V1(lquery_out);18
19
20#define UNCHAR ereport(ERROR, \21(errcode(ERRCODE_SYNTAX_ERROR), \22errmsg("syntax error at position %d", \23pos)));24
25
26typedef struct27{
28char *start;29int len; /* length in bytes */30int flag;31int wlen; /* length in characters */32} nodeitem;33
34#define LTPRS_WAITNAME 035#define LTPRS_WAITDELIM 136
37Datum
38ltree_in(PG_FUNCTION_ARGS)39{
40char *buf = (char *) PG_GETARG_POINTER(0);41char *ptr;42nodeitem *list,43*lptr;44int num = 0,45totallen = 0;46int state = LTPRS_WAITNAME;47ltree *result;48ltree_level *curlevel;49int charlen;50int pos = 0;51
52ptr = buf;53while (*ptr)54{55charlen = pg_mblen(ptr);56if (charlen == 1 && t_iseq(ptr, '.'))57num++;58ptr += charlen;59}60
61if (num + 1 > LTREE_MAX_LEVELS)62ereport(ERROR,63(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),64errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",65num + 1, LTREE_MAX_LEVELS)));66list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));67ptr = buf;68while (*ptr)69{70charlen = pg_mblen(ptr);71
72if (state == LTPRS_WAITNAME)73{74if (ISALNUM(ptr))75{76lptr->start = ptr;77lptr->wlen = 0;78state = LTPRS_WAITDELIM;79}80else81UNCHAR;82}83else if (state == LTPRS_WAITDELIM)84{85if (charlen == 1 && t_iseq(ptr, '.'))86{87lptr->len = ptr - lptr->start;88if (lptr->wlen > 255)89ereport(ERROR,90(errcode(ERRCODE_NAME_TOO_LONG),91errmsg("name of level is too long"),92errdetail("Name length is %d, must "93"be < 256, in position %d.",94lptr->wlen, pos)));95
96totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);97lptr++;98state = LTPRS_WAITNAME;99}100else if (!ISALNUM(ptr))101UNCHAR;102}103else104/* internal error */105elog(ERROR, "internal error in parser");106
107ptr += charlen;108lptr->wlen++;109pos++;110}111
112if (state == LTPRS_WAITDELIM)113{114lptr->len = ptr - lptr->start;115if (lptr->wlen > 255)116ereport(ERROR,117(errcode(ERRCODE_NAME_TOO_LONG),118errmsg("name of level is too long"),119errdetail("Name length is %d, must "120"be < 256, in position %d.",121lptr->wlen, pos)));122
123totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);124lptr++;125}126else if (!(state == LTPRS_WAITNAME && lptr == list))127ereport(ERROR,128(errcode(ERRCODE_SYNTAX_ERROR),129errmsg("syntax error"),130errdetail("Unexpected end of line.")));131
132result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);133SET_VARSIZE(result, LTREE_HDRSIZE + totallen);134result->numlevel = lptr - list;135curlevel = LTREE_FIRST(result);136lptr = list;137while (lptr - list < result->numlevel)138{139curlevel->len = (uint16) lptr->len;140memcpy(curlevel->name, lptr->start, lptr->len);141curlevel = LEVEL_NEXT(curlevel);142lptr++;143}144
145pfree(list);146PG_RETURN_POINTER(result);147}
148
149Datum
150ltree_out(PG_FUNCTION_ARGS)151{
152ltree *in = PG_GETARG_LTREE_P(0);153char *buf,154*ptr;155int i;156ltree_level *curlevel;157
158ptr = buf = (char *) palloc(VARSIZE(in));159curlevel = LTREE_FIRST(in);160for (i = 0; i < in->numlevel; i++)161{162if (i != 0)163{164*ptr = '.';165ptr++;166}167memcpy(ptr, curlevel->name, curlevel->len);168ptr += curlevel->len;169curlevel = LEVEL_NEXT(curlevel);170}171
172*ptr = '\0';173PG_FREE_IF_COPY(in, 0);174
175PG_RETURN_POINTER(buf);176}
177
178#define LQPRS_WAITLEVEL 0179#define LQPRS_WAITDELIM 1180#define LQPRS_WAITOPEN 2181#define LQPRS_WAITFNUM 3182#define LQPRS_WAITSNUM 4183#define LQPRS_WAITND 5184#define LQPRS_WAITCLOSE 6185#define LQPRS_WAITEND 7186#define LQPRS_WAITVAR 8187
188
189#define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )190#define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))191#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )192
193Datum
194lquery_in(PG_FUNCTION_ARGS)195{
196char *buf = (char *) PG_GETARG_POINTER(0);197char *ptr;198int num = 0,199totallen = 0,200numOR = 0;201int state = LQPRS_WAITLEVEL;202lquery *result;203nodeitem *lptr = NULL;204lquery_level *cur,205*curqlevel,206*tmpql;207lquery_variant *lrptr = NULL;208bool hasnot = false;209bool wasbad = false;210int charlen;211int pos = 0;212
213ptr = buf;214while (*ptr)215{216charlen = pg_mblen(ptr);217
218if (charlen == 1)219{220if (t_iseq(ptr, '.'))221num++;222else if (t_iseq(ptr, '|'))223numOR++;224}225
226ptr += charlen;227}228
229num++;230if (num > LQUERY_MAX_LEVELS)231ereport(ERROR,232(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),233errmsg("number of lquery levels (%d) exceeds the maximum allowed (%d)",234num, LQUERY_MAX_LEVELS)));235curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);236ptr = buf;237while (*ptr)238{239charlen = pg_mblen(ptr);240
241if (state == LQPRS_WAITLEVEL)242{243if (ISALNUM(ptr))244{245GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));246lptr->start = ptr;247state = LQPRS_WAITDELIM;248curqlevel->numvar = 1;249}250else if (charlen == 1 && t_iseq(ptr, '!'))251{252GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));253lptr->start = ptr + 1;254state = LQPRS_WAITDELIM;255curqlevel->numvar = 1;256curqlevel->flag |= LQL_NOT;257hasnot = true;258}259else if (charlen == 1 && t_iseq(ptr, '*'))260state = LQPRS_WAITOPEN;261else262UNCHAR;263}264else if (state == LQPRS_WAITVAR)265{266if (ISALNUM(ptr))267{268lptr++;269lptr->start = ptr;270state = LQPRS_WAITDELIM;271curqlevel->numvar++;272}273else274UNCHAR;275}276else if (state == LQPRS_WAITDELIM)277{278if (charlen == 1 && t_iseq(ptr, '@'))279{280if (lptr->start == ptr)281UNCHAR;282lptr->flag |= LVAR_INCASE;283curqlevel->flag |= LVAR_INCASE;284}285else if (charlen == 1 && t_iseq(ptr, '*'))286{287if (lptr->start == ptr)288UNCHAR;289lptr->flag |= LVAR_ANYEND;290curqlevel->flag |= LVAR_ANYEND;291}292else if (charlen == 1 && t_iseq(ptr, '%'))293{294if (lptr->start == ptr)295UNCHAR;296lptr->flag |= LVAR_SUBLEXEME;297curqlevel->flag |= LVAR_SUBLEXEME;298}299else if (charlen == 1 && t_iseq(ptr, '|'))300{301lptr->len = ptr - lptr->start -302((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -303((lptr->flag & LVAR_INCASE) ? 1 : 0) -304((lptr->flag & LVAR_ANYEND) ? 1 : 0);305if (lptr->wlen > 255)306ereport(ERROR,307(errcode(ERRCODE_NAME_TOO_LONG),308errmsg("name of level is too long"),309errdetail("Name length is %d, must "310"be < 256, in position %d.",311lptr->wlen, pos)));312
313state = LQPRS_WAITVAR;314}315else if (charlen == 1 && t_iseq(ptr, '.'))316{317lptr->len = ptr - lptr->start -318((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -319((lptr->flag & LVAR_INCASE) ? 1 : 0) -320((lptr->flag & LVAR_ANYEND) ? 1 : 0);321if (lptr->wlen > 255)322ereport(ERROR,323(errcode(ERRCODE_NAME_TOO_LONG),324errmsg("name of level is too long"),325errdetail("Name length is %d, must "326"be < 256, in position %d.",327lptr->wlen, pos)));328
329state = LQPRS_WAITLEVEL;330curqlevel = NEXTLEV(curqlevel);331}332else if (ISALNUM(ptr))333{334if (lptr->flag)335UNCHAR;336}337else338UNCHAR;339}340else if (state == LQPRS_WAITOPEN)341{342if (charlen == 1 && t_iseq(ptr, '{'))343state = LQPRS_WAITFNUM;344else if (charlen == 1 && t_iseq(ptr, '.'))345{346curqlevel->low = 0;347curqlevel->high = LTREE_MAX_LEVELS;348curqlevel = NEXTLEV(curqlevel);349state = LQPRS_WAITLEVEL;350}351else352UNCHAR;353}354else if (state == LQPRS_WAITFNUM)355{356if (charlen == 1 && t_iseq(ptr, ','))357state = LQPRS_WAITSNUM;358else if (t_isdigit(ptr))359{360int low = atoi(ptr);361
362if (low < 0 || low > LTREE_MAX_LEVELS)363ereport(ERROR,364(errcode(ERRCODE_SYNTAX_ERROR),365errmsg("lquery syntax error"),366errdetail("Low limit (%d) exceeds the maximum allowed (%d).",367low, LTREE_MAX_LEVELS)));368
369curqlevel->low = (uint16) low;370state = LQPRS_WAITND;371}372else373UNCHAR;374}375else if (state == LQPRS_WAITSNUM)376{377if (t_isdigit(ptr))378{379int high = atoi(ptr);380
381if (high < 0 || high > LTREE_MAX_LEVELS)382ereport(ERROR,383(errcode(ERRCODE_SYNTAX_ERROR),384errmsg("lquery syntax error"),385errdetail("High limit (%d) exceeds the maximum allowed (%d).",386high, LTREE_MAX_LEVELS)));387
388curqlevel->high = (uint16) high;389state = LQPRS_WAITCLOSE;390}391else if (charlen == 1 && t_iseq(ptr, '}'))392{393curqlevel->high = LTREE_MAX_LEVELS;394state = LQPRS_WAITEND;395}396else397UNCHAR;398}399else if (state == LQPRS_WAITCLOSE)400{401if (charlen == 1 && t_iseq(ptr, '}'))402state = LQPRS_WAITEND;403else if (!t_isdigit(ptr))404UNCHAR;405}406else if (state == LQPRS_WAITND)407{408if (charlen == 1 && t_iseq(ptr, '}'))409{410curqlevel->high = curqlevel->low;411state = LQPRS_WAITEND;412}413else if (charlen == 1 && t_iseq(ptr, ','))414state = LQPRS_WAITSNUM;415else if (!t_isdigit(ptr))416UNCHAR;417}418else if (state == LQPRS_WAITEND)419{420if (charlen == 1 && t_iseq(ptr, '.'))421{422state = LQPRS_WAITLEVEL;423curqlevel = NEXTLEV(curqlevel);424}425else426UNCHAR;427}428else429/* internal error */430elog(ERROR, "internal error in parser");431
432ptr += charlen;433if (state == LQPRS_WAITDELIM)434lptr->wlen++;435pos++;436}437
438if (state == LQPRS_WAITDELIM)439{440if (lptr->start == ptr)441ereport(ERROR,442(errcode(ERRCODE_SYNTAX_ERROR),443errmsg("lquery syntax error"),444errdetail("Unexpected end of line.")));445
446lptr->len = ptr - lptr->start -447((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -448((lptr->flag & LVAR_INCASE) ? 1 : 0) -449((lptr->flag & LVAR_ANYEND) ? 1 : 0);450if (lptr->len == 0)451ereport(ERROR,452(errcode(ERRCODE_SYNTAX_ERROR),453errmsg("lquery syntax error"),454errdetail("Unexpected end of line.")));455
456if (lptr->wlen > 255)457ereport(ERROR,458(errcode(ERRCODE_NAME_TOO_LONG),459errmsg("name of level is too long"),460errdetail("Name length is %d, must "461"be < 256, in position %d.",462lptr->wlen, pos)));463}464else if (state == LQPRS_WAITOPEN)465curqlevel->high = LTREE_MAX_LEVELS;466else if (state != LQPRS_WAITEND)467ereport(ERROR,468(errcode(ERRCODE_SYNTAX_ERROR),469errmsg("lquery syntax error"),470errdetail("Unexpected end of line.")));471
472curqlevel = tmpql;473totallen = LQUERY_HDRSIZE;474while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)475{476totallen += LQL_HDRSIZE;477if (curqlevel->numvar)478{479lptr = GETVAR(curqlevel);480while (lptr - GETVAR(curqlevel) < curqlevel->numvar)481{482totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);483lptr++;484}485}486else if (curqlevel->low > curqlevel->high)487ereport(ERROR,488(errcode(ERRCODE_SYNTAX_ERROR),489errmsg("lquery syntax error"),490errdetail("Low limit (%d) is greater than upper (%d).",491curqlevel->low, curqlevel->high)));492
493curqlevel = NEXTLEV(curqlevel);494}495
496result = (lquery *) palloc0(totallen);497SET_VARSIZE(result, totallen);498result->numlevel = num;499result->firstgood = 0;500result->flag = 0;501if (hasnot)502result->flag |= LQUERY_HASNOT;503cur = LQUERY_FIRST(result);504curqlevel = tmpql;505while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)506{507memcpy(cur, curqlevel, LQL_HDRSIZE);508cur->totallen = LQL_HDRSIZE;509if (curqlevel->numvar)510{511lrptr = LQL_FIRST(cur);512lptr = GETVAR(curqlevel);513while (lptr - GETVAR(curqlevel) < curqlevel->numvar)514{515cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);516lrptr->len = lptr->len;517lrptr->flag = lptr->flag;518lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);519memcpy(lrptr->name, lptr->start, lptr->len);520lptr++;521lrptr = LVAR_NEXT(lrptr);522}523pfree(GETVAR(curqlevel));524if (cur->numvar > 1 || cur->flag != 0)525wasbad = true;526else if (wasbad == false)527(result->firstgood)++;528}529else530wasbad = true;531curqlevel = NEXTLEV(curqlevel);532cur = LQL_NEXT(cur);533}534
535pfree(tmpql);536PG_RETURN_POINTER(result);537}
538
539Datum
540lquery_out(PG_FUNCTION_ARGS)541{
542lquery *in = PG_GETARG_LQUERY_P(0);543char *buf,544*ptr;545int i,546j,547totallen = 1;548lquery_level *curqlevel;549lquery_variant *curtlevel;550
551curqlevel = LQUERY_FIRST(in);552for (i = 0; i < in->numlevel; i++)553{554totallen++;555if (curqlevel->numvar)556totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;557else558totallen += 2 * 11 + 4;559curqlevel = LQL_NEXT(curqlevel);560}561
562ptr = buf = (char *) palloc(totallen);563curqlevel = LQUERY_FIRST(in);564for (i = 0; i < in->numlevel; i++)565{566if (i != 0)567{568*ptr = '.';569ptr++;570}571if (curqlevel->numvar)572{573if (curqlevel->flag & LQL_NOT)574{575*ptr = '!';576ptr++;577}578curtlevel = LQL_FIRST(curqlevel);579for (j = 0; j < curqlevel->numvar; j++)580{581if (j != 0)582{583*ptr = '|';584ptr++;585}586memcpy(ptr, curtlevel->name, curtlevel->len);587ptr += curtlevel->len;588if ((curtlevel->flag & LVAR_SUBLEXEME))589{590*ptr = '%';591ptr++;592}593if ((curtlevel->flag & LVAR_INCASE))594{595*ptr = '@';596ptr++;597}598if ((curtlevel->flag & LVAR_ANYEND))599{600*ptr = '*';601ptr++;602}603curtlevel = LVAR_NEXT(curtlevel);604}605}606else607{608if (curqlevel->low == curqlevel->high)609{610sprintf(ptr, "*{%d}", curqlevel->low);611}612else if (curqlevel->low == 0)613{614if (curqlevel->high == LTREE_MAX_LEVELS)615{616*ptr = '*';617*(ptr + 1) = '\0';618}619else620sprintf(ptr, "*{,%d}", curqlevel->high);621}622else if (curqlevel->high == LTREE_MAX_LEVELS)623{624sprintf(ptr, "*{%d,}", curqlevel->low);625}626else627sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);628ptr = strchr(ptr, '\0');629}630
631curqlevel = LQL_NEXT(curqlevel);632}633
634*ptr = '\0';635PG_FREE_IF_COPY(in, 0);636
637PG_RETURN_POINTER(buf);638}
639