struct TSQueryParserStateData
{ /* Tokenizer used for parsing tsquery */
ts_tokenizer gettoken;
/* State of tokenizer function */ char *buffer; /* entire string we are scanning */ char *buf; /* current scan point */ int count; /* nesting count, incremented by (,
* decremented by ) */
ts_parserstate state;
/* polish (prefix) notation in list, filled in by push* functions */
List *polstr;
/* *Stringsfromoperandsarecollectedinop.curopisapointertothe *endofusedspaceofop.
*/ char *op; char *curop; int lenop; /* allocated size of op */ int sumlen; /* used size of op */
/* state for value's parser */
TSVectorParseState valstate;
/* context object for soft errors - must match valstate's escontext */
Node *escontext;
};
while (*ptr)
{ switch (state)
{ case PHRASE_OPEN: if (t_iseq(ptr, '<'))
{
state = PHRASE_DIST;
ptr++;
} else returnfalse; break;
case PHRASE_DIST: if (t_iseq(ptr, '-'))
{
state = PHRASE_CLOSE;
ptr++; continue;
}
if (!isdigit((unsignedchar) *ptr)) returnfalse;
errno = 0;
l = strtol(ptr, &endptr, 10); if (ptr == endptr) returnfalse; elseif (errno == ERANGE || l < 0 || l > MAXENTRYPOS)
ereturn(pstate->escontext, false,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("distance in phrase operator must be an integer value between zero and %d inclusive",
MAXENTRYPOS))); else
{
state = PHRASE_CLOSE;
ptr = endptr;
} break;
case PHRASE_CLOSE: if (t_iseq(ptr, '>'))
{
state = PHRASE_FINISH;
ptr++;
} else returnfalse; break;
while (true)
{ switch (state->state)
{ case WAITFIRSTOPERAND: case WAITOPERAND: if (t_iseq(state->buf, '-'))
{
state->buf++;
state->state = WAITOPERAND;
*operator = OP_NOT; return PT_OPR;
} elseif (t_iseq(state->buf, '"'))
{ /* Everything in quotes is processed as a single token */
/* iterate to the closing quote or end of the string */ while (*state->buf != '\0' && !t_iseq(state->buf, '"'))
state->buf++;
*lenval = state->buf - *strval;
/* skip closing quote if not end of the string */ if (*state->buf != '\0')
state->buf++;
state->state = WAITOPERATOR;
state->count++; return PT_VAL;
} elseif (ISOPERATOR(state->buf))
{ /* ignore, else gettoken_tsvector() will raise an error */
state->buf++;
state->state = WAITOPERAND; continue;
} elseif (!isspace((unsignedchar) *state->buf))
{ /* *Werelyonthetsvectorparsertoparsethevaluefor *us
*/
reset_tsvector_parser(state->valstate, state->buf); if (gettoken_tsvector(state->valstate, strval, lenval,
NULL, NULL, &state->buf))
{
state->state = WAITOPERATOR; return PT_VAL;
} elseif (SOFT_ERROR_OCCURRED(state->escontext))
{ /* gettoken_tsvector reported a soft error */ return PT_ERR;
} elseif (state->state == WAITFIRSTOPERAND)
{ return PT_END;
} else
{ /* finally, we have to provide an operand */
pushStop(state); return PT_END;
}
} break;
case WAITOPERATOR: if (*state->buf == '\0')
{ return PT_END;
} elseif (parse_or_operator(state))
{
state->state = WAITOPERAND;
*operator = OP_OR; return PT_OPR;
} elseif (ISOPERATOR(state->buf))
{ /* ignore other operators in this state too */
state->buf++; continue;
} elseif (!isspace((unsignedchar) *state->buf))
{ /* insert implicit AND between operands */
state->state = WAITOPERAND;
*operator = OP_AND; return PT_OPR;
} break;
}
tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
tmp->type = QI_OPR;
tmp->oper = oper;
tmp->distance = (oper == OP_PHRASE) ? distance : 0; /* left is filled in later with findoprnd */
state->polstr = lcons(tmp, state->polstr);
}
staticvoid
pushValue_internal(TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
{
QueryOperand *tmp;
if (distance >= MAXSTRPOS)
ereturn(state->escontext,,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("value is too big in tsquery: \"%s\"",
state->buffer))); if (lenval >= MAXSTRLEN)
ereturn(state->escontext,,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("operand is too long in tsquery: \"%s\"",
state->buffer)));
if (lenval >= MAXSTRLEN)
ereturn(state->escontext,,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("word is too long in tsquery: \"%s\"",
state->buffer)));
/* append the value string to state.op, enlarging buffer if needed first */ while (state->curop - state->op + lenval + 1 >= state->lenop)
{ int used = state->curop - state->op;
staticvoid
findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup)
{ /* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
if (*pos >= nnodes)
elog(ERROR, "malformed tsquery: operand not found");
if (ptr[*pos].type == QI_VAL)
{
(*pos)++;
} elseif (ptr[*pos].type == QI_VALSTOP)
{
*needcleanup = true; /* we'll have to remove stop words */
(*pos)++;
} else
{
Assert(ptr[*pos].type == QI_OPR);
/* process the only argument */
findoprnd_recurse(ptr, pos, nnodes, needcleanup);
} else
{
QueryOperator *curitem = &ptr[*pos].qoperator; int tmp = *pos; /* save current position */
if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("tsquery is too large")));
commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
/* Pack the QueryItems in the final TSQuery struct to return to caller */
query = (TSQuery) palloc0(commonlen);
SET_VARSIZE(query, commonlen);
query->size = list_length(state.polstr);
ptr = GETQUERY(query);
/* Copy QueryItems to TSQuery */
i = 0;
foreach(cell, state.polstr)
{
QueryItem *item = (QueryItem *) lfirst(cell);
/* Makes sure inf->buf is large enough for adding 'addsize' bytes */ #define RESIZEBUF(inf, addsize) \ while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
{ \ int len = (inf)->cur - (inf)->buf; \
(inf)->buflen *= 2; \
(inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
(inf)->cur = (inf)->buf + len; \
}
/* *recursivelytraversethetreeand *printitininfix(human-readable)form
*/ staticvoid
infix(INFIX *in, int parentPriority, bool rightPhraseOp)
{ /* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
if (in->curpol->type == QI_VAL)
{
QueryOperand *curpol = &in->curpol->qoperand; char *op = in->op + curpol->distance; int clen;
Datum
tsqueryrecv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
TSQuery query; int i,
len;
QueryItem *item; int datalen; char *ptr;
uint32 size; constchar **operands; bool needcleanup;
size = pq_getmsgint(buf, sizeof(uint32)); if (size > (MaxAllocSize / sizeof(QueryItem)))
elog(ERROR, "invalid size of tsquery");
/* Allocate space to temporarily hold operand strings */
operands = palloc(size * sizeof(char *));
/* Allocate space for all the QueryItems. */
len = HDRSIZETQ + sizeof(QueryItem) * size;
query = (TSQuery) palloc0(len);
query->size = size;
item = GETQUERY(query);
datalen = 0; for (i = 0; i < size; i++)
{
item->type = (int8) pq_getmsgint(buf, sizeof(int8));
if (item->type == QI_VAL)
{
size_t val_len; /* length after recoding to server
* encoding */
uint8 weight;
uint8 prefix; constchar *val;
pg_crc32 valcrc;
/* Enlarge buffer to make room for the operand values. */
query = (TSQuery) repalloc(query, len + datalen);
item = GETQUERY(query);
ptr = GETOPERAND(query);
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.