2002-07-30 18:40:34 +02:00
|
|
|
/*
|
|
|
|
* in/out function for ltree and lquery
|
|
|
|
* Teodor Sigaev <teodor@stack.net>
|
2010-09-20 22:08:53 +02:00
|
|
|
* contrib/ltree/ltree_io.c
|
2002-07-30 18:40:34 +02:00
|
|
|
*/
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "postgres.h"
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
#include <ctype.h>
|
2008-05-12 02:00:54 +02:00
|
|
|
|
2019-10-23 05:56:22 +02:00
|
|
|
#include "crc32.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "ltree.h"
|
2014-02-17 15:33:31 +01:00
|
|
|
#include "utils/memutils.h"
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(ltree_in);
|
|
|
|
PG_FUNCTION_INFO_V1(ltree_out);
|
|
|
|
PG_FUNCTION_INFO_V1(lquery_in);
|
|
|
|
PG_FUNCTION_INFO_V1(lquery_out);
|
|
|
|
|
|
|
|
|
2003-07-24 19:52:50 +02:00
|
|
|
#define UNCHAR ereport(ERROR, \
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), \
|
2008-06-30 20:30:48 +02:00
|
|
|
errmsg("syntax error at position %d", \
|
|
|
|
pos)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
char *start;
|
2009-06-11 16:49:15 +02:00
|
|
|
int len; /* length in bytes */
|
2002-09-04 22:31:48 +02:00
|
|
|
int flag;
|
2009-06-11 16:49:15 +02:00
|
|
|
int wlen; /* length in characters */
|
|
|
|
} nodeitem;
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
#define LTPRS_WAITNAME 0
|
2002-09-04 22:31:48 +02:00
|
|
|
#define LTPRS_WAITDELIM 1
|
|
|
|
|
|
|
|
Datum
|
|
|
|
ltree_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
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;
|
2009-06-11 16:49:15 +02:00
|
|
|
int charlen;
|
|
|
|
int pos = 0;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
charlen = pg_mblen(ptr);
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '.'))
|
2002-07-30 18:40:34 +02:00
|
|
|
num++;
|
2009-06-11 16:49:15 +02:00
|
|
|
ptr += charlen;
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 22:09:51 +01:00
|
|
|
if (num + 1 > LTREE_MAX_LEVELS)
|
2014-02-17 15:33:31 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
|
|
|
|
num + 1, LTREE_MAX_LEVELS)));
|
2002-09-04 22:31:48 +02:00
|
|
|
list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
charlen = pg_mblen(ptr);
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
if (state == LTPRS_WAITNAME)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
if (ISALNUM(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr->start = ptr;
|
2008-06-30 20:30:48 +02:00
|
|
|
lptr->wlen = 0;
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LTPRS_WAITDELIM;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LTPRS_WAITDELIM)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '.'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr->len = ptr - lptr->start;
|
2008-06-30 20:30:48 +02:00
|
|
|
if (lptr->wlen > 255)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
|
|
|
errmsg("name of level is too long"),
|
2006-03-01 07:30:32 +01:00
|
|
|
errdetail("Name length is %d, must "
|
|
|
|
"be < 256, in position %d.",
|
2009-06-11 16:49:15 +02:00
|
|
|
lptr->wlen, pos)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-08-04 07:02:50 +02:00
|
|
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
|
|
|
state = LTPRS_WAITNAME;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2008-06-30 20:30:48 +02:00
|
|
|
else if (!ISALNUM(ptr))
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-24 19:52:50 +02:00
|
|
|
/* internal error */
|
|
|
|
elog(ERROR, "internal error in parser");
|
2008-06-30 20:30:48 +02:00
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
ptr += charlen;
|
2008-06-30 20:30:48 +02:00
|
|
|
lptr->wlen++;
|
|
|
|
pos++;
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
if (state == LTPRS_WAITDELIM)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr->len = ptr - lptr->start;
|
2008-06-30 20:30:48 +02:00
|
|
|
if (lptr->wlen > 255)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
|
|
|
errmsg("name of level is too long"),
|
2006-03-01 07:30:32 +01:00
|
|
|
errdetail("Name length is %d, must "
|
|
|
|
"be < 256, in position %d.",
|
2008-06-30 20:30:48 +02:00
|
|
|
lptr->wlen, pos)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-08-04 07:02:50 +02:00
|
|
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (!(state == LTPRS_WAITNAME && lptr == list))
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("syntax error"),
|
|
|
|
errdetail("Unexpected end of line.")));
|
2002-07-30 18:40:34 +02:00
|
|
|
|
2008-04-12 00:52:05 +02:00
|
|
|
result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
|
2007-02-28 23:44:38 +01:00
|
|
|
SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
|
2002-09-04 22:31:48 +02:00
|
|
|
result->numlevel = lptr - list;
|
2002-07-30 18:40:34 +02:00
|
|
|
curlevel = LTREE_FIRST(result);
|
2002-09-04 22:31:48 +02:00
|
|
|
lptr = list;
|
|
|
|
while (lptr - list < result->numlevel)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
curlevel->len = (uint16) lptr->len;
|
2002-09-04 22:31:48 +02:00
|
|
|
memcpy(curlevel->name, lptr->start, lptr->len);
|
|
|
|
curlevel = LEVEL_NEXT(curlevel);
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(list);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
Datum
|
|
|
|
ltree_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2017-09-18 21:21:23 +02:00
|
|
|
ltree *in = PG_GETARG_LTREE_P(0);
|
2002-09-04 22:31:48 +02:00
|
|
|
char *buf,
|
|
|
|
*ptr;
|
|
|
|
int i;
|
|
|
|
ltree_level *curlevel;
|
|
|
|
|
2007-02-28 23:44:38 +01:00
|
|
|
ptr = buf = (char *) palloc(VARSIZE(in));
|
2002-07-30 18:40:34 +02:00
|
|
|
curlevel = LTREE_FIRST(in);
|
2002-09-04 22:31:48 +02:00
|
|
|
for (i = 0; i < in->numlevel; i++)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '.';
|
|
|
|
ptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
memcpy(ptr, curlevel->name, curlevel->len);
|
|
|
|
ptr += curlevel->len;
|
2002-07-30 18:40:34 +02:00
|
|
|
curlevel = LEVEL_NEXT(curlevel);
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
*ptr = '\0';
|
|
|
|
PG_FREE_IF_COPY(in, 0);
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(buf);
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
#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
|
2002-07-30 18:40:34 +02:00
|
|
|
#define LQPRS_WAITEND 7
|
|
|
|
#define LQPRS_WAITVAR 8
|
|
|
|
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
#define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
|
|
|
|
#define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
|
|
|
|
#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
|
|
|
|
|
|
|
|
Datum
|
|
|
|
lquery_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
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;
|
2008-06-30 20:30:48 +02:00
|
|
|
int charlen;
|
2009-06-11 16:49:15 +02:00
|
|
|
int pos = 0;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
charlen = pg_mblen(ptr);
|
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1)
|
2008-06-30 20:30:48 +02:00
|
|
|
{
|
|
|
|
if (t_iseq(ptr, '.'))
|
|
|
|
num++;
|
|
|
|
else if (t_iseq(ptr, '|'))
|
|
|
|
numOR++;
|
|
|
|
}
|
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
ptr += charlen;
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
num++;
|
2020-03-28 22:09:51 +01:00
|
|
|
if (num > LQUERY_MAX_LEVELS)
|
2014-02-17 15:33:31 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("number of lquery levels (%d) exceeds the maximum allowed (%d)",
|
|
|
|
num, LQUERY_MAX_LEVELS)));
|
2008-04-12 00:52:05 +02:00
|
|
|
curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
|
2002-09-04 22:31:48 +02:00
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
charlen = pg_mblen(ptr);
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
if (state == LQPRS_WAITLEVEL)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
if (ISALNUM(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2008-04-12 00:52:05 +02:00
|
|
|
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr->start = ptr;
|
|
|
|
state = LQPRS_WAITDELIM;
|
|
|
|
curqlevel->numvar = 1;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '!'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2008-04-12 00:52:05 +02:00
|
|
|
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
2002-09-04 22:31:48 +02:00
|
|
|
lptr->start = ptr + 1;
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITDELIM;
|
|
|
|
curqlevel->numvar = 1;
|
|
|
|
curqlevel->flag |= LQL_NOT;
|
2002-09-04 22:31:48 +02:00
|
|
|
hasnot = true;
|
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '*'))
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITOPEN;
|
2002-09-04 22:31:48 +02:00
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITVAR)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
if (ISALNUM(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
|
|
|
lptr->start = ptr;
|
|
|
|
state = LQPRS_WAITDELIM;
|
|
|
|
curqlevel->numvar++;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITDELIM)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '@'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
if (lptr->start == ptr)
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
|
|
|
lptr->flag |= LVAR_INCASE;
|
|
|
|
curqlevel->flag |= LVAR_INCASE;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '*'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
if (lptr->start == ptr)
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
|
|
|
lptr->flag |= LVAR_ANYEND;
|
|
|
|
curqlevel->flag |= LVAR_ANYEND;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '%'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
if (lptr->start == ptr)
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2006-03-01 07:30:32 +01:00
|
|
|
lptr->flag |= LVAR_SUBLEXEME;
|
|
|
|
curqlevel->flag |= LVAR_SUBLEXEME;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '|'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
lptr->len = ptr - lptr->start -
|
2006-03-01 07:30:32 +01:00
|
|
|
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
2002-09-04 22:31:48 +02:00
|
|
|
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
|
|
|
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
2008-06-30 20:30:48 +02:00
|
|
|
if (lptr->wlen > 255)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
|
|
|
errmsg("name of level is too long"),
|
2006-03-01 07:30:32 +01:00
|
|
|
errdetail("Name length is %d, must "
|
|
|
|
"be < 256, in position %d.",
|
2009-06-11 16:49:15 +02:00
|
|
|
lptr->wlen, pos)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITVAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '.'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
lptr->len = ptr - lptr->start -
|
2006-03-01 07:30:32 +01:00
|
|
|
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
2002-09-04 22:31:48 +02:00
|
|
|
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
|
|
|
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
2008-06-30 20:30:48 +02:00
|
|
|
if (lptr->wlen > 255)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
|
|
|
errmsg("name of level is too long"),
|
2006-03-01 07:30:32 +01:00
|
|
|
errdetail("Name length is %d, must "
|
|
|
|
"be < 256, in position %d.",
|
2009-06-11 16:49:15 +02:00
|
|
|
lptr->wlen, pos)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITLEVEL;
|
2002-08-04 07:02:50 +02:00
|
|
|
curqlevel = NEXTLEV(curqlevel);
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2008-06-30 20:30:48 +02:00
|
|
|
else if (ISALNUM(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
if (lptr->flag)
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITOPEN)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '{'))
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITFNUM;
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '.'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
curqlevel->low = 0;
|
2020-03-28 22:09:51 +01:00
|
|
|
curqlevel->high = LTREE_MAX_LEVELS;
|
2002-08-04 07:02:50 +02:00
|
|
|
curqlevel = NEXTLEV(curqlevel);
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITLEVEL;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITFNUM)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, ','))
|
2002-09-04 22:31:48 +02:00
|
|
|
state = LQPRS_WAITSNUM;
|
2008-06-30 20:30:48 +02:00
|
|
|
else if (t_isdigit(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2020-03-28 22:09:51 +01:00
|
|
|
int low = atoi(ptr);
|
|
|
|
|
|
|
|
if (low < 0 || low > LTREE_MAX_LEVELS)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("lquery syntax error"),
|
|
|
|
errdetail("Low limit (%d) exceeds the maximum allowed (%d).",
|
|
|
|
low, LTREE_MAX_LEVELS)));
|
|
|
|
|
|
|
|
curqlevel->low = (uint16) low;
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITND;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
UNCHAR;
|
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITSNUM)
|
|
|
|
{
|
2008-06-30 20:30:48 +02:00
|
|
|
if (t_isdigit(ptr))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2020-03-28 22:09:51 +01:00
|
|
|
int high = atoi(ptr);
|
|
|
|
|
|
|
|
if (high < 0 || high > LTREE_MAX_LEVELS)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("lquery syntax error"),
|
|
|
|
errdetail("High limit (%d) exceeds the maximum allowed (%d).",
|
|
|
|
high, LTREE_MAX_LEVELS)));
|
|
|
|
|
|
|
|
curqlevel->high = (uint16) high;
|
2002-09-04 22:31:48 +02:00
|
|
|
state = LQPRS_WAITCLOSE;
|
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, '}'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2020-03-28 22:09:51 +01:00
|
|
|
curqlevel->high = LTREE_MAX_LEVELS;
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITEND;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITCLOSE)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '}'))
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITEND;
|
2008-06-30 20:30:48 +02:00
|
|
|
else if (!t_isdigit(ptr))
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITND)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '}'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
curqlevel->high = curqlevel->low;
|
|
|
|
state = LQPRS_WAITEND;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
else if (charlen == 1 && t_iseq(ptr, ','))
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITSNUM;
|
2008-06-30 20:30:48 +02:00
|
|
|
else if (!t_isdigit(ptr))
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITEND)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
if (charlen == 1 && t_iseq(ptr, '.'))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
state = LQPRS_WAITLEVEL;
|
2002-08-04 07:02:50 +02:00
|
|
|
curqlevel = NEXTLEV(curqlevel);
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2002-07-30 18:40:34 +02:00
|
|
|
UNCHAR;
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-24 19:52:50 +02:00
|
|
|
/* internal error */
|
|
|
|
elog(ERROR, "internal error in parser");
|
2008-06-30 20:30:48 +02:00
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
ptr += charlen;
|
|
|
|
if (state == LQPRS_WAITDELIM)
|
2008-06-30 20:30:48 +02:00
|
|
|
lptr->wlen++;
|
|
|
|
pos++;
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
|
|
if (state == LQPRS_WAITDELIM)
|
|
|
|
{
|
|
|
|
if (lptr->start == ptr)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("lquery syntax error"),
|
2003-07-24 19:52:50 +02:00
|
|
|
errdetail("Unexpected end of line.")));
|
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr->len = ptr - lptr->start -
|
2006-03-01 07:30:32 +01:00
|
|
|
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
2002-09-04 22:31:48 +02:00
|
|
|
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
|
|
|
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
|
|
|
if (lptr->len == 0)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("lquery syntax error"),
|
2003-07-24 19:52:50 +02:00
|
|
|
errdetail("Unexpected end of line.")));
|
|
|
|
|
2008-06-30 20:30:48 +02:00
|
|
|
if (lptr->wlen > 255)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
|
|
|
errmsg("name of level is too long"),
|
2006-03-01 07:30:32 +01:00
|
|
|
errdetail("Name length is %d, must "
|
|
|
|
"be < 256, in position %d.",
|
2008-06-30 20:30:48 +02:00
|
|
|
lptr->wlen, pos)));
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (state == LQPRS_WAITOPEN)
|
2020-03-28 22:09:51 +01:00
|
|
|
curqlevel->high = LTREE_MAX_LEVELS;
|
2002-09-04 22:31:48 +02:00
|
|
|
else if (state != LQPRS_WAITEND)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("lquery syntax error"),
|
2003-07-24 19:52:50 +02:00
|
|
|
errdetail("Unexpected end of line.")));
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-30 18:40:34 +02:00
|
|
|
curqlevel = tmpql;
|
2002-09-04 22:31:48 +02:00
|
|
|
totallen = LQUERY_HDRSIZE;
|
|
|
|
while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
|
|
|
|
{
|
|
|
|
totallen += LQL_HDRSIZE;
|
|
|
|
if (curqlevel->numvar)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr = GETVAR(curqlevel);
|
2002-09-04 22:31:48 +02:00
|
|
|
while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
|
|
|
|
{
|
2002-08-04 07:02:50 +02:00
|
|
|
totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else if (curqlevel->low > curqlevel->high)
|
2003-07-24 19:52:50 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2020-03-28 22:09:51 +01:00
|
|
|
errmsg("lquery syntax error"),
|
|
|
|
errdetail("Low limit (%d) is greater than upper (%d).",
|
2003-08-04 02:43:34 +02:00
|
|
|
curqlevel->low, curqlevel->high)));
|
2003-07-24 19:52:50 +02:00
|
|
|
|
2002-08-04 07:02:50 +02:00
|
|
|
curqlevel = NEXTLEV(curqlevel);
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
2002-08-04 07:02:50 +02:00
|
|
|
|
2008-04-12 00:52:05 +02:00
|
|
|
result = (lquery *) palloc0(totallen);
|
2007-02-28 23:44:38 +01:00
|
|
|
SET_VARSIZE(result, totallen);
|
2002-07-30 18:40:34 +02:00
|
|
|
result->numlevel = num;
|
|
|
|
result->firstgood = 0;
|
2002-09-04 22:31:48 +02:00
|
|
|
result->flag = 0;
|
|
|
|
if (hasnot)
|
2002-07-30 18:40:34 +02:00
|
|
|
result->flag |= LQUERY_HASNOT;
|
|
|
|
cur = LQUERY_FIRST(result);
|
|
|
|
curqlevel = tmpql;
|
2002-09-04 22:31:48 +02:00
|
|
|
while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
|
|
|
|
{
|
|
|
|
memcpy(cur, curqlevel, LQL_HDRSIZE);
|
|
|
|
cur->totallen = LQL_HDRSIZE;
|
|
|
|
if (curqlevel->numvar)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
lrptr = LQL_FIRST(cur);
|
|
|
|
lptr = GETVAR(curqlevel);
|
2002-09-04 22:31:48 +02:00
|
|
|
while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
|
|
|
|
{
|
2002-08-04 07:02:50 +02:00
|
|
|
cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
|
2002-09-04 22:31:48 +02:00
|
|
|
lrptr->len = lptr->len;
|
2002-07-30 18:40:34 +02:00
|
|
|
lrptr->flag = lptr->flag;
|
2005-09-24 21:14:05 +02:00
|
|
|
lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
|
2002-09-04 22:31:48 +02:00
|
|
|
memcpy(lrptr->name, lptr->start, lptr->len);
|
2002-07-30 18:40:34 +02:00
|
|
|
lptr++;
|
2002-09-04 22:31:48 +02:00
|
|
|
lrptr = LVAR_NEXT(lrptr);
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
pfree(GETVAR(curqlevel));
|
|
|
|
if (cur->numvar > 1 || cur->flag != 0)
|
|
|
|
wasbad = true;
|
|
|
|
else if (wasbad == false)
|
|
|
|
(result->firstgood)++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wasbad = true;
|
2002-08-04 07:02:50 +02:00
|
|
|
curqlevel = NEXTLEV(curqlevel);
|
2002-07-30 18:40:34 +02:00
|
|
|
cur = LQL_NEXT(cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(tmpql);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
Datum
|
|
|
|
lquery_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2017-09-18 21:21:23 +02:00
|
|
|
lquery *in = PG_GETARG_LQUERY_P(0);
|
2002-09-04 22:31:48 +02:00
|
|
|
char *buf,
|
|
|
|
*ptr;
|
|
|
|
int i,
|
|
|
|
j,
|
2003-12-17 21:15:41 +01:00
|
|
|
totallen = 1;
|
2002-09-04 22:31:48 +02:00
|
|
|
lquery_level *curqlevel;
|
|
|
|
lquery_variant *curtlevel;
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
curqlevel = LQUERY_FIRST(in);
|
2002-09-04 22:31:48 +02:00
|
|
|
for (i = 0; i < in->numlevel; i++)
|
|
|
|
{
|
2003-12-17 21:15:41 +01:00
|
|
|
totallen++;
|
2002-09-04 22:31:48 +02:00
|
|
|
if (curqlevel->numvar)
|
2003-12-17 21:15:41 +01:00
|
|
|
totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
|
2002-07-30 18:40:34 +02:00
|
|
|
else
|
2003-12-17 21:15:41 +01:00
|
|
|
totallen += 2 * 11 + 4;
|
2002-07-30 18:40:34 +02:00
|
|
|
curqlevel = LQL_NEXT(curqlevel);
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
|
|
ptr = buf = (char *) palloc(totallen);
|
2002-07-30 18:40:34 +02:00
|
|
|
curqlevel = LQUERY_FIRST(in);
|
2002-09-04 22:31:48 +02:00
|
|
|
for (i = 0; i < in->numlevel; i++)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '.';
|
|
|
|
ptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
if (curqlevel->numvar)
|
|
|
|
{
|
|
|
|
if (curqlevel->flag & LQL_NOT)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '!';
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
curtlevel = LQL_FIRST(curqlevel);
|
2002-09-04 22:31:48 +02:00
|
|
|
for (j = 0; j < curqlevel->numvar; j++)
|
|
|
|
{
|
|
|
|
if (j != 0)
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '|';
|
|
|
|
ptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
memcpy(ptr, curtlevel->name, curtlevel->len);
|
|
|
|
ptr += curtlevel->len;
|
2006-03-01 07:30:32 +01:00
|
|
|
if ((curtlevel->flag & LVAR_SUBLEXEME))
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '%';
|
|
|
|
ptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
if ((curtlevel->flag & LVAR_INCASE))
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '@';
|
|
|
|
ptr++;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
if ((curtlevel->flag & LVAR_ANYEND))
|
|
|
|
{
|
2002-07-30 18:40:34 +02:00
|
|
|
*ptr = '*';
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
curtlevel = LVAR_NEXT(curtlevel);
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (curqlevel->low == curqlevel->high)
|
|
|
|
{
|
|
|
|
sprintf(ptr, "*{%d}", curqlevel->low);
|
|
|
|
}
|
|
|
|
else if (curqlevel->low == 0)
|
|
|
|
{
|
2020-03-28 22:09:51 +01:00
|
|
|
if (curqlevel->high == LTREE_MAX_LEVELS)
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
*ptr = '*';
|
|
|
|
*(ptr + 1) = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sprintf(ptr, "*{,%d}", curqlevel->high);
|
|
|
|
}
|
2020-03-28 22:09:51 +01:00
|
|
|
else if (curqlevel->high == LTREE_MAX_LEVELS)
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
sprintf(ptr, "*{%d,}", curqlevel->low);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
|
|
|
|
ptr = strchr(ptr, '\0');
|
2002-07-30 18:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
curqlevel = LQL_NEXT(curqlevel);
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
*ptr = '\0';
|
|
|
|
PG_FREE_IF_COPY(in, 0);
|
2002-07-30 18:40:34 +02:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(buf);
|
|
|
|
}
|