Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Enumerations | Functions

tsquery.c File Reference

#include "postgres.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_utils.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
Include dependency graph for tsquery.c:

Go to the source code of this file.

Data Structures

struct  TSQueryParserStateData
struct  INFIX

Defines

#define WAITOPERAND   1
#define WAITOPERATOR   2
#define WAITFIRSTOPERAND   3
#define WAITSINGLEOPERAND   4
#define STACKDEPTH   32
#define RESIZEBUF(inf, addsize)

Enumerations

enum  ts_tokentype {
  PT_END = 0, PT_ERR = 1, PT_VAL = 2, PT_OPR = 3,
  PT_OPEN = 4, PT_CLOSE = 5
}

Functions

static char * get_modifiers (char *buf, int16 *weight, bool *prefix)
static ts_tokentype gettoken_query (TSQueryParserState state, int8 *operator, int *lenval, char **strval, int16 *weight, bool *prefix)
void pushOperator (TSQueryParserState state, int8 oper)
static void pushValue_internal (TSQueryParserState state, pg_crc32 valcrc, int distance, int lenval, int weight, bool prefix)
void pushValue (TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
void pushStop (TSQueryParserState state)
static void makepol (TSQueryParserState state, PushFunction pushval, Datum opaque)
static void findoprnd_recurse (QueryItem *ptr, uint32 *pos, int nnodes)
static void findoprnd (QueryItem *ptr, int size)
TSQuery parse_tsquery (char *buf, PushFunction pushval, Datum opaque, bool isplain)
static void pushval_asis (Datum opaque, TSQueryParserState state, char *strval, int lenval, int16 weight, bool prefix)
Datum tsqueryin (PG_FUNCTION_ARGS)
static void infix (INFIX *in, bool first)
Datum tsqueryout (PG_FUNCTION_ARGS)
Datum tsquerysend (PG_FUNCTION_ARGS)
Datum tsqueryrecv (PG_FUNCTION_ARGS)
Datum tsquerytree (PG_FUNCTION_ARGS)

Define Documentation

#define RESIZEBUF (   inf,
  addsize 
)
Value:
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; \
}

Definition at line 588 of file tsquery.c.

Referenced by infix().

#define STACKDEPTH   32

Definition at line 320 of file tsquery.c.

Referenced by makepol().

#define WAITFIRSTOPERAND   3

Definition at line 53 of file tsquery.c.

Referenced by gettoken_query(), and parse_tsquery().

#define WAITOPERAND   1

Definition at line 51 of file tsquery.c.

Referenced by gettoken_query().

#define WAITOPERATOR   2

Definition at line 52 of file tsquery.c.

Referenced by gettoken_query().

#define WAITSINGLEOPERAND   4

Definition at line 54 of file tsquery.c.

Referenced by gettoken_query(), and parse_tsquery().


Enumeration Type Documentation

Enumerator:
PT_END 
PT_ERR 
PT_VAL 
PT_OPR 
PT_OPEN 
PT_CLOSE 

Definition at line 105 of file tsquery.c.

{
    PT_END = 0,
    PT_ERR = 1,
    PT_VAL = 2,
    PT_OPR = 3,
    PT_OPEN = 4,
    PT_CLOSE = 5
} ts_tokentype;


Function Documentation

static void findoprnd ( QueryItem ptr,
int  size 
) [static]

Definition at line 446 of file tsquery.c.

References elog, ERROR, and findoprnd_recurse().

Referenced by parse_tsquery(), and tsqueryrecv().

{
    uint32      pos;

    pos = 0;
    findoprnd_recurse(ptr, &pos, size);

    if (pos != size)
        elog(ERROR, "malformed tsquery: extra nodes");
}

static void findoprnd_recurse ( QueryItem ptr,
uint32 pos,
int  nnodes 
) [static]

Definition at line 401 of file tsquery.c.

References Assert, check_stack_depth(), elog, ERROR, QueryOperator::left, OP_AND, OP_NOT, OP_OR, QueryOperator::oper, QI_OPR, QI_VAL, QI_VALSTOP, and QueryItem::qoperator.

Referenced by findoprnd().

{
    /* 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 ||
        ptr[*pos].type == QI_VALSTOP)   /* need to handle VALSTOP here, they
                                         * haven't been cleaned away yet. */
    {
        (*pos)++;
    }
    else
    {
        Assert(ptr[*pos].type == QI_OPR);

        if (ptr[*pos].qoperator.oper == OP_NOT)
        {
            ptr[*pos].qoperator.left = 1;
            (*pos)++;
            findoprnd_recurse(ptr, pos, nnodes);
        }
        else
        {
            QueryOperator *curitem = &ptr[*pos].qoperator;
            int         tmp = *pos;

            Assert(curitem->oper == OP_AND || curitem->oper == OP_OR);

            (*pos)++;
            findoprnd_recurse(ptr, pos, nnodes);
            curitem->left = *pos - tmp;
            findoprnd_recurse(ptr, pos, nnodes);
        }
    }
}

static char* get_modifiers ( char *  buf,
int16 weight,
bool prefix 
) [static]

Definition at line 61 of file tsquery.c.

References pg_mblen(), and t_iseq.

Referenced by gettoken_query().

{
    *weight = 0;
    *prefix = false;

    if (!t_iseq(buf, ':'))
        return buf;

    buf++;
    while (*buf && pg_mblen(buf) == 1)
    {
        switch (*buf)
        {
            case 'a':
            case 'A':
                *weight |= 1 << 3;
                break;
            case 'b':
            case 'B':
                *weight |= 1 << 2;
                break;
            case 'c':
            case 'C':
                *weight |= 1 << 1;
                break;
            case 'd':
            case 'D':
                *weight |= 1;
                break;
            case '*':
                *prefix = true;
                break;
            default:
                return buf;
        }
        buf++;
    }

    return buf;
}

static ts_tokentype gettoken_query ( TSQueryParserState  state,
int8 operator,
int *  lenval,
char **  strval,
int16 weight,
bool prefix 
) [static]

Definition at line 122 of file tsquery.c.

References TSQueryParserStateData::buf, TSQueryParserStateData::buffer, TSQueryParserStateData::count, ereport, errcode(), errmsg(), ERROR, get_modifiers(), gettoken_tsvector(), NULL, pg_mblen(), PT_END, PT_ERR, reset_tsvector_parser(), TSQueryParserStateData::state, t_iseq, t_isspace, TSQueryParserStateData::valstate, WAITFIRSTOPERAND, WAITOPERAND, WAITOPERATOR, and WAITSINGLEOPERAND.

Referenced by makepol().

{
    *weight = 0;
    *prefix = false;

    while (1)
    {
        switch (state->state)
        {
            case WAITFIRSTOPERAND:
            case WAITOPERAND:
                if (t_iseq(state->buf, '!'))
                {
                    (state->buf)++;     /* can safely ++, t_iseq guarantee
                                         * that pg_mblen()==1 */
                    *operator = OP_NOT;
                    state->state = WAITOPERAND;
                    return PT_OPR;
                }
                else if (t_iseq(state->buf, '('))
                {
                    state->count++;
                    (state->buf)++;
                    state->state = WAITOPERAND;
                    return PT_OPEN;
                }
                else if (t_iseq(state->buf, ':'))
                {
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("syntax error in tsquery: \"%s\"",
                                    state->buffer)));
                }
                else if (!t_isspace(state->buf))
                {
                    /*
                     * We rely on the tsvector parser to parse the value for
                     * us
                     */
                    reset_tsvector_parser(state->valstate, state->buf);
                    if (gettoken_tsvector(state->valstate, strval, lenval, NULL, NULL, &state->buf))
                    {
                        state->buf = get_modifiers(state->buf, weight, prefix);
                        state->state = WAITOPERATOR;
                        return PT_VAL;
                    }
                    else if (state->state == WAITFIRSTOPERAND)
                        return PT_END;
                    else
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("no operand in tsquery: \"%s\"",
                                        state->buffer)));
                }
                break;
            case WAITOPERATOR:
                if (t_iseq(state->buf, '&'))
                {
                    state->state = WAITOPERAND;
                    *operator = OP_AND;
                    (state->buf)++;
                    return PT_OPR;
                }
                if (t_iseq(state->buf, '|'))
                {
                    state->state = WAITOPERAND;
                    *operator = OP_OR;
                    (state->buf)++;
                    return PT_OPR;
                }
                else if (t_iseq(state->buf, ')'))
                {
                    (state->buf)++;
                    state->count--;
                    return (state->count < 0) ? PT_ERR : PT_CLOSE;
                }
                else if (*(state->buf) == '\0')
                    return (state->count) ? PT_ERR : PT_END;
                else if (!t_isspace(state->buf))
                    return PT_ERR;
                break;
            case WAITSINGLEOPERAND:
                if (*(state->buf) == '\0')
                    return PT_END;
                *strval = state->buf;
                *lenval = strlen(state->buf);
                state->buf += strlen(state->buf);
                state->count++;
                return PT_VAL;
            default:
                return PT_ERR;
                break;
        }
        state->buf += pg_mblen(state->buf);
    }
}

static void infix ( INFIX in,
bool  first 
) [static]

Definition at line 602 of file tsquery.c.

References INFIX::buf, INFIX::buflen, check_stack_depth(), COPYCHAR, INFIX::cur, INFIX::curpol, QueryOperand::distance, elog, ERROR, QueryOperand::length, INFIX::op, TSQueryParserStateData::op, OP_AND, OP_NOT, OP_OR, palloc(), pfree(), pg_database_encoding_max_length(), pg_mblen(), QueryOperand::prefix, QI_OPR, QI_VAL, RESIZEBUF, t_iseq, ITEM::type, and QueryOperand::weight.

Referenced by tsqueryout(), and tsquerytree().

{
    /* 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;

        RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 6);
        *(in->cur) = '\'';
        in->cur++;
        while (*op)
        {
            if (t_iseq(op, '\''))
            {
                *(in->cur) = '\'';
                in->cur++;
            }
            else if (t_iseq(op, '\\'))
            {
                *(in->cur) = '\\';
                in->cur++;
            }
            COPYCHAR(in->cur, op);

            clen = pg_mblen(op);
            op += clen;
            in->cur += clen;
        }
        *(in->cur) = '\'';
        in->cur++;
        if (curpol->weight || curpol->prefix)
        {
            *(in->cur) = ':';
            in->cur++;
            if (curpol->prefix)
            {
                *(in->cur) = '*';
                in->cur++;
            }
            if (curpol->weight & (1 << 3))
            {
                *(in->cur) = 'A';
                in->cur++;
            }
            if (curpol->weight & (1 << 2))
            {
                *(in->cur) = 'B';
                in->cur++;
            }
            if (curpol->weight & (1 << 1))
            {
                *(in->cur) = 'C';
                in->cur++;
            }
            if (curpol->weight & 1)
            {
                *(in->cur) = 'D';
                in->cur++;
            }
        }
        *(in->cur) = '\0';
        in->curpol++;
    }
    else if (in->curpol->qoperator.oper == OP_NOT)
    {
        bool        isopr = false;

        RESIZEBUF(in, 1);
        *(in->cur) = '!';
        in->cur++;
        *(in->cur) = '\0';
        in->curpol++;

        if (in->curpol->type == QI_OPR)
        {
            isopr = true;
            RESIZEBUF(in, 2);
            sprintf(in->cur, "( ");
            in->cur = strchr(in->cur, '\0');
        }

        infix(in, isopr);
        if (isopr)
        {
            RESIZEBUF(in, 2);
            sprintf(in->cur, " )");
            in->cur = strchr(in->cur, '\0');
        }
    }
    else
    {
        int8        op = in->curpol->qoperator.oper;
        INFIX       nrm;

        in->curpol++;
        if (op == OP_OR && !first)
        {
            RESIZEBUF(in, 2);
            sprintf(in->cur, "( ");
            in->cur = strchr(in->cur, '\0');
        }

        nrm.curpol = in->curpol;
        nrm.op = in->op;
        nrm.buflen = 16;
        nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);

        /* get right operand */
        infix(&nrm, false);

        /* get & print left operand */
        in->curpol = nrm.curpol;
        infix(in, false);

        /* print operator & right operand */
        RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
        switch (op)
        {
            case OP_OR:
                sprintf(in->cur, " | %s", nrm.buf);
                break;
            case OP_AND:
                sprintf(in->cur, " & %s", nrm.buf);
                break;
            default:
                /* OP_NOT is handled in above if-branch */
                elog(ERROR, "unrecognized operator type: %d", op);
        }
        in->cur = strchr(in->cur, '\0');
        pfree(nrm.buf);

        if (op == OP_OR && !first)
        {
            RESIZEBUF(in, 2);
            sprintf(in->cur, " )");
            in->cur = strchr(in->cur, '\0');
        }
    }
}

static void makepol ( TSQueryParserState  state,
PushFunction  pushval,
Datum  opaque 
) [static]

Definition at line 328 of file tsquery.c.

References TSQueryParserStateData::buffer, check_stack_depth(), elog, ereport, errcode(), errmsg(), ERROR, gettoken_query(), OP_AND, OP_NOT, OP_OR, PT_CLOSE, PT_END, PT_ERR, PT_OPEN, PT_OPR, PT_VAL, pushOperator(), and STACKDEPTH.

Referenced by parse_tsquery().

{
    int8        operator = 0;
    ts_tokentype type;
    int         lenval = 0;
    char       *strval = NULL;
    int8        opstack[STACKDEPTH];
    int         lenstack = 0;
    int16       weight = 0;
    bool        prefix;

    /* since this function recurses, it could be driven to stack overflow */
    check_stack_depth();

    while ((type = gettoken_query(state, &operator, &lenval, &strval, &weight, &prefix)) != PT_END)
    {
        switch (type)
        {
            case PT_VAL:
                pushval(opaque, state, strval, lenval, weight, prefix);
                while (lenstack && (opstack[lenstack - 1] == OP_AND ||
                                    opstack[lenstack - 1] == OP_NOT))
                {
                    lenstack--;
                    pushOperator(state, opstack[lenstack]);
                }
                break;
            case PT_OPR:
                if (lenstack && operator == OP_OR)
                    pushOperator(state, OP_OR);
                else
                {
                    if (lenstack == STACKDEPTH) /* internal error */
                        elog(ERROR, "tsquery stack too small");
                    opstack[lenstack] = operator;
                    lenstack++;
                }
                break;
            case PT_OPEN:
                makepol(state, pushval, opaque);

                while (lenstack && (opstack[lenstack - 1] == OP_AND ||
                                    opstack[lenstack - 1] == OP_NOT))
                {
                    lenstack--;
                    pushOperator(state, opstack[lenstack]);
                }
                break;
            case PT_CLOSE:
                while (lenstack)
                {
                    lenstack--;
                    pushOperator(state, opstack[lenstack]);
                };
                return;
            case PT_ERR:
            default:
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("syntax error in tsquery: \"%s\"",
                                state->buffer)));
        }
    }
    while (lenstack)
    {
        lenstack--;
        pushOperator(state, opstack[lenstack]);
    }
}

TSQuery parse_tsquery ( char *  buf,
PushFunction  pushval,
Datum  opaque,
bool  isplain 
)

Definition at line 473 of file tsquery.c.

References TSQueryParserStateData::buf, TSQueryParserStateData::buffer, close_tsvector_parser(), COMPUTESIZE, TSQueryParserStateData::count, TSQueryParserStateData::curop, elog, ereport, errmsg(), ERROR, findoprnd(), GETOPERAND, GETQUERY, HDRSIZETQ, i, init_tsvector_parser(), TSQueryParserStateData::lenop, lfirst, list_length(), makepol(), NOTICE, TSQueryParserStateData::op, palloc(), palloc0(), pfree(), TSQueryParserStateData::polstr, QI_OPR, QI_VAL, QI_VALSTOP, SET_VARSIZE, TSQueryData::size, TSQueryParserStateData::state, TSQueryParserStateData::sumlen, QueryItem::type, TSQueryParserStateData::valstate, WAITFIRSTOPERAND, and WAITSINGLEOPERAND.

Referenced by plainto_tsquery_byid(), to_tsquery_byid(), and tsqueryin().

{
    struct TSQueryParserStateData state;
    int         i;
    TSQuery     query;
    int         commonlen;
    QueryItem  *ptr;
    ListCell   *cell;

    /* init state */
    state.buffer = buf;
    state.buf = buf;
    state.state = (isplain) ? WAITSINGLEOPERAND : WAITFIRSTOPERAND;
    state.count = 0;
    state.polstr = NIL;

    /* init value parser's state */
    state.valstate = init_tsvector_parser(state.buffer, true, true);

    /* init list of operand */
    state.sumlen = 0;
    state.lenop = 64;
    state.curop = state.op = (char *) palloc(state.lenop);
    *(state.curop) = '\0';

    /* parse query & make polish notation (postfix, but in reverse order) */
    makepol(&state, pushval, opaque);

    close_tsvector_parser(state.valstate);

    if (list_length(state.polstr) == 0)
    {
        ereport(NOTICE,
                (errmsg("text-search query doesn't contain lexemes: \"%s\"",
                        state.buffer)));
        query = (TSQuery) palloc(HDRSIZETQ);
        SET_VARSIZE(query, HDRSIZETQ);
        query->size = 0;
        return query;
    }

    /* Pack the QueryItems in the final TSQuery struct to return to caller */
    commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
    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);

        switch (item->type)
        {
            case QI_VAL:
                memcpy(&ptr[i], item, sizeof(QueryOperand));
                break;
            case QI_VALSTOP:
                ptr[i].type = QI_VALSTOP;
                break;
            case QI_OPR:
                memcpy(&ptr[i], item, sizeof(QueryOperator));
                break;
            default:
                elog(ERROR, "unrecognized QueryItem type: %d", item->type);
        }
        i++;
    }

    /* Copy all the operand strings to TSQuery */
    memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
    pfree(state.op);

    /* Set left operand pointers for every operator. */
    findoprnd(ptr, query->size);

    return query;
}

void pushOperator ( TSQueryParserState  state,
int8  oper 
)

Definition at line 225 of file tsquery.c.

References Assert, lcons(), OP_AND, OP_NOT, OP_OR, QueryOperator::oper, palloc0(), TSQueryParserStateData::polstr, and QueryOperator::type.

Referenced by makepol(), and pushval_morph().

{
    QueryOperator *tmp;

    Assert(oper == OP_NOT || oper == OP_AND || oper == OP_OR);

    tmp = (QueryOperator *) palloc0(sizeof(QueryOperator));
    tmp->type = QI_OPR;
    tmp->oper = oper;
    /* left is filled in later with findoprnd */

    state->polstr = lcons(tmp, state->polstr);
}

void pushStop ( TSQueryParserState  state  ) 

Definition at line 309 of file tsquery.c.

References lcons(), palloc0(), TSQueryParserStateData::polstr, and QueryOperand::type.

Referenced by pushval_morph().

{
    QueryOperand *tmp;

    tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
    tmp->type = QI_VALSTOP;

    state->polstr = lcons(tmp, state->polstr);
}

static void pushval_asis ( Datum  opaque,
TSQueryParserState  state,
char *  strval,
int  lenval,
int16  weight,
bool  prefix 
) [static]

Definition at line 558 of file tsquery.c.

References pushValue().

Referenced by tsqueryin().

{
    pushValue(state, strval, lenval, weight, prefix);
}

void pushValue ( TSQueryParserState  state,
char *  strval,
int  lenval,
int16  weight,
bool  prefix 
)

Definition at line 273 of file tsquery.c.

References TSQueryParserStateData::buffer, COMP_CRC32, TSQueryParserStateData::curop, ereport, errcode(), errmsg(), ERROR, FIN_CRC32, INIT_CRC32, TSQueryParserStateData::lenop, MAXSTRLEN, TSQueryParserStateData::op, pushValue_internal(), repalloc(), and TSQueryParserStateData::sumlen.

Referenced by pushval_asis(), and pushval_morph().

{
    pg_crc32    valcrc;

    if (lenval >= MAXSTRLEN)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("word is too long in tsquery: \"%s\"",
                        state->buffer)));

    INIT_CRC32(valcrc);
    COMP_CRC32(valcrc, strval, lenval);
    FIN_CRC32(valcrc);
    pushValue_internal(state, valcrc, state->curop - state->op, lenval, weight, prefix);

    /* 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;

        state->lenop *= 2;
        state->op = (char *) repalloc((void *) state->op, state->lenop);
        state->curop = state->op + used;
    }
    memcpy((void *) state->curop, (void *) strval, lenval);
    state->curop += lenval;
    *(state->curop) = '\0';
    state->curop++;
    state->sumlen += lenval + 1 /* \0 */ ;
}

static void pushValue_internal ( TSQueryParserState  state,
pg_crc32  valcrc,
int  distance,
int  lenval,
int  weight,
bool  prefix 
) [static]

Definition at line 240 of file tsquery.c.

References TSQueryParserStateData::buffer, QueryOperand::distance, ereport, errcode(), errmsg(), ERROR, lcons(), QueryOperand::length, MAXSTRLEN, MAXSTRPOS, palloc0(), TSQueryParserStateData::polstr, QueryOperand::prefix, QueryOperand::type, QueryOperand::valcrc, and QueryOperand::weight.

Referenced by pushValue().

{
    QueryOperand *tmp;

    if (distance >= MAXSTRPOS)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("value is too big in tsquery: \"%s\"",
                        state->buffer)));
    if (lenval >= MAXSTRLEN)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("operand is too long in tsquery: \"%s\"",
                        state->buffer)));

    tmp = (QueryOperand *) palloc0(sizeof(QueryOperand));
    tmp->type = QI_VAL;
    tmp->weight = weight;
    tmp->prefix = prefix;
    tmp->valcrc = (int32) valcrc;
    tmp->length = lenval;
    tmp->distance = distance;

    state->polstr = lcons(tmp, state->polstr);
}

Datum tsqueryin ( PG_FUNCTION_ARGS   ) 
Datum tsqueryout ( PG_FUNCTION_ARGS   ) 

Definition at line 748 of file tsquery.c.

References INFIX::buf, INFIX::buflen, INFIX::cur, INFIX::curpol, GETOPERAND, GETQUERY, infix(), INFIX::op, palloc(), PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_CSTRING, PG_RETURN_POINTER, and TSQueryData::size.

{
    TSQuery     query = PG_GETARG_TSQUERY(0);
    INFIX       nrm;

    if (query->size == 0)
    {
        char       *b = palloc(1);

        *b = '\0';
        PG_RETURN_POINTER(b);
    }
    nrm.curpol = GETQUERY(query);
    nrm.buflen = 32;
    nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
    *(nrm.cur) = '\0';
    nrm.op = GETOPERAND(query);
    infix(&nrm, true);

    PG_FREE_IF_COPY(query, 0);
    PG_RETURN_CSTRING(nrm.buf);
}

Datum tsqueryrecv ( PG_FUNCTION_ARGS   ) 

Definition at line 825 of file tsquery.c.

References Assert, buf, COMP_CRC32, QueryOperand::distance, elog, ERROR, FIN_CRC32, findoprnd(), GETOPERAND, GETQUERY, HDRSIZETQ, i, INIT_CRC32, QueryOperand::length, MaxAllocSize, MAXSTRLEN, MAXSTRPOS, OP_AND, OP_NOT, OP_OR, QueryOperator::oper, palloc(), palloc0(), pfree(), PG_GETARG_POINTER, PG_RETURN_TSVECTOR, pq_getmsgint(), pq_getmsgstring(), QueryOperand::prefix, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, repalloc(), SET_VARSIZE, QueryItem::type, val, QueryOperand::valcrc, and QueryOperand::weight.

{
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    TSQuery     query;
    int         i,
                len;
    QueryItem  *item;
    int         datalen;
    char       *ptr;
    uint32      size;
    const char **operands;

    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;
            const char *val;
            pg_crc32    valcrc;

            weight = (uint8) pq_getmsgint(buf, sizeof(uint8));
            prefix = (uint8) pq_getmsgint(buf, sizeof(uint8));
            val = pq_getmsgstring(buf);
            val_len = strlen(val);

            /* Sanity checks */

            if (weight > 0xF)
                elog(ERROR, "invalid tsquery: invalid weight bitmap");

            if (val_len > MAXSTRLEN)
                elog(ERROR, "invalid tsquery: operand too long");

            if (datalen > MAXSTRPOS)
                elog(ERROR, "invalid tsquery: total operand length exceeded");

            /* Looks valid. */

            INIT_CRC32(valcrc);
            COMP_CRC32(valcrc, val, val_len);
            FIN_CRC32(valcrc);

            item->qoperand.weight = weight;
            item->qoperand.prefix = (prefix) ? true : false;
            item->qoperand.valcrc = (int32) valcrc;
            item->qoperand.length = val_len;
            item->qoperand.distance = datalen;

            /*
             * Operand strings are copied to the final struct after this loop;
             * here we just collect them to an array
             */
            operands[i] = val;

            datalen += val_len + 1;     /* + 1 for the '\0' terminator */
        }
        else if (item->type == QI_OPR)
        {
            int8        oper;

            oper = (int8) pq_getmsgint(buf, sizeof(int8));
            if (oper != OP_NOT && oper != OP_OR && oper != OP_AND)
                elog(ERROR, "invalid tsquery: unrecognized operator type %d",
                     (int) oper);
            if (i == size - 1)
                elog(ERROR, "invalid pointer to right operand");

            item->qoperator.oper = oper;
        }
        else
            elog(ERROR, "unrecognized tsquery node type: %d", item->type);

        item++;
    }

    /* Enlarge buffer to make room for the operand values. */
    query = (TSQuery) repalloc(query, len + datalen);
    item = GETQUERY(query);
    ptr = GETOPERAND(query);

    /*
     * Fill in the left-pointers. Checks that the tree is well-formed as a
     * side-effect.
     */
    findoprnd(item, size);

    /* Copy operands to output struct */
    for (i = 0; i < size; i++)
    {
        if (item->type == QI_VAL)
        {
            memcpy(ptr, operands[i], item->qoperand.length + 1);
            ptr += item->qoperand.length + 1;
        }
        item++;
    }

    pfree(operands);

    Assert(ptr - GETOPERAND(query) == datalen);

    SET_VARSIZE(query, len + datalen);

    PG_RETURN_TSVECTOR(query);
}

Datum tsquerysend ( PG_FUNCTION_ARGS   ) 

Definition at line 789 of file tsquery.c.

References buf, QueryOperand::distance, elog, ERROR, GETOPERAND, GETQUERY, i, QueryOperator::oper, PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint(), pq_sendstring(), QueryOperand::prefix, QI_OPR, QI_VAL, QueryItem::qoperand, QueryItem::qoperator, TSQueryData::size, QueryItem::type, and QueryOperand::weight.

{
    TSQuery     query = PG_GETARG_TSQUERY(0);
    StringInfoData buf;
    int         i;
    QueryItem  *item = GETQUERY(query);

    pq_begintypsend(&buf);

    pq_sendint(&buf, query->size, sizeof(uint32));
    for (i = 0; i < query->size; i++)
    {
        pq_sendint(&buf, item->type, sizeof(item->type));

        switch (item->type)
        {
            case QI_VAL:
                pq_sendint(&buf, item->qoperand.weight, sizeof(uint8));
                pq_sendint(&buf, item->qoperand.prefix, sizeof(uint8));
                pq_sendstring(&buf, GETOPERAND(query) + item->qoperand.distance);
                break;
            case QI_OPR:
                pq_sendint(&buf, item->qoperator.oper, sizeof(item->qoperator.oper));
                break;
            default:
                elog(ERROR, "unrecognized tsquery node type: %d", item->type);
        }
        item++;
    }

    PG_FREE_IF_COPY(query, 0);

    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

Datum tsquerytree ( PG_FUNCTION_ARGS   ) 

Definition at line 954 of file tsquery.c.

References INFIX::buf, INFIX::buflen, clean_NOT(), cstring_to_text(), cstring_to_text_with_len(), INFIX::cur, INFIX::curpol, GETOPERAND, GETQUERY, infix(), INFIX::op, palloc(), pfree(), PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_RETURN_POINTER, PG_RETURN_TEXT_P, SET_VARSIZE, TSQueryData::size, and VARHDRSZ.

{
    TSQuery     query = PG_GETARG_TSQUERY(0);
    INFIX       nrm;
    text       *res;
    QueryItem  *q;
    int         len;

    if (query->size == 0)
    {
        res = (text *) palloc(VARHDRSZ);
        SET_VARSIZE(res, VARHDRSZ);
        PG_RETURN_POINTER(res);
    }

    q = clean_NOT(GETQUERY(query), &len);

    if (!q)
    {
        res = cstring_to_text("T");
    }
    else
    {
        nrm.curpol = q;
        nrm.buflen = 32;
        nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
        *(nrm.cur) = '\0';
        nrm.op = GETOPERAND(query);
        infix(&nrm, true);
        res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
        pfree(q);
    }

    PG_FREE_IF_COPY(query, 0);

    PG_RETURN_TEXT_P(res);
}