1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-19 17:02:53 +03:00
Files
postgres/contrib/ltree/ltxtquery_op.c
Jeff Davis 84d5efa7e3 Fix multibyte issue in ltree_strncasecmp().
Previously, the API for ltree_strncasecmp() took two inputs but only
one length (that of the smaller input). It truncated the larger input
to that length, but that could break a multibyte sequence.

Change the API to be a check for prefix equality (possibly
case-insensitive) instead, which is all that's needed by the
callers. Also, provide the lengths of both inputs.

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://postgr.es/m/5f65b85740197ba6249ea507cddf609f84a6188b.camel%40j-davis.com
Backpatch-through: 14
2025-12-16 10:35:40 -08:00

112 lines
2.5 KiB
C

/*
* txtquery operations with ltree
* Teodor Sigaev <teodor@stack.net>
* contrib/ltree/ltxtquery_op.c
*/
#include "postgres.h"
#include <ctype.h>
#include "ltree.h"
#include "miscadmin.h"
PG_FUNCTION_INFO_V1(ltxtq_exec);
PG_FUNCTION_INFO_V1(ltxtq_rexec);
/*
* check for boolean condition
*/
bool
ltree_execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *val))
{
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
if (curitem->type == VAL)
return (*chkcond) (checkval, curitem);
else if (curitem->val == (int32) '!')
{
return calcnot ?
((ltree_execute(curitem + 1, checkval, calcnot, chkcond)) ? false : true)
: true;
}
else if (curitem->val == (int32) '&')
{
if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
else
return false;
}
else
{ /* |-operator */
if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
return true;
else
return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
}
}
typedef struct
{
ltree *node;
char *operand;
} CHKVAL;
static bool
checkcondition_str(void *checkval, ITEM *val)
{
ltree_level *level = LTREE_FIRST(((CHKVAL *) checkval)->node);
int tlen = ((CHKVAL *) checkval)->node->numlevel;
char *op = ((CHKVAL *) checkval)->operand + val->distance;
ltree_prefix_eq_func prefix_eq;
prefix_eq = (val->flag & LVAR_INCASE) ? ltree_prefix_eq_ci : ltree_prefix_eq;
while (tlen > 0)
{
if (val->flag & LVAR_SUBLEXEME)
{
if (compare_subnode(level, op, val->length, prefix_eq, (val->flag & LVAR_ANYEND)))
return true;
}
else if ((val->length == level->len ||
(level->len > val->length && (val->flag & LVAR_ANYEND))) &&
(*prefix_eq) (op, val->length, level->name, level->len))
return true;
tlen--;
level = LEVEL_NEXT(level);
}
return false;
}
Datum
ltxtq_exec(PG_FUNCTION_ARGS)
{
ltree *val = PG_GETARG_LTREE_P(0);
ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
CHKVAL chkval;
bool result;
chkval.node = val;
chkval.operand = GETOPERAND(query);
result = ltree_execute(GETQUERY(query),
&chkval,
true,
checkcondition_str);
PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(result);
}
Datum
ltxtq_rexec(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall2(ltxtq_exec,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
));
}