Header And Logo

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

Data Structures | Defines | Functions

ltree_io.c File Reference

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

Go to the source code of this file.

Data Structures

struct  nodeitem

Defines

#define UNCHAR
#define LTPRS_WAITNAME   0
#define LTPRS_WAITDELIM   1
#define LQPRS_WAITLEVEL   0
#define LQPRS_WAITDELIM   1
#define LQPRS_WAITOPEN   2
#define LQPRS_WAITFNUM   3
#define LQPRS_WAITSNUM   4
#define LQPRS_WAITND   5
#define LQPRS_WAITCLOSE   6
#define LQPRS_WAITEND   7
#define LQPRS_WAITVAR   8
#define GETVAR(x)   ( *((nodeitem**)LQL_FIRST(x)) )
#define ITEMSIZE   MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
#define NEXTLEV(x)   ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )

Functions

 PG_FUNCTION_INFO_V1 (ltree_in)
Datum ltree_in (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (ltree_out)
Datum ltree_out (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (lquery_in)
Datum lquery_in (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (lquery_out)
Datum lquery_out (PG_FUNCTION_ARGS)

Define Documentation

#define GETVAR (   x  )     ( *((nodeitem**)LQL_FIRST(x)) )

Definition at line 190 of file ltree_io.c.

Referenced by lquery_in().

#define ITEMSIZE   MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))

Definition at line 191 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITCLOSE   6

Definition at line 185 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITDELIM   1

Definition at line 180 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITEND   7

Definition at line 186 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITFNUM   3

Definition at line 182 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITLEVEL   0

Definition at line 179 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITND   5

Definition at line 184 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITOPEN   2

Definition at line 181 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITSNUM   4

Definition at line 183 of file ltree_io.c.

Referenced by lquery_in().

#define LQPRS_WAITVAR   8

Definition at line 187 of file ltree_io.c.

Referenced by lquery_in().

#define LTPRS_WAITDELIM   1

Definition at line 41 of file ltree_io.c.

Referenced by ltree_in().

#define LTPRS_WAITNAME   0

Definition at line 40 of file ltree_io.c.

Referenced by ltree_in().

#define NEXTLEV (   x  )     ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )

Definition at line 192 of file ltree_io.c.

Referenced by lquery_in().

#define UNCHAR
Value:
ereport(ERROR, \
                       (errcode(ERRCODE_SYNTAX_ERROR), \
                        errmsg("syntax error at position %d", \
                        pos)));

Definition at line 26 of file ltree_io.c.


Function Documentation

Datum lquery_in ( PG_FUNCTION_ARGS   ) 

Definition at line 195 of file ltree_io.c.

References buf, cur, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, lquery::firstgood, lquery_variant::flag, lquery::flag, nodeitem::flag, lquery_level::flag, GETVAR, lquery_level::high, ISALNUM, ITEMSIZE, lquery_variant::len, nodeitem::len, lquery_level::low, LQL_FIRST, LQL_HDRSIZE, LQL_NEXT, LQPRS_WAITCLOSE, LQPRS_WAITDELIM, LQPRS_WAITEND, LQPRS_WAITFNUM, LQPRS_WAITLEVEL, LQPRS_WAITND, LQPRS_WAITOPEN, LQPRS_WAITSNUM, LQPRS_WAITVAR, LQUERY_FIRST, ltree_crc32_sz(), LVAR_HDRSIZE, LVAR_NEXT, MAXALIGN, lquery_variant::name, NEXTLEV, lquery::numlevel, lquery_level::numvar, palloc0(), pfree(), PG_GETARG_POINTER, pg_mblen(), PG_RETURN_POINTER, SET_VARSIZE, nodeitem::start, t_isdigit, t_iseq, lquery_level::totallen, lquery_variant::val, and nodeitem::wlen.

{
    char       *buf = (char *) PG_GETARG_POINTER(0);
    char       *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 = 0;

    ptr = buf;
    while (*ptr)
    {
        charlen = pg_mblen(ptr);

        if (charlen == 1)
        {
            if (t_iseq(ptr, '.'))
                num++;
            else if (t_iseq(ptr, '|'))
                numOR++;
        }

        ptr += charlen;
    }

    num++;
    curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
    ptr = buf;
    while (*ptr)
    {
        charlen = pg_mblen(ptr);

        if (state == LQPRS_WAITLEVEL)
        {
            if (ISALNUM(ptr))
            {
                GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
                lptr->start = ptr;
                state = LQPRS_WAITDELIM;
                curqlevel->numvar = 1;
            }
            else if (charlen == 1 && t_iseq(ptr, '!'))
            {
                GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
                lptr->start = ptr + 1;
                state = LQPRS_WAITDELIM;
                curqlevel->numvar = 1;
                curqlevel->flag |= LQL_NOT;
                hasnot = true;
            }
            else if (charlen == 1 && t_iseq(ptr, '*'))
                state = LQPRS_WAITOPEN;
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITVAR)
        {
            if (ISALNUM(ptr))
            {
                lptr++;
                lptr->start = ptr;
                state = LQPRS_WAITDELIM;
                curqlevel->numvar++;
            }
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITDELIM)
        {
            if (charlen == 1 && t_iseq(ptr, '@'))
            {
                if (lptr->start == ptr)
                    UNCHAR;
                lptr->flag |= LVAR_INCASE;
                curqlevel->flag |= LVAR_INCASE;
            }
            else if (charlen == 1 && t_iseq(ptr, '*'))
            {
                if (lptr->start == ptr)
                    UNCHAR;
                lptr->flag |= LVAR_ANYEND;
                curqlevel->flag |= LVAR_ANYEND;
            }
            else if (charlen == 1 && t_iseq(ptr, '%'))
            {
                if (lptr->start == ptr)
                    UNCHAR;
                lptr->flag |= LVAR_SUBLEXEME;
                curqlevel->flag |= LVAR_SUBLEXEME;
            }
            else if (charlen == 1 && t_iseq(ptr, '|'))
            {
                lptr->len = ptr - lptr->start -
                    ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
                    ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
                    ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
                if (lptr->wlen > 255)
                    ereport(ERROR,
                            (errcode(ERRCODE_NAME_TOO_LONG),
                             errmsg("name of level is too long"),
                             errdetail("Name length is %d, must "
                                       "be < 256, in position %d.",
                                       lptr->wlen, pos)));

                state = LQPRS_WAITVAR;
            }
            else if (charlen == 1 && t_iseq(ptr, '.'))
            {
                lptr->len = ptr - lptr->start -
                    ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
                    ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
                    ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
                if (lptr->wlen > 255)
                    ereport(ERROR,
                            (errcode(ERRCODE_NAME_TOO_LONG),
                             errmsg("name of level is too long"),
                             errdetail("Name length is %d, must "
                                       "be < 256, in position %d.",
                                       lptr->wlen, pos)));

                state = LQPRS_WAITLEVEL;
                curqlevel = NEXTLEV(curqlevel);
            }
            else if (ISALNUM(ptr))
            {
                if (lptr->flag)
                    UNCHAR;
            }
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITOPEN)
        {
            if (charlen == 1 && t_iseq(ptr, '{'))
                state = LQPRS_WAITFNUM;
            else if (charlen == 1 && t_iseq(ptr, '.'))
            {
                curqlevel->low = 0;
                curqlevel->high = 0xffff;
                curqlevel = NEXTLEV(curqlevel);
                state = LQPRS_WAITLEVEL;
            }
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITFNUM)
        {
            if (charlen == 1 && t_iseq(ptr, ','))
                state = LQPRS_WAITSNUM;
            else if (t_isdigit(ptr))
            {
                curqlevel->low = atoi(ptr);
                state = LQPRS_WAITND;
            }
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITSNUM)
        {
            if (t_isdigit(ptr))
            {
                curqlevel->high = atoi(ptr);
                state = LQPRS_WAITCLOSE;
            }
            else if (charlen == 1 && t_iseq(ptr, '}'))
            {
                curqlevel->high = 0xffff;
                state = LQPRS_WAITEND;
            }
            else
                UNCHAR;
        }
        else if (state == LQPRS_WAITCLOSE)
        {
            if (charlen == 1 && t_iseq(ptr, '}'))
                state = LQPRS_WAITEND;
            else if (!t_isdigit(ptr))
                UNCHAR;
        }
        else if (state == LQPRS_WAITND)
        {
            if (charlen == 1 && t_iseq(ptr, '}'))
            {
                curqlevel->high = curqlevel->low;
                state = LQPRS_WAITEND;
            }
            else if (charlen == 1 && t_iseq(ptr, ','))
                state = LQPRS_WAITSNUM;
            else if (!t_isdigit(ptr))
                UNCHAR;
        }
        else if (state == LQPRS_WAITEND)
        {
            if (charlen == 1 && t_iseq(ptr, '.'))
            {
                state = LQPRS_WAITLEVEL;
                curqlevel = NEXTLEV(curqlevel);
            }
            else
                UNCHAR;
        }
        else
            /* internal error */
            elog(ERROR, "internal error in parser");

        ptr += charlen;
        if (state == LQPRS_WAITDELIM)
            lptr->wlen++;
        pos++;
    }

    if (state == LQPRS_WAITDELIM)
    {
        if (lptr->start == ptr)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("syntax error"),
                     errdetail("Unexpected end of line.")));

        lptr->len = ptr - lptr->start -
            ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
            ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
            ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
        if (lptr->len == 0)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("syntax error"),
                     errdetail("Unexpected end of line.")));

        if (lptr->wlen > 255)
            ereport(ERROR,
                    (errcode(ERRCODE_NAME_TOO_LONG),
                     errmsg("name of level is too long"),
                     errdetail("Name length is %d, must "
                               "be < 256, in position %d.",
                               lptr->wlen, pos)));
    }
    else if (state == LQPRS_WAITOPEN)
        curqlevel->high = 0xffff;
    else if (state != LQPRS_WAITEND)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("syntax error"),
                 errdetail("Unexpected end of line.")));

    curqlevel = tmpql;
    totallen = LQUERY_HDRSIZE;
    while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
    {
        totallen += LQL_HDRSIZE;
        if (curqlevel->numvar)
        {
            lptr = GETVAR(curqlevel);
            while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
            {
                totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
                lptr++;
            }
        }
        else if (curqlevel->low > curqlevel->high)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("syntax error"),
                     errdetail("Low limit(%d) is greater than upper(%d).",
                               curqlevel->low, curqlevel->high)));

        curqlevel = NEXTLEV(curqlevel);
    }

    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)
            {
                cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
                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)
                wasbad = true;
            else if (wasbad == false)
                (result->firstgood)++;
        }
        else
            wasbad = true;
        curqlevel = NEXTLEV(curqlevel);
        cur = LQL_NEXT(cur);
    }

    pfree(tmpql);
    PG_RETURN_POINTER(result);
}

Datum lquery_out ( PG_FUNCTION_ARGS   ) 

Definition at line 518 of file ltree_io.c.

References buf, lquery_variant::flag, lquery_level::flag, lquery_level::high, i, lquery_variant::len, lquery_level::low, LQL_FIRST, LQL_NEXT, LQL_NOT, LQUERY_FIRST, LVAR_ANYEND, LVAR_INCASE, LVAR_NEXT, LVAR_SUBLEXEME, lquery_variant::name, lquery::numlevel, lquery_level::numvar, palloc(), PG_FREE_IF_COPY, PG_GETARG_LQUERY, PG_RETURN_POINTER, and lquery_level::totallen.

{
    lquery     *in = PG_GETARG_LQUERY(0);
    char       *buf,
               *ptr;
    int         i,
                j,
                totallen = 1;
    lquery_level *curqlevel;
    lquery_variant *curtlevel;

    curqlevel = LQUERY_FIRST(in);
    for (i = 0; i < in->numlevel; i++)
    {
        totallen++;
        if (curqlevel->numvar)
            totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
        else
            totallen += 2 * 11 + 4;
        curqlevel = LQL_NEXT(curqlevel);
    }

    ptr = buf = (char *) palloc(totallen);
    curqlevel = LQUERY_FIRST(in);
    for (i = 0; i < in->numlevel; i++)
    {
        if (i != 0)
        {
            *ptr = '.';
            ptr++;
        }
        if (curqlevel->numvar)
        {
            if (curqlevel->flag & LQL_NOT)
            {
                *ptr = '!';
                ptr++;
            }
            curtlevel = LQL_FIRST(curqlevel);
            for (j = 0; j < curqlevel->numvar; j++)
            {
                if (j != 0)
                {
                    *ptr = '|';
                    ptr++;
                }
                memcpy(ptr, curtlevel->name, curtlevel->len);
                ptr += curtlevel->len;
                if ((curtlevel->flag & LVAR_SUBLEXEME))
                {
                    *ptr = '%';
                    ptr++;
                }
                if ((curtlevel->flag & LVAR_INCASE))
                {
                    *ptr = '@';
                    ptr++;
                }
                if ((curtlevel->flag & LVAR_ANYEND))
                {
                    *ptr = '*';
                    ptr++;
                }
                curtlevel = LVAR_NEXT(curtlevel);
            }
        }
        else
        {
            if (curqlevel->low == curqlevel->high)
            {
                sprintf(ptr, "*{%d}", curqlevel->low);
            }
            else if (curqlevel->low == 0)
            {
                if (curqlevel->high == 0xffff)
                {
                    *ptr = '*';
                    *(ptr + 1) = '\0';
                }
                else
                    sprintf(ptr, "*{,%d}", curqlevel->high);
            }
            else if (curqlevel->high == 0xffff)
            {
                sprintf(ptr, "*{%d,}", curqlevel->low);
            }
            else
                sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
            ptr = strchr(ptr, '\0');
        }

        curqlevel = LQL_NEXT(curqlevel);
    }

    *ptr = '\0';
    PG_FREE_IF_COPY(in, 0);

    PG_RETURN_POINTER(buf);
}

Datum ltree_in ( PG_FUNCTION_ARGS   ) 

Definition at line 44 of file ltree_io.c.

References buf, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ISALNUM, ltree_level::len, nodeitem::len, LEVEL_HDRSIZE, LEVEL_NEXT, sort-test::list, LTPRS_WAITDELIM, LTPRS_WAITNAME, LTREE_FIRST, LTREE_HDRSIZE, MAXALIGN, ltree_level::name, ltree::numlevel, palloc(), palloc0(), pfree(), PG_GETARG_POINTER, pg_mblen(), PG_RETURN_POINTER, SET_VARSIZE, nodeitem::start, t_iseq, and nodeitem::wlen.

Referenced by ltree_addtext(), ltree_textadd(), and text2ltree().

{
    char       *buf = (char *) PG_GETARG_POINTER(0);
    char       *ptr;
    nodeitem   *list,
               *lptr;
    int         num = 0,
                totallen = 0;
    int         state = LTPRS_WAITNAME;
    ltree      *result;
    ltree_level *curlevel;
    int         charlen;
    int         pos = 0;

    ptr = buf;
    while (*ptr)
    {
        charlen = pg_mblen(ptr);
        if (charlen == 1 && t_iseq(ptr, '.'))
            num++;
        ptr += charlen;
    }

    list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
    ptr = buf;
    while (*ptr)
    {
        charlen = pg_mblen(ptr);

        if (state == LTPRS_WAITNAME)
        {
            if (ISALNUM(ptr))
            {
                lptr->start = ptr;
                lptr->wlen = 0;
                state = LTPRS_WAITDELIM;
            }
            else
                UNCHAR;
        }
        else if (state == LTPRS_WAITDELIM)
        {
            if (charlen == 1 && t_iseq(ptr, '.'))
            {
                lptr->len = ptr - lptr->start;
                if (lptr->wlen > 255)
                    ereport(ERROR,
                            (errcode(ERRCODE_NAME_TOO_LONG),
                             errmsg("name of level is too long"),
                             errdetail("Name length is %d, must "
                                       "be < 256, in position %d.",
                                       lptr->wlen, pos)));

                totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
                lptr++;
                state = LTPRS_WAITNAME;
            }
            else if (!ISALNUM(ptr))
                UNCHAR;
        }
        else
            /* internal error */
            elog(ERROR, "internal error in parser");

        ptr += charlen;
        lptr->wlen++;
        pos++;
    }

    if (state == LTPRS_WAITDELIM)
    {
        lptr->len = ptr - lptr->start;
        if (lptr->wlen > 255)
            ereport(ERROR,
                    (errcode(ERRCODE_NAME_TOO_LONG),
                     errmsg("name of level is too long"),
                     errdetail("Name length is %d, must "
                               "be < 256, in position %d.",
                               lptr->wlen, pos)));

        totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
        lptr++;
    }
    else if (!(state == LTPRS_WAITNAME && lptr == list))
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("syntax error"),
                 errdetail("Unexpected end of line.")));

    result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
    SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
    result->numlevel = lptr - list;
    curlevel = LTREE_FIRST(result);
    lptr = list;
    while (lptr - list < result->numlevel)
    {
        curlevel->len = (uint16) lptr->len;
        memcpy(curlevel->name, lptr->start, lptr->len);
        curlevel = LEVEL_NEXT(curlevel);
        lptr++;
    }

    pfree(list);
    PG_RETURN_POINTER(result);
}

Datum ltree_out ( PG_FUNCTION_ARGS   ) 

Definition at line 151 of file ltree_io.c.

References buf, i, ltree_level::len, LEVEL_NEXT, LTREE_FIRST, ltree_level::name, ltree::numlevel, palloc(), PG_FREE_IF_COPY, PG_GETARG_LTREE, PG_RETURN_POINTER, and VARSIZE.

{
    ltree      *in = PG_GETARG_LTREE(0);
    char       *buf,
               *ptr;
    int         i;
    ltree_level *curlevel;

    ptr = buf = (char *) palloc(VARSIZE(in));
    curlevel = LTREE_FIRST(in);
    for (i = 0; i < in->numlevel; i++)
    {
        if (i != 0)
        {
            *ptr = '.';
            ptr++;
        }
        memcpy(ptr, curlevel->name, curlevel->len);
        ptr += curlevel->len;
        curlevel = LEVEL_NEXT(curlevel);
    }

    *ptr = '\0';
    PG_FREE_IF_COPY(in, 0);

    PG_RETURN_POINTER(buf);
}

PG_FUNCTION_INFO_V1 ( lquery_in   ) 
PG_FUNCTION_INFO_V1 ( ltree_in   ) 
PG_FUNCTION_INFO_V1 ( lquery_out   ) 
PG_FUNCTION_INFO_V1 ( ltree_out   )