/* *expectsanullterminatedstring *returnsanlquery
*/ static lquery *
parse_lquery(constchar *buf, struct Node *escontext)
{ constchar *ptr; int num = 0,
totallen = 0,
numOR = 0; int state = LQPRS_WAITLEVEL;
lquery *result;
nodeitem *lptr = NULL;
lquery_level *cur,
*curqlevel,
*tmpql;
lquery_variant *lrptr = NULL; bool hasnot = false; bool wasbad = false; int charlen; int pos = 1; /* character position for error messages */
#define UNCHAR ereturn(escontext, NULL,\
errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("lquery syntax error at character %d", \
pos))
ptr = buf; while (*ptr)
{
charlen = pg_mblen_cstr(ptr);
if (t_iseq(ptr, '.'))
num++; elseif (t_iseq(ptr, '|'))
numOR++;
ptr += charlen;
}
num++; if (num > LQUERY_MAX_LEVELS)
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of lquery items (%d) exceeds the maximum allowed (%d)",
num, LQUERY_MAX_LEVELS)));
curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
ptr = buf; while (*ptr)
{
charlen = pg_mblen_cstr(ptr);
switch (state)
{ case LQPRS_WAITLEVEL: if (ISLABEL(ptr))
{
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
lptr->start = ptr;
state = LQPRS_WAITDELIM;
curqlevel->numvar = 1;
} elseif (t_iseq(ptr, '!'))
{
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
lptr->start = ptr + 1;
lptr->wlen = -1; /* compensate for counting ! below */
state = LQPRS_WAITDELIM;
curqlevel->numvar = 1;
curqlevel->flag |= LQL_NOT;
hasnot = true;
} elseif (t_iseq(ptr, '*'))
state = LQPRS_WAITOPEN; else
UNCHAR; break; case LQPRS_WAITVAR: if (ISLABEL(ptr))
{
lptr++;
lptr->start = ptr;
state = LQPRS_WAITDELIM; if (pg_add_u16_overflow(curqlevel->numvar, 1, &curqlevel->numvar))
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("lquery level has too many variants"),
errdetail("Number of variants exceeds the maximum allowed (%d).",
PG_UINT16_MAX)));
} else
UNCHAR; break; case LQPRS_WAITDELIM: if (t_iseq(ptr, '@'))
{
lptr->flag |= LVAR_INCASE;
curqlevel->flag |= LVAR_INCASE;
} elseif (t_iseq(ptr, '*'))
{
lptr->flag |= LVAR_ANYEND;
curqlevel->flag |= LVAR_ANYEND;
} elseif (t_iseq(ptr, '%'))
{
lptr->flag |= LVAR_SUBLEXEME;
curqlevel->flag |= LVAR_SUBLEXEME;
} elseif (t_iseq(ptr, '|'))
{ if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) return NULL;
state = LQPRS_WAITVAR;
} elseif (t_iseq(ptr, '{'))
{ if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) return NULL;
curqlevel->flag |= LQL_COUNT;
state = LQPRS_WAITFNUM;
} elseif (t_iseq(ptr, '.'))
{ if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) return NULL;
state = LQPRS_WAITLEVEL;
curqlevel = NEXTLEV(curqlevel);
} elseif (ISLABEL(ptr))
{ /* disallow more chars after a flag */ if (lptr->flag)
UNCHAR;
} else
UNCHAR; break; case LQPRS_WAITOPEN: if (t_iseq(ptr, '{'))
state = LQPRS_WAITFNUM; elseif (t_iseq(ptr, '.'))
{ /* We only get here for '*', so these are correct defaults */
curqlevel->low = 0;
curqlevel->high = LTREE_MAX_LEVELS;
curqlevel = NEXTLEV(curqlevel);
state = LQPRS_WAITLEVEL;
} else
UNCHAR; break; case LQPRS_WAITFNUM: if (t_iseq(ptr, ','))
state = LQPRS_WAITSNUM; elseif (isdigit((unsignedchar) *ptr))
{ int low = atoi(ptr);
if (low < 0 || low > LTREE_MAX_LEVELS)
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("lquery syntax error"),
errdetail("Low limit (%d) exceeds the maximum allowed (%d), at character %d.",
low, LTREE_MAX_LEVELS, pos)));
curqlevel->low = (uint16) low;
state = LQPRS_WAITND;
} else
UNCHAR; break; case LQPRS_WAITSNUM: if (isdigit((unsignedchar) *ptr))
{ int high = atoi(ptr);
if (high < 0 || high > LTREE_MAX_LEVELS)
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("lquery syntax error"),
errdetail("High limit (%d) exceeds the maximum allowed (%d), at character %d.",
high, LTREE_MAX_LEVELS, pos))); elseif (curqlevel->low > high)
ereturn(escontext, NULL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("lquery syntax error"),
errdetail("Low limit (%d) is greater than high limit (%d), at character %d.",
curqlevel->low, high, pos)));
curqlevel->high = (uint16) high;
state = LQPRS_WAITCLOSE;
} elseif (t_iseq(ptr, '}'))
{
curqlevel->high = LTREE_MAX_LEVELS;
state = LQPRS_WAITEND;
} else
UNCHAR; break; case LQPRS_WAITCLOSE: if (t_iseq(ptr, '}'))
state = LQPRS_WAITEND; elseif (!isdigit((unsignedchar) *ptr))
UNCHAR; break; case LQPRS_WAITND: if (t_iseq(ptr, '}'))
{
curqlevel->high = curqlevel->low;
state = LQPRS_WAITEND;
} elseif (t_iseq(ptr, ','))
state = LQPRS_WAITSNUM; elseif (!isdigit((unsignedchar) *ptr))
UNCHAR; break; case LQPRS_WAITEND: if (t_iseq(ptr, '.'))
{
state = LQPRS_WAITLEVEL;
curqlevel = NEXTLEV(curqlevel);
} else
UNCHAR; break; default:
elog(ERROR, "internal error in lquery parser");
}
ptr += charlen; if (state == LQPRS_WAITDELIM)
lptr->wlen++;
pos++;
}
if (state == LQPRS_WAITDELIM)
{ if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) return NULL;
} elseif (state == LQPRS_WAITOPEN)
curqlevel->high = LTREE_MAX_LEVELS; elseif (state != LQPRS_WAITEND)
ereturn(escontext, NULL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("lquery syntax error"),
errdetail("Unexpected end of input.")));
result = (lquery *) palloc0(totallen);
SET_VARSIZE(result, totallen);
result->numlevel = num;
result->firstgood = 0;
result->flag = 0; if (hasnot)
result->flag |= LQUERY_HASNOT;
cur = LQUERY_FIRST(result);
curqlevel = tmpql; while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
{
memcpy(cur, curqlevel, LQL_HDRSIZE);
cur->totallen = LQL_HDRSIZE; if (curqlevel->numvar)
{
lrptr = LQL_FIRST(cur);
lptr = GETVAR(curqlevel); while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
{ int newlen = cur->totallen + MAXALIGN(LVAR_HDRSIZE + lptr->len);
if (newlen > PG_UINT16_MAX)
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("lquery level is too large"),
errdetail("Total size of level exceeds the maximum allowed (%d bytes).",
PG_UINT16_MAX)));
cur->totallen = (uint16) newlen;
lrptr->len = lptr->len;
lrptr->flag = lptr->flag;
lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
memcpy(lrptr->name, lptr->start, lptr->len);
lptr++;
lrptr = LVAR_NEXT(lrptr);
}
pfree(GETVAR(curqlevel)); if (cur->numvar > 1 || cur->flag != 0)
{ /* Not a simple match */
wasbad = true;
} elseif (wasbad == false)
{ /* count leading simple matches */
(result->firstgood)++;
}
} else
{ /* '*', so this isn't a simple match */
wasbad = true;
}
curqlevel = NEXTLEV(curqlevel);
cur = LQL_NEXT(cur);
}
/* Now compute the byte length, which we weren't tracking before. */
lptr->len = ptr - lptr->start;
/* Complain if it's empty or too long */ if (lptr->len == 0)
ereturn(escontext, false,
(errcode(ERRCODE_SYNTAX_ERROR),
is_lquery ?
errmsg("lquery syntax error at character %d", pos) :
errmsg("ltree syntax error at character %d", pos),
errdetail("Empty labels are not allowed."))); if (lptr->wlen > LTREE_LABEL_MAX_CHARS)
ereturn(escontext, false,
(errcode(ERRCODE_NAME_TOO_LONG),
errmsg("label string is too long"),
errdetail("Label length is %d, must be at most %d, at character %d.",
lptr->wlen, LTREE_LABEL_MAX_CHARS, pos))); returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.