PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
lquery_op.c
Go to the documentation of this file.
1 /*
2  * op function for ltree and lquery
3  * Teodor Sigaev <teodor@stack.net>
4  * contrib/ltree/lquery_op.c
5  */
6 #include "postgres.h"
7 
8 #include <ctype.h>
9 
10 #include "catalog/pg_collation.h"
11 #include "utils/formatting.h"
12 #include "ltree.h"
13 
16 
19 
20 #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
21 
22 typedef struct
23 {
25  int nq;
27  int nt;
28  int posq;
29  int post;
30 } FieldNot;
31 
32 static char *
33 getlexeme(char *start, char *end, int *len)
34 {
35  char *ptr;
36  int charlen;
37 
38  while (start < end && (charlen = pg_mblen(start)) == 1 && t_iseq(start, '_'))
39  start += charlen;
40 
41  ptr = start;
42  if (ptr >= end)
43  return NULL;
44 
45  while (ptr < end && !((charlen = pg_mblen(ptr)) == 1 && t_iseq(ptr, '_')))
46  ptr += charlen;
47 
48  *len = ptr - start;
49  return start;
50 }
51 
52 bool
53  compare_subnode(ltree_level *t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
54 {
55  char *endt = t->name + t->len;
56  char *endq = qn + len;
57  char *tn;
58  int lent,
59  lenq;
60  bool isok;
61 
62  while ((qn = getlexeme(qn, endq, &lenq)) != NULL)
63  {
64  tn = t->name;
65  isok = false;
66  while ((tn = getlexeme(tn, endt, &lent)) != NULL)
67  {
68  if (
69  (
70  lent == lenq ||
71  (lent > lenq && anyend)
72  ) &&
73  (*cmpptr) (qn, tn, lenq) == 0)
74  {
75 
76  isok = true;
77  break;
78  }
79  tn += lent;
80  }
81 
82  if (!isok)
83  return false;
84  qn += lenq;
85  }
86 
87  return true;
88 }
89 
90 int
91 ltree_strncasecmp(const char *a, const char *b, size_t s)
92 {
93  char *al = str_tolower(a, s, DEFAULT_COLLATION_OID);
94  char *bl = str_tolower(b, s, DEFAULT_COLLATION_OID);
95  int res;
96 
97  res = strncmp(al, bl, s);
98 
99  pfree(al);
100  pfree(bl);
101 
102  return res;
103 }
104 
105 static bool
107 {
108  int (*cmpptr) (const char *, const char *, size_t);
109  lquery_variant *curvar = LQL_FIRST(curq);
110  int i;
111 
112  for (i = 0; i < curq->numvar; i++)
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, (curvar->flag & LVAR_ANYEND)))
119  return true;
120  }
121  else if (
122  (
123  curvar->len == curt->len ||
124  (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))
125  ) &&
126  (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
127  {
128 
129  return true;
130  }
131  curvar = LVAR_NEXT(curvar);
132  }
133  return false;
134 }
135 
136 /*
137 void
138 printFieldNot(FieldNot *fn ) {
139  while(fn->q) {
140  elog(NOTICE,"posQ:%d lenQ:%d posT:%d lenT:%d", fn->posq,fn->nq,fn->post,fn->nt);
141  fn++;
142  }
143 }
144 */
145 
146 static struct
147 {
148  bool muse;
150 } SomeStack =
151 
152 {
153  false, 0,
154 };
155 
156 static bool
157 checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_numlevel, FieldNot *ptr)
158 {
159  uint32 low_pos = 0,
160  high_pos = 0,
161  cur_tpos = 0;
162  int tlen = tree_numlevel,
163  qlen = query_numlevel;
164  int isok;
165  lquery_level *prevq = NULL;
166  ltree_level *prevt = NULL;
167 
168  if (SomeStack.muse)
169  {
170  high_pos = SomeStack.high_pos;
171  qlen--;
172  prevq = curq;
173  curq = LQL_NEXT(curq);
174  SomeStack.muse = false;
175  }
176 
177  while (tlen > 0 && qlen > 0)
178  {
179  if (curq->numvar)
180  {
181  prevt = curt;
182  while (cur_tpos < low_pos)
183  {
184  curt = LEVEL_NEXT(curt);
185  tlen--;
186  cur_tpos++;
187  if (tlen == 0)
188  return false;
189  if (ptr && ptr->q)
190  ptr->nt++;
191  }
192 
193  if (ptr && curq->flag & LQL_NOT)
194  {
195  if (!(prevq && prevq->numvar == 0))
196  prevq = curq;
197  if (ptr->q == NULL)
198  {
199  ptr->t = prevt;
200  ptr->q = prevq;
201  ptr->nt = 1;
202  ptr->nq = 1 + ((prevq == curq) ? 0 : 1);
203  ptr->posq = query_numlevel - qlen - ((prevq == curq) ? 0 : 1);
204  ptr->post = cur_tpos;
205  }
206  else
207  {
208  ptr->nt++;
209  ptr->nq++;
210  }
211 
212  if (qlen == 1 && ptr->q->numvar == 0)
213  ptr->nt = tree_numlevel - ptr->post;
214  curt = LEVEL_NEXT(curt);
215  tlen--;
216  cur_tpos++;
217  if (high_pos < cur_tpos)
218  high_pos++;
219  }
220  else
221  {
222  isok = false;
223  while (cur_tpos <= high_pos && tlen > 0 && !isok)
224  {
225  isok = checkLevel(curq, curt);
226  curt = LEVEL_NEXT(curt);
227  tlen--;
228  cur_tpos++;
229  if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos)
230  {
231  FieldNot tmpptr;
232 
233  if (ptr)
234  memcpy(&tmpptr, ptr, sizeof(FieldNot));
235  SomeStack.high_pos = high_pos - cur_tpos;
236  SomeStack.muse = true;
237  if (checkCond(prevq, qlen + 1, curt, tlen, (ptr) ? &tmpptr : NULL))
238  return true;
239  }
240  if (!isok && ptr)
241  ptr->nt++;
242  }
243  if (!isok)
244  return false;
245 
246  if (ptr && ptr->q)
247  {
248  if (checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
249  return false;
250  ptr->q = NULL;
251  }
252  low_pos = cur_tpos;
253  high_pos = cur_tpos;
254  }
255  }
256  else
257  {
258  low_pos = cur_tpos + curq->low;
259  high_pos = cur_tpos + curq->high;
260  if (ptr && ptr->q)
261  {
262  ptr->nq++;
263  if (qlen == 1)
264  ptr->nt = tree_numlevel - ptr->post;
265  }
266  }
267 
268  prevq = curq;
269  curq = LQL_NEXT(curq);
270  qlen--;
271  }
272 
273  if (low_pos > tree_numlevel || tree_numlevel > high_pos)
274  return false;
275 
276  while (qlen > 0)
277  {
278  if (curq->numvar)
279  {
280  if (!(curq->flag & LQL_NOT))
281  return false;
282  }
283  else
284  {
285  low_pos = cur_tpos + curq->low;
286  high_pos = cur_tpos + curq->high;
287  }
288 
289  curq = LQL_NEXT(curq);
290  qlen--;
291  }
292 
293  if (low_pos > tree_numlevel || tree_numlevel > high_pos)
294  return false;
295 
296  if (ptr && ptr->q && checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
297  return false;
298 
299  return true;
300 }
301 
302 Datum
304 {
305  ltree *tree = PG_GETARG_LTREE(0);
306  lquery *query = PG_GETARG_LQUERY(1);
307  bool res = false;
308 
309  if (query->flag & LQUERY_HASNOT)
310  {
311  FieldNot fn;
312 
313  fn.q = NULL;
314 
315  res = checkCond(LQUERY_FIRST(query), query->numlevel,
316  LTREE_FIRST(tree), tree->numlevel, &fn);
317  }
318  else
319  {
320  res = checkCond(LQUERY_FIRST(query), query->numlevel,
321  LTREE_FIRST(tree), tree->numlevel, NULL);
322  }
323 
324  PG_FREE_IF_COPY(tree, 0);
325  PG_FREE_IF_COPY(query, 1);
326  PG_RETURN_BOOL(res);
327 }
328 
329 Datum
331 {
333  PG_GETARG_DATUM(1),
334  PG_GETARG_DATUM(0)
335  ));
336 }
337 
338 Datum
340 {
341  ltree *tree = PG_GETARG_LTREE(0);
342  ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
343  lquery *query = (lquery *) ARR_DATA_PTR(_query);
344  bool res = false;
345  int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
346 
347  if (ARR_NDIM(_query) > 1)
348  ereport(ERROR,
349  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
350  errmsg("array must be one-dimensional")));
351  if (array_contains_nulls(_query))
352  ereport(ERROR,
353  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
354  errmsg("array must not contain nulls")));
355 
356  while (num > 0)
357  {
359  PointerGetDatum(tree), PointerGetDatum(query))))
360  {
361 
362  res = true;
363  break;
364  }
365  num--;
366  query = NEXTVAL(query);
367  }
368 
369  PG_FREE_IF_COPY(tree, 0);
370  PG_FREE_IF_COPY(_query, 1);
371  PG_RETURN_BOOL(res);
372 }
373 
374 Datum
376 {
378  PG_GETARG_DATUM(1),
379  PG_GETARG_DATUM(0)
380  ));
381 }
int ltree_strncasecmp(const char *a, const char *b, size_t s)
Definition: lquery_op.c:91
bool compare_subnode(ltree_level *t, char *qn, int len, int(*cmpptr)(const char *, const char *, size_t), bool anyend)
Definition: lquery_op.c:53
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:13
#define LVAR_INCASE
Definition: ltree.h:44
uint8 flag
Definition: ltree.h:36
uint32 high_pos
Definition: lquery_op.c:149
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1469
uint16 low
Definition: ltree.h:52
#define LQUERY_FIRST(x)
Definition: ltree.h:79
uint16 len
Definition: ltree.h:35
uint16 len
Definition: ltree.h:12
Datum ltq_rregex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:330
#define LVAR_ANYEND
Definition: ltree.h:43
#define PointerGetDatum(X)
Definition: postgres.h:564
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
Definition: ltree.h:69
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:37
#define LQL_FIRST(x)
Definition: ltree.h:59
#define LQL_NEXT(x)
Definition: ltree.h:58
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:75
lquery_level * q
Definition: lquery_op.c:24
int errcode(int sqlerrcode)
Definition: elog.c:575
uint16 flag
Definition: ltree.h:74
#define LVAR_NEXT(x)
Definition: ltree.h:41
int posq
Definition: lquery_op.c:28
#define NEXTVAL(x)
Definition: lquery_op.c:20
ltree_level * t
Definition: lquery_op.c:26
PG_FUNCTION_INFO_V1(ltq_regex)
int post
Definition: lquery_op.c:29
#define PG_GETARG_LTREE(x)
Definition: ltree.h:168
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:244
void pfree(void *pointer)
Definition: mcxt.c:992
uint16 flag
Definition: ltree.h:50
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:275
Datum ltq_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:303
static char * getlexeme(char *start, char *end, int *len)
Definition: lquery_op.c:33
static bool checkLevel(lquery_level *curq, ltree_level *curt)
Definition: lquery_op.c:106
#define LQL_NOT
Definition: ltree.h:61
#define ARR_DATA_PTR(a)
Definition: array.h:303
#define PG_GETARG_LQUERY(x)
Definition: ltree.h:170
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:68
#define t_iseq(x, c)
Definition: ts_locale.h:61
int nq
Definition: lquery_op.c:25
#define DatumGetBool(X)
Definition: postgres.h:401
unsigned int uint32
Definition: c.h:265
#define LEVEL_NEXT(x)
Definition: ltree.h:17
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: ltree.h:19
Datum lt_q_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:339
int nt
Definition: lquery_op.c:27
static struct @0 SomeStack
uint16 numlevel
Definition: ltree.h:22
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:303
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
static void * fn(void *arg)
#define NULL
Definition: c.h:226
uint16 numlevel
Definition: ltree.h:72
#define LVAR_SUBLEXEME
Definition: ltree.h:45
uint16 numvar
Definition: ltree.h:51
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:216
Datum lt_q_rregex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:375
int pg_mblen(const char *mbstr)
Definition: mbutils.c:771
#define ARR_NDIM(a)
Definition: array.h:271
bool muse
Definition: lquery_op.c:148
static bool checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_numlevel, FieldNot *ptr)
Definition: lquery_op.c:157
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define LTREE_FIRST(x)
Definition: ltree.h:27
int i
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
#define LQUERY_HASNOT
Definition: ltree.h:81
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3542
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:557
uint16 high
Definition: ltree.h:53