PostgreSQL Source Code  git master
lquery_op.c File Reference
#include "postgres.h"
#include <ctype.h>
#include "catalog/pg_collation.h"
#include "ltree.h"
#include "miscadmin.h"
#include "utils/formatting.h"
Include dependency graph for lquery_op.c:

Go to the source code of this file.

Macros

#define NEXTVAL(x)   ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
 

Functions

 PG_FUNCTION_INFO_V1 (ltq_regex)
 
 PG_FUNCTION_INFO_V1 (ltq_rregex)
 
 PG_FUNCTION_INFO_V1 (lt_q_regex)
 
 PG_FUNCTION_INFO_V1 (lt_q_rregex)
 
static char * getlexeme (char *start, char *end, int *len)
 
bool compare_subnode (ltree_level *t, char *qn, int len, int(*cmpptr)(const char *, const char *, size_t), bool anyend)
 
int ltree_strncasecmp (const char *a, const char *b, size_t s)
 
static bool checkLevel (lquery_level *curq, ltree_level *curt)
 
static bool checkCond (lquery_level *curq, int qlen, ltree_level *curt, int tlen)
 
Datum ltq_regex (PG_FUNCTION_ARGS)
 
Datum ltq_rregex (PG_FUNCTION_ARGS)
 
Datum lt_q_regex (PG_FUNCTION_ARGS)
 
Datum lt_q_rregex (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ NEXTVAL

#define NEXTVAL (   x)    ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )

Definition at line 21 of file lquery_op.c.

Referenced by lt_q_regex().

Function Documentation

◆ checkCond()

static bool checkCond ( lquery_level curq,
int  qlen,
ltree_level curt,
int  tlen 
)
static

Definition at line 136 of file lquery_op.c.

References CHECK_FOR_INTERRUPTS, check_stack_depth(), checkLevel(), lquery_level::flag, lquery_level::high, LEVEL_NEXT, lquery_level::low, LQL_COUNT, LQL_NEXT, and lquery_level::numvar.

Referenced by ltq_regex().

138 {
139  /* Since this function recurses, it could be driven to stack overflow */
141 
142  /* Pathological patterns could take awhile, too */
144 
145  /* Loop while we have query items to consider */
146  while (qlen > 0)
147  {
148  int low,
149  high;
150  lquery_level *nextq;
151 
152  /*
153  * Get min and max repetition counts for this query item, dealing with
154  * the backwards-compatibility hack that the low/high fields aren't
155  * meaningful for non-'*' items unless LQL_COUNT is set.
156  */
157  if ((curq->flag & LQL_COUNT) || curq->numvar == 0)
158  low = curq->low, high = curq->high;
159  else
160  low = high = 1;
161 
162  /*
163  * We may limit "high" to the remaining text length; this avoids
164  * separate tests below.
165  */
166  if (high > tlen)
167  high = tlen;
168 
169  /* Fail if a match of required number of items is impossible */
170  if (high < low)
171  return false;
172 
173  /*
174  * Recursively check the rest of the pattern against each possible
175  * start point following some of this item's match(es).
176  */
177  nextq = LQL_NEXT(curq);
178  qlen--;
179 
180  for (int matchcnt = 0; matchcnt < high; matchcnt++)
181  {
182  /*
183  * If we've consumed an acceptable number of matches of this item,
184  * and the rest of the pattern matches beginning here, we're good.
185  */
186  if (matchcnt >= low && checkCond(nextq, qlen, curt, tlen))
187  return true;
188 
189  /*
190  * Otherwise, try to match one more text item to this query item.
191  */
192  if (!checkLevel(curq, curt))
193  return false;
194 
195  curt = LEVEL_NEXT(curt);
196  tlen--;
197  }
198 
199  /*
200  * Once we've consumed "high" matches, we can succeed only if the rest
201  * of the pattern matches beginning here. Loop around (if you prefer,
202  * think of this as tail recursion).
203  */
204  curq = nextq;
205  }
206 
207  /*
208  * Once we're out of query items, we match only if there's no remaining
209  * text either.
210  */
211  return (tlen == 0);
212 }
uint16 low
Definition: ltree.h:80
#define LQL_NEXT(x)
Definition: ltree.h:87
static bool checkCond(lquery_level *curq, int qlen, ltree_level *curt, int tlen)
Definition: lquery_op.c:136
uint16 flag
Definition: ltree.h:78
#define LQL_COUNT
Definition: ltree.h:91
static bool checkLevel(lquery_level *curq, ltree_level *curt)
Definition: lquery_op.c:99
void check_stack_depth(void)
Definition: postgres.c:3312
#define LEVEL_NEXT(x)
Definition: ltree.h:27
uint16 numvar
Definition: ltree.h:79
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
uint16 high
Definition: ltree.h:81

◆ checkLevel()

static bool checkLevel ( lquery_level curq,
ltree_level curt 
)
static

Definition at line 99 of file lquery_op.c.

References compare_subnode(), lquery_variant::flag, lquery_level::flag, i, ltree_level::len, lquery_variant::len, LQL_FIRST, LQL_NOT, ltree_strncasecmp(), LVAR_ANYEND, LVAR_INCASE, LVAR_NEXT, LVAR_SUBLEXEME, ltree_level::name, lquery_variant::name, lquery_level::numvar, and success.

Referenced by checkCond().

100 {
101  lquery_variant *curvar = LQL_FIRST(curq);
102  bool success;
103 
104  success = (curq->flag & LQL_NOT) ? false : true;
105 
106  /* numvar == 0 means '*' which matches anything */
107  if (curq->numvar == 0)
108  return success;
109 
110  for (int i = 0; i < curq->numvar; i++)
111  {
112  int (*cmpptr) (const char *, const char *, size_t);
113 
114  cmpptr = (curvar->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
115 
116  if (curvar->flag & LVAR_SUBLEXEME)
117  {
118  if (compare_subnode(curt, curvar->name, curvar->len, cmpptr,
119  (curvar->flag & LVAR_ANYEND)))
120  return success;
121  }
122  else if ((curvar->len == curt->len ||
123  (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))) &&
124  (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
125  return success;
126 
127  curvar = LVAR_NEXT(curvar);
128  }
129  return !success;
130 }
int ltree_strncasecmp(const char *a, const char *b, size_t s)
Definition: lquery_op.c:78
bool compare_subnode(ltree_level *t, char *qn, int len, int(*cmpptr)(const char *, const char *, size_t), bool anyend)
Definition: lquery_op.c:44
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:23
#define LVAR_INCASE
Definition: ltree.h:62
uint8 flag
Definition: ltree.h:49
uint16 len
Definition: ltree.h:48
uint16 len
Definition: ltree.h:22
#define LVAR_ANYEND
Definition: ltree.h:61
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:50
#define LQL_FIRST(x)
Definition: ltree.h:88
#define LVAR_NEXT(x)
Definition: ltree.h:59
uint16 flag
Definition: ltree.h:78
#define LQL_NOT
Definition: ltree.h:90
#define LVAR_SUBLEXEME
Definition: ltree.h:63
uint16 numvar
Definition: ltree.h:79
int i
static bool success
Definition: initdb.c:162

◆ compare_subnode()

bool compare_subnode ( ltree_level t,
char *  qn,
int  len,
int(*)(const char *, const char *, size_t)  cmpptr,
bool  anyend 
)

Definition at line 44 of file lquery_op.c.

References getlexeme(), ltree_level::len, and ltree_level::name.

Referenced by checkcondition_str(), and checkLevel().

45 {
46  char *endt = t->name + t->len;
47  char *endq = qn + len;
48  char *tn;
49  int lent,
50  lenq;
51  bool isok;
52 
53  while ((qn = getlexeme(qn, endq, &lenq)) != NULL)
54  {
55  tn = t->name;
56  isok = false;
57  while ((tn = getlexeme(tn, endt, &lent)) != NULL)
58  {
59  if ((lent == lenq || (lent > lenq && anyend)) &&
60  (*cmpptr) (qn, tn, lenq) == 0)
61  {
62 
63  isok = true;
64  break;
65  }
66  tn += lent;
67  }
68 
69  if (!isok)
70  return false;
71  qn += lenq;
72  }
73 
74  return true;
75 }
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:23
uint16 len
Definition: ltree.h:22
static char * getlexeme(char *start, char *end, int *len)
Definition: lquery_op.c:24

◆ getlexeme()

static char* getlexeme ( char *  start,
char *  end,
int *  len 
)
static

Definition at line 24 of file lquery_op.c.

References pg_mblen(), and t_iseq.

Referenced by compare_subnode().

25 {
26  char *ptr;
27  int charlen;
28 
29  while (start < end && (charlen = pg_mblen(start)) == 1 && t_iseq(start, '_'))
30  start += charlen;
31 
32  ptr = start;
33  if (ptr >= end)
34  return NULL;
35 
36  while (ptr < end && !((charlen = pg_mblen(ptr)) == 1 && t_iseq(ptr, '_')))
37  ptr += charlen;
38 
39  *len = ptr - start;
40  return start;
41 }
#define t_iseq(x, c)
Definition: ts_locale.h:46
int pg_mblen(const char *mbstr)
Definition: mbutils.c:907

◆ lt_q_regex()

Datum lt_q_regex ( PG_FUNCTION_ARGS  )

Definition at line 239 of file lquery_op.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, array_contains_nulls(), ArrayGetNItems(), DatumGetBool, DirectFunctionCall2, ereport, errcode(), errmsg(), ERROR, ltq_regex(), NEXTVAL, PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_GETARG_LTREE_P, PG_RETURN_BOOL, and PointerGetDatum.

Referenced by lt_q_rregex(), and ltree_consistent().

240 {
241  ltree *tree = PG_GETARG_LTREE_P(0);
242  ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
243  lquery *query = (lquery *) ARR_DATA_PTR(_query);
244  bool res = false;
245  int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
246 
247  if (ARR_NDIM(_query) > 1)
248  ereport(ERROR,
249  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
250  errmsg("array must be one-dimensional")));
251  if (array_contains_nulls(_query))
252  ereport(ERROR,
253  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
254  errmsg("array must not contain nulls")));
255 
256  while (num > 0)
257  {
259  PointerGetDatum(tree), PointerGetDatum(query))))
260  {
261 
262  res = true;
263  break;
264  }
265  num--;
266  query = NEXTVAL(query);
267  }
268 
269  PG_FREE_IF_COPY(tree, 0);
270  PG_FREE_IF_COPY(_query, 1);
271  PG_RETURN_BOOL(res);
272 }
#define PointerGetDatum(X)
Definition: postgres.h:556
Definition: ltree.h:100
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:75
int errcode(int sqlerrcode)
Definition: elog.c:691
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:204
#define NEXTVAL(x)
Definition: lquery_op.c:21
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
Datum ltq_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:215
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define DatumGetBool(X)
Definition: postgres.h:393
Definition: ltree.h:29
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define ereport(elevel,...)
Definition: elog.h:155
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define ARR_NDIM(a)
Definition: array.h:278
int errmsg(const char *fmt,...)
Definition: elog.c:902
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3550
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:628

◆ lt_q_rregex()

Datum lt_q_rregex ( PG_FUNCTION_ARGS  )

Definition at line 275 of file lquery_op.c.

References DirectFunctionCall2, lt_q_regex(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

276 {
278  PG_GETARG_DATUM(1),
279  PG_GETARG_DATUM(0)
280  ));
281 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
Datum lt_q_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:239
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:628

◆ ltq_regex()

Datum ltq_regex ( PG_FUNCTION_ARGS  )

Definition at line 215 of file lquery_op.c.

References checkCond(), LQUERY_FIRST, LTREE_FIRST, ltree::numlevel, lquery::numlevel, PG_FREE_IF_COPY, PG_GETARG_LQUERY_P, PG_GETARG_LTREE_P, and PG_RETURN_BOOL.

Referenced by _lt_q_regex(), _ltq_extract_regex(), _ltq_regex(), lt_q_regex(), ltq_rregex(), and ltree_consistent().

216 {
217  ltree *tree = PG_GETARG_LTREE_P(0);
218  lquery *query = PG_GETARG_LQUERY_P(1);
219  bool res;
220 
221  res = checkCond(LQUERY_FIRST(query), query->numlevel,
222  LTREE_FIRST(tree), tree->numlevel);
223 
224  PG_FREE_IF_COPY(tree, 0);
225  PG_FREE_IF_COPY(query, 1);
226  PG_RETURN_BOOL(res);
227 }
#define LQUERY_FIRST(x)
Definition: ltree.h:111
Definition: ltree.h:100
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:204
static bool checkCond(lquery_level *curq, int qlen, ltree_level *curt, int tlen)
Definition: lquery_op.c:136
#define PG_GETARG_LQUERY_P(n)
Definition: ltree.h:209
Definition: ltree.h:29
uint16 numlevel
Definition: ltree.h:32
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
uint16 numlevel
Definition: ltree.h:103
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define LTREE_FIRST(x)
Definition: ltree.h:38

◆ ltq_rregex()

Datum ltq_rregex ( PG_FUNCTION_ARGS  )

Definition at line 230 of file lquery_op.c.

References DirectFunctionCall2, ltq_regex(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

231 {
233  PG_GETARG_DATUM(1),
234  PG_GETARG_DATUM(0)
235  ));
236 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
Datum ltq_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:215
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:628

◆ ltree_strncasecmp()

int ltree_strncasecmp ( const char *  a,
const char *  b,
size_t  s 
)

Definition at line 78 of file lquery_op.c.

References pfree(), and str_tolower().

Referenced by checkcondition_str(), and checkLevel().

79 {
80  char *al = str_tolower(a, s, DEFAULT_COLLATION_OID);
81  char *bl = str_tolower(b, s, DEFAULT_COLLATION_OID);
82  int res;
83 
84  res = strncmp(al, bl, s);
85 
86  pfree(al);
87  pfree(bl);
88 
89  return res;
90 }
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1638
void pfree(void *pointer)
Definition: mcxt.c:1057

◆ PG_FUNCTION_INFO_V1() [1/4]

PG_FUNCTION_INFO_V1 ( ltq_regex  )

◆ PG_FUNCTION_INFO_V1() [2/4]

PG_FUNCTION_INFO_V1 ( ltq_rregex  )

◆ PG_FUNCTION_INFO_V1() [3/4]

PG_FUNCTION_INFO_V1 ( lt_q_regex  )

◆ PG_FUNCTION_INFO_V1() [4/4]

PG_FUNCTION_INFO_V1 ( lt_q_rregex  )