summaryrefslogtreecommitdiff
path: root/contrib/ltree/ltxtquery_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ltree/ltxtquery_io.c')
-rw-r--r--contrib/ltree/ltxtquery_io.c75
1 files changed, 52 insertions, 23 deletions
diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c
index 8ab0ce8e52..a16e577303 100644
--- a/contrib/ltree/ltxtquery_io.c
+++ b/contrib/ltree/ltxtquery_io.c
@@ -11,6 +11,7 @@
#include "libpq/pqformat.h"
#include "ltree.h"
#include "miscadmin.h"
+#include "nodes/miscnodes.h"
/* parser's states */
@@ -37,6 +38,7 @@ typedef struct
char *buf;
int32 state;
int32 count;
+ struct Node *escontext;
/* reverse polish notation in list (for temporary usage) */
NODE *str;
/* number in str */
@@ -51,6 +53,8 @@ typedef struct
/*
* get token from query string
+ *
+ * caller needs to check if a soft-error was set if the result is ERR.
*/
static int32
gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint16 *flag)
@@ -84,7 +88,7 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
*flag = 0;
}
else if (!t_isspace(state->buf))
- ereport(ERROR,
+ ereturn(state->escontext, ERR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operand syntax error")));
break;
@@ -92,7 +96,7 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
if (ISALNUM(state->buf))
{
if (*flag)
- ereport(ERROR,
+ ereturn(state->escontext, ERR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("modifiers syntax error")));
*lenval += charlen;
@@ -124,9 +128,13 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
return (state->count < 0) ? ERR : CLOSE;
}
else if (*(state->buf) == '\0')
+ {
return (state->count) ? ERR : END;
+ }
else if (!t_iseq(state->buf, ' '))
+ {
return ERR;
+ }
break;
default:
return ERR;
@@ -135,12 +143,14 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
state->buf += charlen;
}
+
+ /* should not get here */
}
/*
* push new one in polish notation reverse view
*/
-static void
+static bool
pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval, uint16 flag)
{
NODE *tmp = (NODE *) palloc(sizeof(NODE));
@@ -149,11 +159,11 @@ pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval
tmp->val = val;
tmp->flag = flag;
if (distance > 0xffff)
- ereport(ERROR,
+ ereturn(state->escontext, false,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("value is too big")));
if (lenval > 0xff)
- ereport(ERROR,
+ ereturn(state->escontext, false,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("operand is too long")));
tmp->distance = distance;
@@ -161,21 +171,23 @@ pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval
tmp->next = state->str;
state->str = tmp;
state->num++;
+ return true;
}
/*
* This function is used for query text parsing
*/
-static void
+static bool
pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
{
if (lenval > 0xffff)
- ereport(ERROR,
+ ereturn(state->escontext, false,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("word is too long")));
- pushquery(state, type, ltree_crc32_sz(strval, lenval),
- state->curop - state->op, lenval, flag);
+ if (! pushquery(state, type, ltree_crc32_sz(strval, lenval),
+ state->curop - state->op, lenval, flag))
+ return false;
while (state->curop - state->op + lenval + 1 >= state->lenop)
{
@@ -190,6 +202,7 @@ pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
*(state->curop) = '\0';
state->curop++;
state->sumlen += lenval + 1;
+ return true;
}
#define STACKDEPTH 32
@@ -215,17 +228,22 @@ makepol(QPRS_STATE *state)
switch (type)
{
case VAL:
- pushval_asis(state, VAL, strval, lenval, flag);
+ if (!pushval_asis(state, VAL, strval, lenval, flag))
+ return ERR;
while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
stack[lenstack - 1] == (int32) '!'))
{
lenstack--;
- pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
+ return ERR;
}
break;
case OPR:
if (lenstack && val == (int32) '|')
- pushquery(state, OPR, val, 0, 0, 0);
+ {
+ if (!pushquery(state, OPR, val, 0, 0, 0))
+ return ERR;
+ }
else
{
if (lenstack == STACKDEPTH)
@@ -242,30 +260,35 @@ makepol(QPRS_STATE *state)
stack[lenstack - 1] == (int32) '!'))
{
lenstack--;
- pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
+ return ERR;
}
break;
case CLOSE:
while (lenstack)
{
lenstack--;
- pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
+ return ERR;
};
return END;
break;
case ERR:
+ if (SOFT_ERROR_OCCURRED(state->escontext))
+ return ERR;
+ /* fall through */
default:
- ereport(ERROR,
+ ereturn(state->escontext, ERR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error")));
- return ERR;
}
}
while (lenstack)
{
lenstack--;
- pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
+ return ERR;
};
return END;
}
@@ -304,7 +327,7 @@ findoprnd(ITEM *ptr, int32 *pos)
* input
*/
static ltxtquery *
-queryin(char *buf)
+queryin(char *buf, struct Node *escontext)
{
QPRS_STATE state;
int32 i;
@@ -325,6 +348,7 @@ queryin(char *buf)
state.count = 0;
state.num = 0;
state.str = NULL;
+ state.escontext = escontext;
/* init list of operand */
state.sumlen = 0;
@@ -333,15 +357,16 @@ queryin(char *buf)
*(state.curop) = '\0';
/* parse query & make polish notation (postfix, but in reverse order) */
- makepol(&state);
+ if (makepol(&state) == ERR)
+ return NULL;
if (!state.num)
- ereport(ERROR,
+ ereturn(escontext, NULL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Empty query.")));
if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
- ereport(ERROR,
+ ereturn(escontext, NULL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("ltxtquery is too large")));
commonlen = COMPUTESIZE(state.num, state.sumlen);
@@ -382,7 +407,11 @@ PG_FUNCTION_INFO_V1(ltxtq_in);
Datum
ltxtq_in(PG_FUNCTION_ARGS)
{
- PG_RETURN_POINTER(queryin((char *) PG_GETARG_POINTER(0)));
+ ltxtquery *res;
+
+ if ((res = queryin((char *) PG_GETARG_POINTER(0), fcinfo->context)) == NULL)
+ PG_RETURN_NULL();
+ PG_RETURN_POINTER(res);
}
/*
@@ -407,7 +436,7 @@ ltxtq_recv(PG_FUNCTION_ARGS)
elog(ERROR, "unsupported ltxtquery version number %d", version);
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
- res = queryin(str);
+ res = queryin(str, NULL);
pfree(str);
PG_RETURN_POINTER(res);