PG_RETURN_BOOL(result);
}
-static void
-findoprnd(ITEM *ptr, int32 *pos)
+/*
+ * Recursively fill the "left" fields of an ITEM array that represents
+ * a valid postfix tree.
+ *
+ * state: only needed for error reporting
+ * ptr: starting element of array
+ * pos: in/out argument, the array index this call is responsible to fill
+ *
+ * At exit, *pos has been decremented to point before the sub-tree whose
+ * top is the entry-time value of *pos.
+ *
+ * Returns true if okay, false if error (the only possible error is
+ * overflow of a "left" field).
+ */
+static bool
+findoprnd(WORKSTATE *state, ITEM *ptr, int32 *pos)
{
+ int32 mypos;
+
/* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
+ /* get the position this call is supposed to update */
+ mypos = *pos;
+ Assert(mypos >= 0);
+
+ /* in all cases, we should decrement *pos to advance over this item */
+ (*pos)--;
+
#ifdef BS_DEBUG
- elog(DEBUG3, (ptr[*pos].type == OPR) ?
- "%d %c" : "%d %d", *pos, ptr[*pos].val);
+ elog(DEBUG3, (ptr[mypos].type == OPR) ?
+ "%d %c" : "%d %d", mypos, ptr[mypos].val);
#endif
- if (ptr[*pos].type == VAL)
+
+ if (ptr[mypos].type == VAL)
{
- ptr[*pos].left = 0;
- (*pos)--;
+ /* base case: a VAL has no operand, so just set its left to zero */
+ ptr[mypos].left = 0;
}
- else if (ptr[*pos].val == (int32) '!')
+ else if (ptr[mypos].val == (int32) '!')
{
- ptr[*pos].left = -1;
- (*pos)--;
- findoprnd(ptr, pos);
+ /* unary operator, likewise easy: operand is just before it */
+ ptr[mypos].left = -1;
+ /* recurse to scan operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
}
else
{
- ITEM *curitem = &ptr[*pos];
- int32 tmp = *pos;
+ /* binary operator */
+ int32 delta;
- (*pos)--;
- findoprnd(ptr, pos);
- curitem->left = *pos - tmp;
- findoprnd(ptr, pos);
+ /* recurse to scan right operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
+ /* we must fill left with offset to left operand's top */
+ /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */
+ delta = *pos - mypos;
+ /* ... but it might be too large to fit in the 16-bit left field */
+ Assert(delta < 0);
+ if (unlikely(delta < PG_INT16_MIN))
+ ereturn(state->escontext, false,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("query_int expression is too complex")));
+ ptr[mypos].left = (int16) delta;
+ /* recurse to scan left operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
}
+
+ return true;
}
query->size = state.num;
ptr = GETQUERY(query);
+ /* fill the query array from the data makepol constructed */
for (i = state.num - 1; i >= 0; i--)
{
ptr[i].type = state.str->type;
state.str = tmp;
}
+ /* now fill the "left" fields */
pos = query->size - 1;
- findoprnd(ptr, &pos);
+ if (!findoprnd(&state, ptr, &pos))
+ PG_RETURN_NULL();
+ /* if successful, findoprnd should have scanned the whole array */
+ Assert(pos == -1);
+
#ifdef BS_DEBUG
initStringInfo(&pbuf);
for (i = 0; i < query->size; i++)
1 & 2 & 4 & ( 5 | !6 )
(1 row)
+SELECT (SELECT '0 | ' || string_agg(i::text, ' & ')
+ FROM generate_series(1, 17000) AS i)::query_int;
+ERROR: query_int expression is too complex
-- test non-error-throwing input
SELECT str as "query_int",
pg_input_is_valid(str,'query_int') as ok,
SELECT '1&2&4&5&6'::query_int;
SELECT '1&(2&(4&(5|6)))'::query_int;
SELECT '1&(2&(4&(5|!6)))'::query_int;
+SELECT (SELECT '0 | ' || string_agg(i::text, ' & ')
+ FROM generate_series(1, 17000) AS i)::query_int;
-- test non-error-throwing input
f
(1 row)
+SELECT (SELECT 'a | ' || string_agg('b', ' & ')
+ FROM generate_series(1, 17000) AS i)::ltxtquery;
+ERROR: ltxtquery is too large
--arrays
SELECT '{1.2.3}'::ltree[] @> '1.2.3.4';
?column?
return END;
}
-static void
-findoprnd(ITEM *ptr, int32 *pos)
+/*
+ * Recursively fill the "left" fields of an ITEM array that represents
+ * a valid postfix tree.
+ *
+ * state: only needed for error reporting
+ * ptr: starting element of array
+ * pos: in/out argument, the array index this call is responsible to fill
+ *
+ * At exit, *pos has been incremented to point after the sub-tree whose
+ * top is the entry-time value of *pos.
+ *
+ * Returns true if okay, false if error (the only possible error is
+ * overflow of a "left" field).
+ */
+static bool
+findoprnd(QPRS_STATE *state, ITEM *ptr, int32 *pos)
{
+ int32 mypos;
+
/* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
- if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
+ /* get the position this call is supposed to update */
+ mypos = *pos;
+
+ /* in all cases, we should increment *pos to advance over this item */
+ (*pos)++;
+
+ if (ptr[mypos].type == VAL || ptr[mypos].type == VALTRUE)
{
- ptr[*pos].left = 0;
- (*pos)++;
+ /* base case: a VAL has no operand, so just set its left to zero */
+ ptr[mypos].left = 0;
}
- else if (ptr[*pos].val == (int32) '!')
+ else if (ptr[mypos].val == (int32) '!')
{
- ptr[*pos].left = 1;
- (*pos)++;
- findoprnd(ptr, pos);
+ /* unary operator, likewise easy: operand is just after it */
+ ptr[mypos].left = 1;
+ /* recurse to scan operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
}
else
{
- ITEM *curitem = &ptr[*pos];
- int32 tmp = *pos;
-
- (*pos)++;
- findoprnd(ptr, pos);
- curitem->left = *pos - tmp;
- findoprnd(ptr, pos);
+ /* binary operator */
+ int32 delta;
+
+ /* recurse to scan right operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
+ /* we must fill left with offset to left operand's top */
+ /* delta can't overflow, see LTXTQUERY_TOO_BIG ... */
+ delta = *pos - mypos;
+ /* ... but it might be too large to fit in the 16-bit left field */
+ Assert(delta > 0);
+ if (unlikely(delta > PG_INT16_MAX))
+ ereturn(state->escontext, false,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("ltxtquery is too large")));
+ ptr[mypos].left = (int16) delta;
+ /* recurse to scan left operand */
+ if (!findoprnd(state, ptr, pos))
+ return false;
}
+
+ return true;
}
/* set left operand's position for every operator */
pos = 0;
- findoprnd(ptr, &pos);
+ if (!findoprnd(&state, ptr, &pos))
+ return NULL;
+ /* if successful, findoprnd should have scanned the whole array */
+ Assert(pos == state.num);
return query;
}
SELECT 'tree.awdfg_qwerty'::ltree @ 'tree & aw_qw%*'::ltxtquery;
SELECT 'tree.awdfg_qwerty'::ltree @ 'tree & aw_rw%*'::ltxtquery;
+SELECT (SELECT 'a | ' || string_agg('b', ' & ')
+ FROM generate_series(1, 17000) AS i)::ltxtquery;
+
--arrays
SELECT '{1.2.3}'::ltree[] @> '1.2.3.4';