ltree support for multibyte encodings. Patch was made by
laser <laserlist@pgsqldb.com> with some editorization by me.
This commit is contained in:
parent
995fb74202
commit
8eee65c996
@ -1,13 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* op function for ltree and lquery
|
* op function for ltree and lquery
|
||||||
* Teodor Sigaev <teodor@stack.net>
|
* Teodor Sigaev <teodor@stack.net>
|
||||||
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.12 2008/05/12 00:00:42 alvherre Exp $
|
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.13 2008/06/30 18:30:48 teodor Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
|
#include "utils/formatting.h"
|
||||||
#include "ltree.h"
|
#include "ltree.h"
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(ltq_regex);
|
PG_FUNCTION_INFO_V1(ltq_regex);
|
||||||
@ -32,23 +33,24 @@ static char *
|
|||||||
getlexeme(char *start, char *end, int *len)
|
getlexeme(char *start, char *end, int *len)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
int charlen;
|
||||||
|
|
||||||
while (start < end && *start == '_')
|
while (start < end && (charlen = pg_mblen(start)) == 1 && t_iseq(start,'_') )
|
||||||
start++;
|
start += charlen;
|
||||||
|
|
||||||
ptr = start;
|
ptr = start;
|
||||||
if (ptr == end)
|
if (ptr >= end)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
while (ptr < end && *ptr != '_')
|
while (ptr < end && !( (charlen = pg_mblen(ptr)) == 1 && t_iseq(ptr, '_') ) )
|
||||||
ptr++;
|
ptr += charlen;
|
||||||
|
|
||||||
*len = ptr - start;
|
*len = ptr - start;
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
|
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
|
||||||
{
|
{
|
||||||
char *endt = t->name + t->len;
|
char *endt = t->name + t->len;
|
||||||
char *endq = qn + len;
|
char *endq = qn + len;
|
||||||
@ -85,6 +87,21 @@ bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ltree_strncasecmp(const char *a, const char *b, size_t s)
|
||||||
|
{
|
||||||
|
char *al = str_tolower(a, s);
|
||||||
|
char *bl = str_tolower(b, s);
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = strncmp(al, bl,s);
|
||||||
|
|
||||||
|
pfree(al);
|
||||||
|
pfree(bl);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
checkLevel(lquery_level * curq, ltree_level * curt)
|
checkLevel(lquery_level * curq, ltree_level * curt)
|
||||||
{
|
{
|
||||||
@ -94,7 +111,7 @@ checkLevel(lquery_level * curq, ltree_level * curt)
|
|||||||
|
|
||||||
for (i = 0; i < curq->numvar; i++)
|
for (i = 0; i < curq->numvar; i++)
|
||||||
{
|
{
|
||||||
cmpptr = (curvar->flag & LVAR_INCASE) ? pg_strncasecmp : strncmp;
|
cmpptr = (curvar->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
|
||||||
|
|
||||||
if (curvar->flag & LVAR_SUBLEXEME)
|
if (curvar->flag & LVAR_SUBLEXEME)
|
||||||
{
|
{
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
/* $PostgreSQL: pgsql/contrib/ltree/ltree.h,v 1.20 2008/05/12 00:00:42 alvherre Exp $ */
|
/* $PostgreSQL: pgsql/contrib/ltree/ltree.h,v 1.21 2008/06/30 18:30:48 teodor Exp $ */
|
||||||
|
|
||||||
#ifndef __LTREE_H__
|
#ifndef __LTREE_H__
|
||||||
#define __LTREE_H__
|
#define __LTREE_H__
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
#include "tsearch/ts_locale.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8 len;
|
uint16 len;
|
||||||
char name[1];
|
char name[1];
|
||||||
} ltree_level;
|
} ltree_level;
|
||||||
|
|
||||||
#define LEVEL_HDRSIZE (sizeof(uint8))
|
#define LEVEL_HDRSIZE (offsetof(ltree_level,name))
|
||||||
#define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + MAXALIGN(((ltree_level*)(x))->len + LEVEL_HDRSIZE) ) )
|
#define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + MAXALIGN(((ltree_level*)(x))->len + LEVEL_HDRSIZE) ) )
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -21,7 +23,7 @@ typedef struct
|
|||||||
char data[1];
|
char data[1];
|
||||||
} ltree;
|
} ltree;
|
||||||
|
|
||||||
#define LTREE_HDRSIZE MAXALIGN(VARHDRSZ + sizeof(uint16))
|
#define LTREE_HDRSIZE MAXALIGN( offsetof(ltree, data) )
|
||||||
#define LTREE_FIRST(x) ( (ltree_level*)( ((char*)(x))+LTREE_HDRSIZE ) )
|
#define LTREE_FIRST(x) ( (ltree_level*)( ((char*)(x))+LTREE_HDRSIZE ) )
|
||||||
|
|
||||||
|
|
||||||
@ -30,12 +32,12 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int4 val;
|
int4 val;
|
||||||
uint8 len;
|
uint16 len;
|
||||||
uint8 flag;
|
uint8 flag;
|
||||||
char name[1];
|
char name[1];
|
||||||
} lquery_variant;
|
} lquery_variant;
|
||||||
|
|
||||||
#define LVAR_HDRSIZE MAXALIGN(sizeof(uint8)*2 + sizeof(int4))
|
#define LVAR_HDRSIZE MAXALIGN(offsetof(lquery_variant, name))
|
||||||
#define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) + MAXALIGN(((lquery_variant*)(x))->len) + LVAR_HDRSIZE ) )
|
#define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) + MAXALIGN(((lquery_variant*)(x))->len) + LVAR_HDRSIZE ) )
|
||||||
|
|
||||||
#define LVAR_ANYEND 0x01
|
#define LVAR_ANYEND 0x01
|
||||||
@ -52,7 +54,7 @@ typedef struct
|
|||||||
char variants[1];
|
char variants[1];
|
||||||
} lquery_level;
|
} lquery_level;
|
||||||
|
|
||||||
#define LQL_HDRSIZE MAXALIGN( sizeof(uint16)*5 )
|
#define LQL_HDRSIZE MAXALIGN( offsetof(lquery_level,variants) )
|
||||||
#define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) + MAXALIGN(((lquery_level*)(x))->totallen) ) )
|
#define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) + MAXALIGN(((lquery_level*)(x))->totallen) ) )
|
||||||
#define LQL_FIRST(x) ( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) )
|
#define LQL_FIRST(x) ( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) )
|
||||||
|
|
||||||
@ -73,12 +75,12 @@ typedef struct
|
|||||||
char data[1];
|
char data[1];
|
||||||
} lquery;
|
} lquery;
|
||||||
|
|
||||||
#define LQUERY_HDRSIZE MAXALIGN(VARHDRSZ + 3*sizeof(uint16))
|
#define LQUERY_HDRSIZE MAXALIGN( offsetof(lquery, data) )
|
||||||
#define LQUERY_FIRST(x) ( (lquery_level*)( ((char*)(x))+LQUERY_HDRSIZE ) )
|
#define LQUERY_FIRST(x) ( (lquery_level*)( ((char*)(x))+LQUERY_HDRSIZE ) )
|
||||||
|
|
||||||
#define LQUERY_HASNOT 0x01
|
#define LQUERY_HASNOT 0x01
|
||||||
|
|
||||||
#define ISALNUM(x) ( isalnum((unsigned char)(x)) || (x) == '_' )
|
#define ISALNUM(x) ( t_isalpha(x) || t_isdigit(x) || ( pg_mblen(x) == 1 && t_iseq((x), '_') ) )
|
||||||
|
|
||||||
/* full text query */
|
/* full text query */
|
||||||
|
|
||||||
@ -159,6 +161,7 @@ bool inner_isparent(const ltree * c, const ltree * p);
|
|||||||
bool compare_subnode(ltree_level * t, char *q, int len,
|
bool compare_subnode(ltree_level * t, char *q, int len,
|
||||||
int (*cmpptr) (const char *, const char *, size_t), bool anyend);
|
int (*cmpptr) (const char *, const char *, size_t), bool anyend);
|
||||||
ltree *lca_inner(ltree ** a, int len);
|
ltree *lca_inner(ltree ** a, int len);
|
||||||
|
int ltree_strncasecmp(const char *a, const char *b, size_t s);
|
||||||
|
|
||||||
#define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
|
#define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
|
||||||
#define PG_GETARG_LTREE_COPY(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x))))
|
#define PG_GETARG_LTREE_COPY(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x))))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* in/out function for ltree and lquery
|
* in/out function for ltree and lquery
|
||||||
* Teodor Sigaev <teodor@stack.net>
|
* Teodor Sigaev <teodor@stack.net>
|
||||||
* $PostgreSQL: pgsql/contrib/ltree/ltree_io.c,v 1.16 2008/05/12 00:00:43 alvherre Exp $
|
* $PostgreSQL: pgsql/contrib/ltree/ltree_io.c,v 1.17 2008/06/30 18:30:48 teodor Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -25,15 +25,16 @@ Datum lquery_out(PG_FUNCTION_ARGS);
|
|||||||
|
|
||||||
#define UNCHAR ereport(ERROR, \
|
#define UNCHAR ereport(ERROR, \
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR), \
|
(errcode(ERRCODE_SYNTAX_ERROR), \
|
||||||
errmsg("syntax error at position %d near \"%c\"", \
|
errmsg("syntax error at position %d", \
|
||||||
(int)(ptr-buf), *ptr)));
|
pos)));
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *start;
|
char *start;
|
||||||
int len;
|
int len; /* length in bytes */
|
||||||
int flag;
|
int flag;
|
||||||
|
int wlen; /* length in characters */
|
||||||
} nodeitem;
|
} nodeitem;
|
||||||
|
|
||||||
#define LTPRS_WAITNAME 0
|
#define LTPRS_WAITNAME 0
|
||||||
@ -51,24 +52,30 @@ ltree_in(PG_FUNCTION_ARGS)
|
|||||||
int state = LTPRS_WAITNAME;
|
int state = LTPRS_WAITNAME;
|
||||||
ltree *result;
|
ltree *result;
|
||||||
ltree_level *curlevel;
|
ltree_level *curlevel;
|
||||||
|
int charlen;
|
||||||
|
int pos=0;
|
||||||
|
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
if (*ptr == '.')
|
charlen = pg_mblen(ptr);
|
||||||
|
if ( charlen == 1 && t_iseq(ptr, '.') )
|
||||||
num++;
|
num++;
|
||||||
ptr++;
|
ptr+=charlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
|
list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
|
charlen = pg_mblen(ptr);
|
||||||
|
|
||||||
if (state == LTPRS_WAITNAME)
|
if (state == LTPRS_WAITNAME)
|
||||||
{
|
{
|
||||||
if (ISALNUM(*ptr))
|
if (ISALNUM(ptr))
|
||||||
{
|
{
|
||||||
lptr->start = ptr;
|
lptr->start = ptr;
|
||||||
|
lptr->wlen = 0;
|
||||||
state = LTPRS_WAITDELIM;
|
state = LTPRS_WAITDELIM;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -76,40 +83,43 @@ ltree_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LTPRS_WAITDELIM)
|
else if (state == LTPRS_WAITDELIM)
|
||||||
{
|
{
|
||||||
if (*ptr == '.')
|
if ( charlen == 1 && t_iseq(ptr, '.') )
|
||||||
{
|
{
|
||||||
lptr->len = ptr - lptr->start;
|
lptr->len = ptr - lptr->start;
|
||||||
if (lptr->len > 255)
|
if (lptr->wlen > 255)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NAME_TOO_LONG),
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||||
errmsg("name of level is too long"),
|
errmsg("name of level is too long"),
|
||||||
errdetail("Name length is %d, must "
|
errdetail("Name length is %d, must "
|
||||||
"be < 256, in position %d.",
|
"be < 256, in position %d.",
|
||||||
lptr->len, (int) (lptr->start - buf))));
|
lptr->wlen, pos)));
|
||||||
|
|
||||||
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
||||||
lptr++;
|
lptr++;
|
||||||
state = LTPRS_WAITNAME;
|
state = LTPRS_WAITNAME;
|
||||||
}
|
}
|
||||||
else if (!ISALNUM(*ptr))
|
else if (!ISALNUM(ptr))
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "internal error in parser");
|
elog(ERROR, "internal error in parser");
|
||||||
ptr++;
|
|
||||||
|
ptr+=charlen;
|
||||||
|
lptr->wlen++;
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == LTPRS_WAITDELIM)
|
if (state == LTPRS_WAITDELIM)
|
||||||
{
|
{
|
||||||
lptr->len = ptr - lptr->start;
|
lptr->len = ptr - lptr->start;
|
||||||
if (lptr->len > 255)
|
if (lptr->wlen > 255)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NAME_TOO_LONG),
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||||
errmsg("name of level is too long"),
|
errmsg("name of level is too long"),
|
||||||
errdetail("Name length is %d, must "
|
errdetail("Name length is %d, must "
|
||||||
"be < 256, in position %d.",
|
"be < 256, in position %d.",
|
||||||
lptr->len, (int) (lptr->start - buf))));
|
lptr->wlen, pos)));
|
||||||
|
|
||||||
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
||||||
lptr++;
|
lptr++;
|
||||||
@ -127,7 +137,7 @@ ltree_in(PG_FUNCTION_ARGS)
|
|||||||
lptr = list;
|
lptr = list;
|
||||||
while (lptr - list < result->numlevel)
|
while (lptr - list < result->numlevel)
|
||||||
{
|
{
|
||||||
curlevel->len = (uint8) lptr->len;
|
curlevel->len = (uint16) lptr->len;
|
||||||
memcpy(curlevel->name, lptr->start, lptr->len);
|
memcpy(curlevel->name, lptr->start, lptr->len);
|
||||||
curlevel = LEVEL_NEXT(curlevel);
|
curlevel = LEVEL_NEXT(curlevel);
|
||||||
lptr++;
|
lptr++;
|
||||||
@ -198,15 +208,23 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
lquery_variant *lrptr = NULL;
|
lquery_variant *lrptr = NULL;
|
||||||
bool hasnot = false;
|
bool hasnot = false;
|
||||||
bool wasbad = false;
|
bool wasbad = false;
|
||||||
|
int charlen;
|
||||||
|
int pos=0;
|
||||||
|
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
if (*ptr == '.')
|
charlen = pg_mblen(ptr);
|
||||||
|
|
||||||
|
if ( charlen == 1 )
|
||||||
|
{
|
||||||
|
if (t_iseq(ptr, '.'))
|
||||||
num++;
|
num++;
|
||||||
else if (*ptr == '|')
|
else if (t_iseq(ptr, '|'))
|
||||||
numOR++;
|
numOR++;
|
||||||
ptr++;
|
}
|
||||||
|
|
||||||
|
ptr+=charlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
num++;
|
num++;
|
||||||
@ -214,16 +232,18 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
ptr = buf;
|
ptr = buf;
|
||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
|
charlen = pg_mblen(ptr);
|
||||||
|
|
||||||
if (state == LQPRS_WAITLEVEL)
|
if (state == LQPRS_WAITLEVEL)
|
||||||
{
|
{
|
||||||
if (ISALNUM(*ptr))
|
if (ISALNUM(ptr))
|
||||||
{
|
{
|
||||||
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
||||||
lptr->start = ptr;
|
lptr->start = ptr;
|
||||||
state = LQPRS_WAITDELIM;
|
state = LQPRS_WAITDELIM;
|
||||||
curqlevel->numvar = 1;
|
curqlevel->numvar = 1;
|
||||||
}
|
}
|
||||||
else if (*ptr == '!')
|
else if (charlen==1 && t_iseq(ptr, '!'))
|
||||||
{
|
{
|
||||||
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
|
||||||
lptr->start = ptr + 1;
|
lptr->start = ptr + 1;
|
||||||
@ -232,14 +252,14 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
curqlevel->flag |= LQL_NOT;
|
curqlevel->flag |= LQL_NOT;
|
||||||
hasnot = true;
|
hasnot = true;
|
||||||
}
|
}
|
||||||
else if (*ptr == '*')
|
else if (charlen==1 && t_iseq(ptr, '*'))
|
||||||
state = LQPRS_WAITOPEN;
|
state = LQPRS_WAITOPEN;
|
||||||
else
|
else
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITVAR)
|
else if (state == LQPRS_WAITVAR)
|
||||||
{
|
{
|
||||||
if (ISALNUM(*ptr))
|
if (ISALNUM(ptr))
|
||||||
{
|
{
|
||||||
lptr++;
|
lptr++;
|
||||||
lptr->start = ptr;
|
lptr->start = ptr;
|
||||||
@ -251,61 +271,61 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITDELIM)
|
else if (state == LQPRS_WAITDELIM)
|
||||||
{
|
{
|
||||||
if (*ptr == '@')
|
if (charlen==1 && t_iseq(ptr, '@'))
|
||||||
{
|
{
|
||||||
if (lptr->start == ptr)
|
if (lptr->start == ptr)
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
lptr->flag |= LVAR_INCASE;
|
lptr->flag |= LVAR_INCASE;
|
||||||
curqlevel->flag |= LVAR_INCASE;
|
curqlevel->flag |= LVAR_INCASE;
|
||||||
}
|
}
|
||||||
else if (*ptr == '*')
|
else if (charlen==1 && t_iseq(ptr, '*'))
|
||||||
{
|
{
|
||||||
if (lptr->start == ptr)
|
if (lptr->start == ptr)
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
lptr->flag |= LVAR_ANYEND;
|
lptr->flag |= LVAR_ANYEND;
|
||||||
curqlevel->flag |= LVAR_ANYEND;
|
curqlevel->flag |= LVAR_ANYEND;
|
||||||
}
|
}
|
||||||
else if (*ptr == '%')
|
else if (charlen==1 && t_iseq(ptr, '%'))
|
||||||
{
|
{
|
||||||
if (lptr->start == ptr)
|
if (lptr->start == ptr)
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
lptr->flag |= LVAR_SUBLEXEME;
|
lptr->flag |= LVAR_SUBLEXEME;
|
||||||
curqlevel->flag |= LVAR_SUBLEXEME;
|
curqlevel->flag |= LVAR_SUBLEXEME;
|
||||||
}
|
}
|
||||||
else if (*ptr == '|')
|
else if (charlen==1 && t_iseq(ptr, '|'))
|
||||||
{
|
{
|
||||||
lptr->len = ptr - lptr->start -
|
lptr->len = ptr - lptr->start -
|
||||||
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
||||||
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
||||||
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
||||||
if (lptr->len > 255)
|
if (lptr->wlen > 255)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NAME_TOO_LONG),
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||||
errmsg("name of level is too long"),
|
errmsg("name of level is too long"),
|
||||||
errdetail("Name length is %d, must "
|
errdetail("Name length is %d, must "
|
||||||
"be < 256, in position %d.",
|
"be < 256, in position %d.",
|
||||||
lptr->len, (int) (lptr->start - buf))));
|
lptr->wlen, pos)));
|
||||||
|
|
||||||
state = LQPRS_WAITVAR;
|
state = LQPRS_WAITVAR;
|
||||||
}
|
}
|
||||||
else if (*ptr == '.')
|
else if (charlen==1 && t_iseq(ptr, '.'))
|
||||||
{
|
{
|
||||||
lptr->len = ptr - lptr->start -
|
lptr->len = ptr - lptr->start -
|
||||||
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
|
||||||
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
((lptr->flag & LVAR_INCASE) ? 1 : 0) -
|
||||||
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
((lptr->flag & LVAR_ANYEND) ? 1 : 0);
|
||||||
if (lptr->len > 255)
|
if (lptr->wlen > 255)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NAME_TOO_LONG),
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||||
errmsg("name of level is too long"),
|
errmsg("name of level is too long"),
|
||||||
errdetail("Name length is %d, must "
|
errdetail("Name length is %d, must "
|
||||||
"be < 256, in position %d.",
|
"be < 256, in position %d.",
|
||||||
lptr->len, (int) (lptr->start - buf))));
|
lptr->wlen, pos)));
|
||||||
|
|
||||||
state = LQPRS_WAITLEVEL;
|
state = LQPRS_WAITLEVEL;
|
||||||
curqlevel = NEXTLEV(curqlevel);
|
curqlevel = NEXTLEV(curqlevel);
|
||||||
}
|
}
|
||||||
else if (ISALNUM(*ptr))
|
else if (ISALNUM(ptr))
|
||||||
{
|
{
|
||||||
if (lptr->flag)
|
if (lptr->flag)
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
@ -315,9 +335,9 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITOPEN)
|
else if (state == LQPRS_WAITOPEN)
|
||||||
{
|
{
|
||||||
if (*ptr == '{')
|
if (charlen==1 && t_iseq(ptr, '{'))
|
||||||
state = LQPRS_WAITFNUM;
|
state = LQPRS_WAITFNUM;
|
||||||
else if (*ptr == '.')
|
else if (charlen==1 && t_iseq(ptr, '.'))
|
||||||
{
|
{
|
||||||
curqlevel->low = 0;
|
curqlevel->low = 0;
|
||||||
curqlevel->high = 0xffff;
|
curqlevel->high = 0xffff;
|
||||||
@ -329,9 +349,9 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITFNUM)
|
else if (state == LQPRS_WAITFNUM)
|
||||||
{
|
{
|
||||||
if (*ptr == ',')
|
if (charlen==1 && t_iseq(ptr, ','))
|
||||||
state = LQPRS_WAITSNUM;
|
state = LQPRS_WAITSNUM;
|
||||||
else if (isdigit((unsigned char) *ptr))
|
else if (t_isdigit(ptr))
|
||||||
{
|
{
|
||||||
curqlevel->low = atoi(ptr);
|
curqlevel->low = atoi(ptr);
|
||||||
state = LQPRS_WAITND;
|
state = LQPRS_WAITND;
|
||||||
@ -341,12 +361,12 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITSNUM)
|
else if (state == LQPRS_WAITSNUM)
|
||||||
{
|
{
|
||||||
if (isdigit((unsigned char) *ptr))
|
if (t_isdigit(ptr))
|
||||||
{
|
{
|
||||||
curqlevel->high = atoi(ptr);
|
curqlevel->high = atoi(ptr);
|
||||||
state = LQPRS_WAITCLOSE;
|
state = LQPRS_WAITCLOSE;
|
||||||
}
|
}
|
||||||
else if (*ptr == '}')
|
else if (charlen==1 && t_iseq(ptr, '}'))
|
||||||
{
|
{
|
||||||
curqlevel->high = 0xffff;
|
curqlevel->high = 0xffff;
|
||||||
state = LQPRS_WAITEND;
|
state = LQPRS_WAITEND;
|
||||||
@ -356,26 +376,26 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITCLOSE)
|
else if (state == LQPRS_WAITCLOSE)
|
||||||
{
|
{
|
||||||
if (*ptr == '}')
|
if (charlen==1 && t_iseq(ptr, '}'))
|
||||||
state = LQPRS_WAITEND;
|
state = LQPRS_WAITEND;
|
||||||
else if (!isdigit((unsigned char) *ptr))
|
else if (!t_isdigit(ptr))
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITND)
|
else if (state == LQPRS_WAITND)
|
||||||
{
|
{
|
||||||
if (*ptr == '}')
|
if (charlen==1 && t_iseq(ptr, '}'))
|
||||||
{
|
{
|
||||||
curqlevel->high = curqlevel->low;
|
curqlevel->high = curqlevel->low;
|
||||||
state = LQPRS_WAITEND;
|
state = LQPRS_WAITEND;
|
||||||
}
|
}
|
||||||
else if (*ptr == ',')
|
else if (charlen==1 && t_iseq(ptr, ','))
|
||||||
state = LQPRS_WAITSNUM;
|
state = LQPRS_WAITSNUM;
|
||||||
else if (!isdigit((unsigned char) *ptr))
|
else if (!t_isdigit(ptr))
|
||||||
UNCHAR;
|
UNCHAR;
|
||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITEND)
|
else if (state == LQPRS_WAITEND)
|
||||||
{
|
{
|
||||||
if (*ptr == '.')
|
if (charlen==1 && t_iseq(ptr, '.'))
|
||||||
{
|
{
|
||||||
state = LQPRS_WAITLEVEL;
|
state = LQPRS_WAITLEVEL;
|
||||||
curqlevel = NEXTLEV(curqlevel);
|
curqlevel = NEXTLEV(curqlevel);
|
||||||
@ -386,7 +406,11 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "internal error in parser");
|
elog(ERROR, "internal error in parser");
|
||||||
ptr++;
|
|
||||||
|
ptr+=charlen;
|
||||||
|
if ( state == LQPRS_WAITDELIM )
|
||||||
|
lptr->wlen++;
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == LQPRS_WAITDELIM)
|
if (state == LQPRS_WAITDELIM)
|
||||||
@ -407,13 +431,13 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||||||
errmsg("syntax error"),
|
errmsg("syntax error"),
|
||||||
errdetail("Unexpected end of line.")));
|
errdetail("Unexpected end of line.")));
|
||||||
|
|
||||||
if (lptr->len > 255)
|
if (lptr->wlen > 255)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NAME_TOO_LONG),
|
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||||
errmsg("name of level is too long"),
|
errmsg("name of level is too long"),
|
||||||
errdetail("Name length is %d, must "
|
errdetail("Name length is %d, must "
|
||||||
"be < 256, in position %d.",
|
"be < 256, in position %d.",
|
||||||
lptr->len, (int) (lptr->start - buf))));
|
lptr->wlen, pos)));
|
||||||
}
|
}
|
||||||
else if (state == LQPRS_WAITOPEN)
|
else if (state == LQPRS_WAITOPEN)
|
||||||
curqlevel->high = 0xffff;
|
curqlevel->high = 0xffff;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* txtquery io
|
* txtquery io
|
||||||
* Teodor Sigaev <teodor@stack.net>
|
* Teodor Sigaev <teodor@stack.net>
|
||||||
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_io.c,v 1.15 2008/05/12 00:00:43 alvherre Exp $
|
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_io.c,v 1.16 2008/06/30 18:30:48 teodor Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -59,49 +59,53 @@ typedef struct
|
|||||||
static int4
|
static int4
|
||||||
gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, uint16 *flag)
|
gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, uint16 *flag)
|
||||||
{
|
{
|
||||||
while (1)
|
int charlen;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
{
|
{
|
||||||
|
charlen = pg_mblen(state->buf);
|
||||||
|
|
||||||
switch (state->state)
|
switch (state->state)
|
||||||
{
|
{
|
||||||
case WAITOPERAND:
|
case WAITOPERAND:
|
||||||
if (*(state->buf) == '!')
|
if (charlen==1 && t_iseq(state->buf, '!'))
|
||||||
{
|
{
|
||||||
(state->buf)++;
|
(state->buf)++;
|
||||||
*val = (int4) '!';
|
*val = (int4) '!';
|
||||||
return OPR;
|
return OPR;
|
||||||
}
|
}
|
||||||
else if (*(state->buf) == '(')
|
else if (charlen==1 && t_iseq(state->buf, '('))
|
||||||
{
|
{
|
||||||
state->count++;
|
state->count++;
|
||||||
(state->buf)++;
|
(state->buf)++;
|
||||||
return OPEN;
|
return OPEN;
|
||||||
}
|
}
|
||||||
else if (ISALNUM(*(state->buf)))
|
else if (ISALNUM(state->buf))
|
||||||
{
|
{
|
||||||
state->state = INOPERAND;
|
state->state = INOPERAND;
|
||||||
*strval = state->buf;
|
*strval = state->buf;
|
||||||
*lenval = 1;
|
*lenval = charlen;
|
||||||
*flag = 0;
|
*flag = 0;
|
||||||
}
|
}
|
||||||
else if (!isspace((unsigned char) *(state->buf)))
|
else if (!t_isspace(state->buf))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("operand syntax error")));
|
errmsg("operand syntax error")));
|
||||||
break;
|
break;
|
||||||
case INOPERAND:
|
case INOPERAND:
|
||||||
if (ISALNUM(*(state->buf)))
|
if (ISALNUM(state->buf))
|
||||||
{
|
{
|
||||||
if (*flag)
|
if (*flag)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("modificators syntax error")));
|
errmsg("modificators syntax error")));
|
||||||
(*lenval)++;
|
*lenval += charlen;
|
||||||
}
|
}
|
||||||
else if (*(state->buf) == '%')
|
else if (charlen==1 && t_iseq(state->buf, '%'))
|
||||||
*flag |= LVAR_SUBLEXEME;
|
*flag |= LVAR_SUBLEXEME;
|
||||||
else if (*(state->buf) == '@')
|
else if (charlen==1 && t_iseq(state->buf, '@'))
|
||||||
*flag |= LVAR_INCASE;
|
*flag |= LVAR_INCASE;
|
||||||
else if (*(state->buf) == '*')
|
else if (charlen==1 && t_iseq(state->buf, '*'))
|
||||||
*flag |= LVAR_ANYEND;
|
*flag |= LVAR_ANYEND;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -110,14 +114,14 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, uint1
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WAITOPERATOR:
|
case WAITOPERATOR:
|
||||||
if (*(state->buf) == '&' || *(state->buf) == '|')
|
if (charlen==1 && ( t_iseq(state->buf, '&') || t_iseq(state->buf, '|') ))
|
||||||
{
|
{
|
||||||
state->state = WAITOPERAND;
|
state->state = WAITOPERAND;
|
||||||
*val = (int4) *(state->buf);
|
*val = (int4) *(state->buf);
|
||||||
(state->buf)++;
|
(state->buf)++;
|
||||||
return OPR;
|
return OPR;
|
||||||
}
|
}
|
||||||
else if (*(state->buf) == ')')
|
else if (charlen==1 && t_iseq(state->buf, ')'))
|
||||||
{
|
{
|
||||||
(state->buf)++;
|
(state->buf)++;
|
||||||
state->count--;
|
state->count--;
|
||||||
@ -125,14 +129,15 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, uint1
|
|||||||
}
|
}
|
||||||
else if (*(state->buf) == '\0')
|
else if (*(state->buf) == '\0')
|
||||||
return (state->count) ? ERR : END;
|
return (state->count) ? ERR : END;
|
||||||
else if (*(state->buf) != ' ')
|
else if (charlen==1 && !t_iseq(state->buf, ' '))
|
||||||
return ERR;
|
return ERR;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ERR;
|
return ERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(state->buf)++;
|
|
||||||
|
state->buf += charlen;
|
||||||
}
|
}
|
||||||
return END;
|
return END;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* txtquery operations with ltree
|
* txtquery operations with ltree
|
||||||
* Teodor Sigaev <teodor@stack.net>
|
* Teodor Sigaev <teodor@stack.net>
|
||||||
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_op.c,v 1.8 2008/05/12 00:00:43 alvherre Exp $
|
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_op.c,v 1.9 2008/06/30 18:30:48 teodor Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ checkcondition_str(void *checkval, ITEM * val)
|
|||||||
char *op = ((CHKVAL *) checkval)->operand + val->distance;
|
char *op = ((CHKVAL *) checkval)->operand + val->distance;
|
||||||
int (*cmpptr) (const char *, const char *, size_t);
|
int (*cmpptr) (const char *, const char *, size_t);
|
||||||
|
|
||||||
cmpptr = (val->flag & LVAR_INCASE) ? pg_strncasecmp : strncmp;
|
cmpptr = (val->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
|
||||||
while (tlen > 0)
|
while (tlen > 0)
|
||||||
{
|
{
|
||||||
if (val->flag & LVAR_SUBLEXEME)
|
if (val->flag & LVAR_SUBLEXEME)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user