|
|
|
@ -24,8 +24,8 @@ typedef struct |
|
|
|
|
#define LTPRS_WAITNAME 0 |
|
|
|
|
#define LTPRS_WAITDELIM 1 |
|
|
|
|
|
|
|
|
|
static void finish_nodeitem(nodeitem *lptr, const char *ptr, |
|
|
|
|
bool is_lquery, int pos); |
|
|
|
|
static bool finish_nodeitem(nodeitem *lptr, const char *ptr, |
|
|
|
|
bool is_lquery, int pos, struct Node *escontext); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -33,7 +33,7 @@ static void finish_nodeitem(nodeitem *lptr, const char *ptr, |
|
|
|
|
* returns an ltree |
|
|
|
|
*/ |
|
|
|
|
static ltree * |
|
|
|
|
parse_ltree(const char *buf) |
|
|
|
|
parse_ltree(const char *buf, struct Node *escontext) |
|
|
|
|
{ |
|
|
|
|
const char *ptr; |
|
|
|
|
nodeitem *list, |
|
|
|
@ -46,7 +46,7 @@ parse_ltree(const char *buf) |
|
|
|
|
int charlen; |
|
|
|
|
int pos = 1; /* character position for error messages */ |
|
|
|
|
|
|
|
|
|
#define UNCHAR ereport(ERROR, \ |
|
|
|
|
#define UNCHAR ereturn(escontext, NULL,\ |
|
|
|
|
errcode(ERRCODE_SYNTAX_ERROR), \
|
|
|
|
|
errmsg("ltree syntax error at character %d", \
|
|
|
|
|
pos)) |
|
|
|
@ -61,7 +61,7 @@ parse_ltree(const char *buf) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (num + 1 > LTREE_MAX_LEVELS) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
|
|
|
|
errmsg("number of ltree labels (%d) exceeds the maximum allowed (%d)", |
|
|
|
|
num + 1, LTREE_MAX_LEVELS))); |
|
|
|
@ -86,7 +86,8 @@ parse_ltree(const char *buf) |
|
|
|
|
case LTPRS_WAITDELIM: |
|
|
|
|
if (t_iseq(ptr, '.')) |
|
|
|
|
{ |
|
|
|
|
finish_nodeitem(lptr, ptr, false, pos); |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, false, pos, escontext)) |
|
|
|
|
return NULL; |
|
|
|
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); |
|
|
|
|
lptr++; |
|
|
|
|
state = LTPRS_WAITNAME; |
|
|
|
@ -105,12 +106,13 @@ parse_ltree(const char *buf) |
|
|
|
|
|
|
|
|
|
if (state == LTPRS_WAITDELIM) |
|
|
|
|
{ |
|
|
|
|
finish_nodeitem(lptr, ptr, false, pos); |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, false, pos, escontext)) |
|
|
|
|
return NULL; |
|
|
|
|
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); |
|
|
|
|
lptr++; |
|
|
|
|
} |
|
|
|
|
else if (!(state == LTPRS_WAITNAME && lptr == list)) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), |
|
|
|
|
errmsg("ltree syntax error"), |
|
|
|
|
errdetail("Unexpected end of input."))); |
|
|
|
@ -172,8 +174,12 @@ Datum |
|
|
|
|
ltree_in(PG_FUNCTION_ARGS) |
|
|
|
|
{ |
|
|
|
|
char *buf = (char *) PG_GETARG_POINTER(0); |
|
|
|
|
ltree *res; |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(parse_ltree(buf)); |
|
|
|
|
if ((res = parse_ltree(buf, fcinfo->context)) == NULL) |
|
|
|
|
PG_RETURN_NULL(); |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(res); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(ltree_out); |
|
|
|
@ -232,7 +238,7 @@ ltree_recv(PG_FUNCTION_ARGS) |
|
|
|
|
elog(ERROR, "unsupported ltree version number %d", version); |
|
|
|
|
|
|
|
|
|
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
|
|
|
|
res = parse_ltree(str); |
|
|
|
|
res = parse_ltree(str, NULL); |
|
|
|
|
pfree(str); |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(res); |
|
|
|
@ -259,7 +265,7 @@ ltree_recv(PG_FUNCTION_ARGS) |
|
|
|
|
* returns an lquery |
|
|
|
|
*/ |
|
|
|
|
static lquery * |
|
|
|
|
parse_lquery(const char *buf) |
|
|
|
|
parse_lquery(const char *buf, struct Node *escontext) |
|
|
|
|
{ |
|
|
|
|
const char *ptr; |
|
|
|
|
int num = 0, |
|
|
|
@ -277,7 +283,7 @@ parse_lquery(const char *buf) |
|
|
|
|
int charlen; |
|
|
|
|
int pos = 1; /* character position for error messages */ |
|
|
|
|
|
|
|
|
|
#define UNCHAR ereport(ERROR, \ |
|
|
|
|
#define UNCHAR ereturn(escontext, NULL,\ |
|
|
|
|
errcode(ERRCODE_SYNTAX_ERROR), \
|
|
|
|
|
errmsg("lquery syntax error at character %d", \
|
|
|
|
|
pos)) |
|
|
|
@ -297,7 +303,7 @@ parse_lquery(const char *buf) |
|
|
|
|
|
|
|
|
|
num++; |
|
|
|
|
if (num > LQUERY_MAX_LEVELS) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
|
|
|
|
errmsg("number of lquery items (%d) exceeds the maximum allowed (%d)", |
|
|
|
|
num, LQUERY_MAX_LEVELS))); |
|
|
|
@ -361,18 +367,21 @@ parse_lquery(const char *buf) |
|
|
|
|
} |
|
|
|
|
else if (t_iseq(ptr, '|')) |
|
|
|
|
{ |
|
|
|
|
finish_nodeitem(lptr, ptr, true, pos); |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) |
|
|
|
|
return NULL; |
|
|
|
|
state = LQPRS_WAITVAR; |
|
|
|
|
} |
|
|
|
|
else if (t_iseq(ptr, '{')) |
|
|
|
|
{ |
|
|
|
|
finish_nodeitem(lptr, ptr, true, pos); |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) |
|
|
|
|
return NULL; |
|
|
|
|
curqlevel->flag |= LQL_COUNT; |
|
|
|
|
state = LQPRS_WAITFNUM; |
|
|
|
|
} |
|
|
|
|
else if (t_iseq(ptr, '.')) |
|
|
|
|
{ |
|
|
|
|
finish_nodeitem(lptr, ptr, true, pos); |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) |
|
|
|
|
return NULL; |
|
|
|
|
state = LQPRS_WAITLEVEL; |
|
|
|
|
curqlevel = NEXTLEV(curqlevel); |
|
|
|
|
} |
|
|
|
@ -407,7 +416,7 @@ parse_lquery(const char *buf) |
|
|
|
|
int low = atoi(ptr); |
|
|
|
|
|
|
|
|
|
if (low < 0 || low > LTREE_MAX_LEVELS) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
|
|
|
|
errmsg("lquery syntax error"), |
|
|
|
|
errdetail("Low limit (%d) exceeds the maximum allowed (%d), at character %d.", |
|
|
|
@ -425,13 +434,13 @@ parse_lquery(const char *buf) |
|
|
|
|
int high = atoi(ptr); |
|
|
|
|
|
|
|
|
|
if (high < 0 || high > LTREE_MAX_LEVELS) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
|
|
|
|
errmsg("lquery syntax error"), |
|
|
|
|
errdetail("High limit (%d) exceeds the maximum allowed (%d), at character %d.", |
|
|
|
|
high, LTREE_MAX_LEVELS, pos))); |
|
|
|
|
else if (curqlevel->low > high) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), |
|
|
|
|
errmsg("lquery syntax error"), |
|
|
|
|
errdetail("Low limit (%d) is greater than high limit (%d), at character %d.", |
|
|
|
@ -485,11 +494,14 @@ parse_lquery(const char *buf) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (state == LQPRS_WAITDELIM) |
|
|
|
|
finish_nodeitem(lptr, ptr, true, pos); |
|
|
|
|
{ |
|
|
|
|
if (!finish_nodeitem(lptr, ptr, true, pos, escontext)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
else if (state == LQPRS_WAITOPEN) |
|
|
|
|
curqlevel->high = LTREE_MAX_LEVELS; |
|
|
|
|
else if (state != LQPRS_WAITEND) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, NULL, |
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), |
|
|
|
|
errmsg("lquery syntax error"), |
|
|
|
|
errdetail("Unexpected end of input."))); |
|
|
|
@ -569,8 +581,9 @@ parse_lquery(const char *buf) |
|
|
|
|
* Close out parsing an ltree or lquery nodeitem: |
|
|
|
|
* compute the correct length, and complain if it's not OK |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos) |
|
|
|
|
static bool |
|
|
|
|
finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos, |
|
|
|
|
struct Node *escontext) |
|
|
|
|
{ |
|
|
|
|
if (is_lquery) |
|
|
|
|
{ |
|
|
|
@ -591,18 +604,19 @@ finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos) |
|
|
|
|
|
|
|
|
|
/* Complain if it's empty or too long */ |
|
|
|
|
if (lptr->len == 0) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, false, |
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), |
|
|
|
|
is_lquery ? |
|
|
|
|
errmsg("lquery syntax error at character %d", pos) : |
|
|
|
|
errmsg("ltree syntax error at character %d", pos), |
|
|
|
|
errdetail("Empty labels are not allowed."))); |
|
|
|
|
if (lptr->wlen > LTREE_LABEL_MAX_CHARS) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
ereturn(escontext, false, |
|
|
|
|
(errcode(ERRCODE_NAME_TOO_LONG), |
|
|
|
|
errmsg("label string is too long"), |
|
|
|
|
errdetail("Label length is %d, must be at most %d, at character %d.", |
|
|
|
|
lptr->wlen, LTREE_LABEL_MAX_CHARS, pos))); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -730,8 +744,12 @@ Datum |
|
|
|
|
lquery_in(PG_FUNCTION_ARGS) |
|
|
|
|
{ |
|
|
|
|
char *buf = (char *) PG_GETARG_POINTER(0); |
|
|
|
|
lquery *res; |
|
|
|
|
|
|
|
|
|
if ((res = parse_lquery(buf, fcinfo->context)) == NULL) |
|
|
|
|
PG_RETURN_NULL(); |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(parse_lquery(buf)); |
|
|
|
|
PG_RETURN_POINTER(res); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(lquery_out); |
|
|
|
@ -790,7 +808,7 @@ lquery_recv(PG_FUNCTION_ARGS) |
|
|
|
|
elog(ERROR, "unsupported lquery version number %d", version); |
|
|
|
|
|
|
|
|
|
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
|
|
|
|
res = parse_lquery(str); |
|
|
|
|
res = parse_lquery(str, NULL); |
|
|
|
|
pfree(str); |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(res); |
|
|
|
|