Header And Logo

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

Data Structures | Defines | Typedefs | Functions

ltxtquery_io.c File Reference

#include "postgres.h"
#include <ctype.h>
#include "crc32.h"
#include "ltree.h"
Include dependency graph for ltxtquery_io.c:

Go to the source code of this file.

Data Structures

struct  NODE
struct  QPRS_STATE
struct  INFIX

Defines

#define WAITOPERAND   1
#define INOPERAND   2
#define WAITOPERATOR   3
#define STACKDEPTH   32
#define RESIZEBUF(inf, addsize)

Typedefs

typedef struct NODE NODE

Functions

 PG_FUNCTION_INFO_V1 (ltxtq_in)
Datum ltxtq_in (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (ltxtq_out)
Datum ltxtq_out (PG_FUNCTION_ARGS)
static int32 gettoken_query (QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint16 *flag)
static void pushquery (QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval, uint16 flag)
static void pushval_asis (QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
static int32 makepol (QPRS_STATE *state)
static void findoprnd (ITEM *ptr, int32 *pos)
static ltxtqueryqueryin (char *buf)
static void infix (INFIX *in, bool first)

Define Documentation

#define INOPERAND   2

Definition at line 22 of file ltxtquery_io.c.

Referenced by gettoken_query().

#define RESIZEBUF (   inf,
  addsize 
)
Value:
while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
{ \
    int32 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 395 of file ltxtquery_io.c.

Referenced by infix().

#define STACKDEPTH   32

Definition at line 200 of file ltxtquery_io.c.

Referenced by makepol().

#define WAITOPERAND   1

Definition at line 21 of file ltxtquery_io.c.

Referenced by gettoken_query().

#define WAITOPERATOR   3

Definition at line 23 of file ltxtquery_io.c.

Referenced by gettoken_query().


Typedef Documentation

typedef struct NODE NODE

Function Documentation

static void findoprnd ( ITEM ptr,
int32 pos 
) [static]

Definition at line 277 of file ltxtquery_io.c.

References ITEM::left, NODE::type, val, VAL, and VALTRUE.

Referenced by queryin().

{
    if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
    {
        ptr[*pos].left = 0;
        (*pos)++;
    }
    else if (ptr[*pos].val == (int32) '!')
    {
        ptr[*pos].left = 1;
        (*pos)++;
        findoprnd(ptr, pos);
    }
    else
    {
        ITEM       *curitem = &ptr[*pos];
        int32       tmp = *pos;

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

static int32 gettoken_query ( QPRS_STATE state,
int32 val,
int32 lenval,
char **  strval,
uint16 flag 
) [static]

Definition at line 60 of file ltxtquery_io.c.

References QPRS_STATE::buf, QPRS_STATE::count, ereport, ERR, errcode(), errmsg(), ERROR, INOPERAND, ISALNUM, pg_mblen(), QPRS_STATE::state, t_iseq, t_isspace, WAITOPERAND, and WAITOPERATOR.

Referenced by makepol().

{
    int         charlen;

    for (;;)
    {
        charlen = pg_mblen(state->buf);

        switch (state->state)
        {
            case WAITOPERAND:
                if (charlen == 1 && t_iseq(state->buf, '!'))
                {
                    (state->buf)++;
                    *val = (int32) '!';
                    return OPR;
                }
                else if (charlen == 1 && t_iseq(state->buf, '('))
                {
                    state->count++;
                    (state->buf)++;
                    return OPEN;
                }
                else if (ISALNUM(state->buf))
                {
                    state->state = INOPERAND;
                    *strval = state->buf;
                    *lenval = charlen;
                    *flag = 0;
                }
                else if (!t_isspace(state->buf))
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("operand syntax error")));
                break;
            case INOPERAND:
                if (ISALNUM(state->buf))
                {
                    if (*flag)
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("modificators syntax error")));
                    *lenval += charlen;
                }
                else if (charlen == 1 && t_iseq(state->buf, '%'))
                    *flag |= LVAR_SUBLEXEME;
                else if (charlen == 1 && t_iseq(state->buf, '@'))
                    *flag |= LVAR_INCASE;
                else if (charlen == 1 && t_iseq(state->buf, '*'))
                    *flag |= LVAR_ANYEND;
                else
                {
                    state->state = WAITOPERATOR;
                    return VAL;
                }
                break;
            case WAITOPERATOR:
                if (charlen == 1 && (t_iseq(state->buf, '&') || t_iseq(state->buf, '|')))
                {
                    state->state = WAITOPERAND;
                    *val = (int32) *(state->buf);
                    (state->buf)++;
                    return OPR;
                }
                else if (charlen == 1 && t_iseq(state->buf, ')'))
                {
                    (state->buf)++;
                    state->count--;
                    return (state->count < 0) ? ERR : CLOSE;
                }
                else if (*(state->buf) == '\0')
                    return (state->count) ? ERR : END;
                else if (charlen == 1 && !t_iseq(state->buf, ' '))
                    return ERR;
                break;
            default:
                return ERR;
                break;
        }

        state->buf += charlen;
    }
}

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

Definition at line 409 of file ltxtquery_io.c.

References INFIX::buf, INFIX::buflen, INFIX::cur, INFIX::curpol, ITEM::distance, ITEM::flag, ITEM::length, LVAR_ANYEND, LVAR_INCASE, LVAR_SUBLEXEME, INFIX::op, OPR, palloc(), pfree(), RESIZEBUF, ITEM::type, ITEM::val, and VAL.

Referenced by ltxtq_out().

{
    if (in->curpol->type == VAL)
    {
        char       *op = in->op + in->curpol->distance;

        RESIZEBUF(in, in->curpol->length * 2 + 5);
        while (*op)
        {
            *(in->cur) = *op;
            op++;
            in->cur++;
        }
        if (in->curpol->flag & LVAR_SUBLEXEME)
        {
            *(in->cur) = '%';
            in->cur++;
        }
        if (in->curpol->flag & LVAR_INCASE)
        {
            *(in->cur) = '@';
            in->cur++;
        }
        if (in->curpol->flag & LVAR_ANYEND)
        {
            *(in->cur) = '*';
            in->cur++;
        }
        *(in->cur) = '\0';
        in->curpol++;
    }
    else if (in->curpol->val == (int32) '!')
    {
        bool        isopr = false;

        RESIZEBUF(in, 1);
        *(in->cur) = '!';
        in->cur++;
        *(in->cur) = '\0';
        in->curpol++;
        if (in->curpol->type == 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
    {
        int32       op = in->curpol->val;
        INFIX       nrm;

        in->curpol++;
        if (op == (int32) '|' && !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));
        sprintf(in->cur, " %c %s", op, nrm.buf);
        in->cur = strchr(in->cur, '\0');
        pfree(nrm.buf);

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

Datum ltxtq_in ( PG_FUNCTION_ARGS   ) 

Definition at line 378 of file ltxtquery_io.c.

References PG_GETARG_POINTER, PG_RETURN_POINTER, and queryin().

Datum ltxtq_out ( PG_FUNCTION_ARGS   ) 

Definition at line 505 of file ltxtquery_io.c.

References INFIX::buf, INFIX::buflen, INFIX::cur, INFIX::curpol, ereport, errcode(), errdetail(), errmsg(), ERROR, GETOPERAND, GETQUERY, infix(), INFIX::op, palloc(), PG_FREE_IF_COPY, PG_GETARG_LTXTQUERY, PG_RETURN_POINTER, and ltxtquery::size.

{
    ltxtquery  *query = PG_GETARG_LTXTQUERY(0);
    INFIX       nrm;

    if (query->size == 0)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("syntax error"),
                 errdetail("Empty query.")));

    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_POINTER(nrm.buf);
}

static int32 makepol ( QPRS_STATE state  )  [static]

Definition at line 205 of file ltxtquery_io.c.

References CLOSE, elog, END, ereport, ERR, errcode(), errmsg(), ERROR, flag(), gettoken_query(), OPEN, OPR, pushquery(), pushval_asis(), STACKDEPTH, NODE::type, VAL, and val.

Referenced by queryin().

{
    int32       val = 0,
                type;
    int32       lenval = 0;
    char       *strval = NULL;
    int32       stack[STACKDEPTH];
    int32       lenstack = 0;
    uint16      flag = 0;

    while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
    {
        switch (type)
        {
            case VAL:
                pushval_asis(state, VAL, strval, lenval, flag);
                while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
                                    stack[lenstack - 1] == (int32) '!'))
                {
                    lenstack--;
                    pushquery(state, OPR, stack[lenstack], 0, 0, 0);
                }
                break;
            case OPR:
                if (lenstack && val == (int32) '|')
                    pushquery(state, OPR, val, 0, 0, 0);
                else
                {
                    if (lenstack == STACKDEPTH)
                        /* internal error */
                        elog(ERROR, "stack too short");
                    stack[lenstack] = val;
                    lenstack++;
                }
                break;
            case OPEN:
                if (makepol(state) == ERR)
                    return ERR;
                while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
                                    stack[lenstack - 1] == (int32) '!'))
                {
                    lenstack--;
                    pushquery(state, OPR, stack[lenstack], 0, 0, 0);
                }
                break;
            case CLOSE:
                while (lenstack)
                {
                    lenstack--;
                    pushquery(state, OPR, stack[lenstack], 0, 0, 0);
                };
                return END;
                break;
            case ERR:
            default:
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("syntax error")));

                return ERR;

        }
    }
    while (lenstack)
    {
        lenstack--;
        pushquery(state, OPR, stack[lenstack], 0, 0, 0);
    };
    return END;
}

PG_FUNCTION_INFO_V1 ( ltxtq_in   ) 
PG_FUNCTION_INFO_V1 ( ltxtq_out   ) 
static void pushquery ( QPRS_STATE state,
int32  type,
int32  val,
int32  distance,
int32  lenval,
uint16  flag 
) [static]

Definition at line 148 of file ltxtquery_io.c.

References NODE::distance, ereport, errcode(), errmsg(), ERROR, NODE::flag, NODE::length, NODE::next, QPRS_STATE::num, palloc(), QPRS_STATE::str, NODE::type, and NODE::val.

Referenced by makepol(), and pushval_asis().

{
    NODE       *tmp = (NODE *) palloc(sizeof(NODE));

    tmp->type = type;
    tmp->val = val;
    tmp->flag = flag;
    if (distance > 0xffff)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("value is too big")));
    if (lenval > 0xff)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("operand is too long")));
    tmp->distance = distance;
    tmp->length = lenval;
    tmp->next = state->str;
    state->str = tmp;
    state->num++;
}

static void pushval_asis ( QPRS_STATE state,
int  type,
char *  strval,
int  lenval,
uint16  flag 
) [static]

Definition at line 174 of file ltxtquery_io.c.

References QPRS_STATE::curop, ereport, errcode(), errmsg(), ERROR, QPRS_STATE::lenop, ltree_crc32_sz(), QPRS_STATE::op, pushquery(), repalloc(), and QPRS_STATE::sumlen.

Referenced by makepol().

{
    if (lenval > 0xffff)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("word is too long")));

    pushquery(state, type, ltree_crc32_sz(strval, lenval),
              state->curop - state->op, lenval, flag);

    while (state->curop - state->op + lenval + 1 >= state->lenop)
    {
        int32       tmp = state->curop - state->op;

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

static ltxtquery* queryin ( char *  buf  )  [static]

Definition at line 307 of file ltxtquery_io.c.

References QPRS_STATE::buf, COMPUTESIZE, QPRS_STATE::count, cur, QPRS_STATE::curop, NODE::distance, ITEM::distance, ereport, errcode(), errdetail(), errmsg(), ERROR, findoprnd(), NODE::flag, ITEM::flag, GETOPERAND, GETQUERY, i, NODE::length, ITEM::length, QPRS_STATE::lenop, makepol(), NODE::next, QPRS_STATE::num, QPRS_STATE::op, palloc(), pfree(), SET_VARSIZE, ltxtquery::size, QPRS_STATE::state, QPRS_STATE::str, QPRS_STATE::sumlen, NODE::type, ITEM::type, NODE::val, and ITEM::val.

Referenced by ltxtq_in().

{
    QPRS_STATE  state;
    int32       i;
    ltxtquery  *query;
    int32       commonlen;
    ITEM       *ptr;
    NODE       *tmp;
    int32       pos = 0;

#ifdef BS_DEBUG
    char        pbuf[16384],
               *cur;
#endif

    /* init state */
    state.buf = buf;
    state.state = WAITOPERAND;
    state.count = 0;
    state.num = 0;
    state.str = NULL;

    /* 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);
    if (!state.num)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("syntax error"),
                 errdetail("Empty query.")));

    /* make finish struct */
    commonlen = COMPUTESIZE(state.num, state.sumlen);
    query = (ltxtquery *) palloc(commonlen);
    SET_VARSIZE(query, commonlen);
    query->size = state.num;
    ptr = GETQUERY(query);

    /* set item in polish notation */
    for (i = 0; i < state.num; i++)
    {
        ptr[i].type = state.str->type;
        ptr[i].val = state.str->val;
        ptr[i].distance = state.str->distance;
        ptr[i].length = state.str->length;
        ptr[i].flag = state.str->flag;
        tmp = state.str->next;
        pfree(state.str);
        state.str = tmp;
    }

    /* set user friendly-operand view */
    memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
    pfree(state.op);

    /* set left operand's position for every operator */
    pos = 0;
    findoprnd(ptr, &pos);

    return query;
}