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/array.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, ltree_prefix_eq_func prefix_eq, bool anyend)
 
bool ltree_prefix_eq (const char *a, size_t a_sz, const char *b, size_t b_sz)
 
bool ltree_prefix_eq_ci (const char *a, size_t a_sz, const char *b, size_t b_sz)
 
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 22 of file lquery_op.c.

Function Documentation

◆ checkCond()

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

Definition at line 185 of file lquery_op.c.

187{
188 /* Since this function recurses, it could be driven to stack overflow */
190
191 /* Pathological patterns could take awhile, too */
193
194 /* Loop while we have query items to consider */
195 while (qlen > 0)
196 {
197 int low,
198 high;
199 lquery_level *nextq;
200
201 /*
202 * Get min and max repetition counts for this query item, dealing with
203 * the backwards-compatibility hack that the low/high fields aren't
204 * meaningful for non-'*' items unless LQL_COUNT is set.
205 */
206 if ((curq->flag & LQL_COUNT) || curq->numvar == 0)
207 low = curq->low, high = curq->high;
208 else
209 low = high = 1;
210
211 /*
212 * We may limit "high" to the remaining text length; this avoids
213 * separate tests below.
214 */
215 if (high > tlen)
216 high = tlen;
217
218 /* Fail if a match of required number of items is impossible */
219 if (high < low)
220 return false;
221
222 /*
223 * Recursively check the rest of the pattern against each possible
224 * start point following some of this item's match(es).
225 */
226 nextq = LQL_NEXT(curq);
227 qlen--;
228
229 for (int matchcnt = 0; matchcnt < high; matchcnt++)
230 {
231 /*
232 * If we've consumed an acceptable number of matches of this item,
233 * and the rest of the pattern matches beginning here, we're good.
234 */
235 if (matchcnt >= low && checkCond(nextq, qlen, curt, tlen))
236 return true;
237
238 /*
239 * Otherwise, try to match one more text item to this query item.
240 */
241 if (!checkLevel(curq, curt))
242 return false;
243
244 curt = LEVEL_NEXT(curt);
245 tlen--;
246 }
247
248 /*
249 * Once we've consumed "high" matches, we can succeed only if the rest
250 * of the pattern matches beginning here. Loop around (if you prefer,
251 * think of this as tail recursion).
252 */
253 curq = nextq;
254 }
255
256 /*
257 * Once we're out of query items, we match only if there's no remaining
258 * text either.
259 */
260 return (tlen == 0);
261}
static bool checkCond(lquery_level *curq, int qlen, ltree_level *curt, int tlen)
Definition: lquery_op.c:185
static bool checkLevel(lquery_level *curq, ltree_level *curt)
Definition: lquery_op.c:148
#define LEVEL_NEXT(x)
Definition: ltree.h:40
#define LQL_NEXT(x)
Definition: ltree.h:100
#define LQL_COUNT
Definition: ltree.h:104
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
void check_stack_depth(void)
Definition: stack_depth.c:95
uint16 numvar
Definition: ltree.h:92
uint16 high
Definition: ltree.h:94
uint16 flag
Definition: ltree.h:91
uint16 low
Definition: ltree.h:93

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

Referenced by checkCond(), and ltq_regex().

◆ checkLevel()

static bool checkLevel ( lquery_level curq,
ltree_level curt 
)
static

Definition at line 148 of file lquery_op.c.

149{
150 lquery_variant *curvar = LQL_FIRST(curq);
151 bool success;
152
153 success = (curq->flag & LQL_NOT) ? false : true;
154
155 /* numvar == 0 means '*' which matches anything */
156 if (curq->numvar == 0)
157 return success;
158
159 for (int i = 0; i < curq->numvar; i++)
160 {
161 ltree_prefix_eq_func prefix_eq;
162
163 prefix_eq = (curvar->flag & LVAR_INCASE) ? ltree_prefix_eq_ci : ltree_prefix_eq;
164
165 if (curvar->flag & LVAR_SUBLEXEME)
166 {
167 if (compare_subnode(curt, curvar->name, curvar->len, prefix_eq,
168 (curvar->flag & LVAR_ANYEND)))
169 return success;
170 }
171 else if ((curvar->len == curt->len ||
172 (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))) &&
173 (*prefix_eq) (curvar->name, curvar->len, curt->name, curt->len))
174 return success;
175
176 curvar = LVAR_NEXT(curvar);
177 }
178 return !success;
179}
static bool success
Definition: initdb.c:187
int i
Definition: isn.c:77
bool compare_subnode(ltree_level *t, char *qn, int len, ltree_prefix_eq_func prefix_eq, bool anyend)
Definition: lquery_op.c:44
bool ltree_prefix_eq(const char *a, size_t a_sz, const char *b, size_t b_sz)
Definition: lquery_op.c:82
bool ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz)
Definition: lquery_op.c:94
#define LVAR_INCASE
Definition: ltree.h:75
#define LVAR_ANYEND
Definition: ltree.h:74
bool(* ltree_prefix_eq_func)(const char *, size_t, const char *, size_t)
Definition: ltree.h:160
#define LQL_FIRST(x)
Definition: ltree.h:101
#define LVAR_NEXT(x)
Definition: ltree.h:72
#define LQL_NOT
Definition: ltree.h:103
#define LVAR_SUBLEXEME
Definition: ltree.h:76
uint8 flag
Definition: ltree.h:62
uint16 len
Definition: ltree.h:61
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:63
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:36
uint16 len
Definition: ltree.h:35

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

Referenced by checkCond().

◆ compare_subnode()

bool compare_subnode ( ltree_level t,
char *  qn,
int  len,
ltree_prefix_eq_func  prefix_eq,
bool  anyend 
)

Definition at line 44 of file lquery_op.c.

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

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

Referenced by checkcondition_str(), and checkLevel().

◆ getlexeme()

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

Definition at line 25 of file lquery_op.c.

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

References len, pg_mblen(), start, and t_iseq.

Referenced by compare_subnode().

◆ lt_q_regex()

Datum lt_q_regex ( PG_FUNCTION_ARGS  )

Definition at line 288 of file lquery_op.c.

289{
291 ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
292 lquery *query = (lquery *) ARR_DATA_PTR(_query);
293 bool res = false;
294 int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
295
296 if (ARR_NDIM(_query) > 1)
298 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
299 errmsg("array must be one-dimensional")));
300 if (array_contains_nulls(_query))
302 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
303 errmsg("array must not contain nulls")));
304
305 while (num > 0)
306 {
309 {
310
311 res = true;
312 break;
313 }
314 num--;
315 query = NEXTVAL(query);
316 }
317
319 PG_FREE_IF_COPY(_query, 1);
320 PG_RETURN_BOOL(res);
321}
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_DIMS(a)
Definition: array.h:294
bool array_contains_nulls(const ArrayType *array)
Definition: arrayfuncs.c:3768
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:57
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:686
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:360
#define NEXTVAL(x)
Definition: lquery_op.c:22
Datum ltq_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:264
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:221
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:352
tree
Definition: radixtree.h:1828
Definition: ltree.h:114
Definition: ltree.h:43

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, PointerGetDatum(), and tree.

Referenced by lt_q_rregex(), and ltree_consistent().

◆ lt_q_rregex()

Datum lt_q_rregex ( PG_FUNCTION_ARGS  )

Definition at line 324 of file lquery_op.c.

325{
329 ));
330}
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:354
Datum lt_q_regex(PG_FUNCTION_ARGS)
Definition: lquery_op.c:288

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

◆ ltq_regex()

Datum ltq_regex ( PG_FUNCTION_ARGS  )

Definition at line 264 of file lquery_op.c.

265{
267 lquery *query = PG_GETARG_LQUERY_P(1);
268 bool res;
269
270 res = checkCond(LQUERY_FIRST(query), query->numlevel,
271 LTREE_FIRST(tree), tree->numlevel);
272
274 PG_FREE_IF_COPY(query, 1);
275 PG_RETURN_BOOL(res);
276}
#define LTREE_FIRST(x)
Definition: ltree.h:51
#define PG_GETARG_LQUERY_P(n)
Definition: ltree.h:226
#define LQUERY_FIRST(x)
Definition: ltree.h:124
uint16 numlevel
Definition: ltree.h:116

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

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

◆ ltq_rregex()

Datum ltq_rregex ( PG_FUNCTION_ARGS  )

◆ ltree_prefix_eq()

bool ltree_prefix_eq ( const char *  a,
size_t  a_sz,
const char *  b,
size_t  b_sz 
)

Definition at line 82 of file lquery_op.c.

83{
84 if (a_sz > b_sz)
85 return false;
86 else
87 return (strncmp(a, b, a_sz) == 0);
88}
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, and b.

Referenced by checkcondition_str(), and checkLevel().

◆ ltree_prefix_eq_ci()

bool ltree_prefix_eq_ci ( const char *  a,
size_t  a_sz,
const char *  b,
size_t  b_sz 
)

Definition at line 94 of file lquery_op.c.

95{
96 static pg_locale_t locale = NULL;
97 size_t al_sz = a_sz + 1;
98 size_t al_len;
99 char *al = palloc(al_sz);
100 size_t bl_sz = b_sz + 1;
101 size_t bl_len;
102 char *bl = palloc(bl_sz);
103 bool res;
104
105 if (!locale)
107
108 /* casefold both a and b */
109
110 al_len = pg_strfold(al, al_sz, a, a_sz, locale);
111 if (al_len + 1 > al_sz)
112 {
113 /* grow buffer if needed and retry */
114 al_sz = al_len + 1;
115 al = repalloc(al, al_sz);
116 al_len = pg_strfold(al, al_sz, a, a_sz, locale);
117 Assert(al_len + 1 <= al_sz);
118 }
119
120 bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale);
121 if (bl_len + 1 > bl_sz)
122 {
123 /* grow buffer if needed and retry */
124 bl_sz = bl_len + 1;
125 bl = repalloc(bl, bl_sz);
126 bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale);
127 Assert(bl_len + 1 <= bl_sz);
128 }
129
130 if (al_len > bl_len)
131 res = false;
132 else
133 res = (strncmp(al, bl, al_len) == 0);
134
135 pfree(al);
136 pfree(bl);
137
138 return res;
139}
Assert(PointerIsAligned(start, uint64))
static char * locale
Definition: initdb.c:140
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1632
void pfree(void *pointer)
Definition: mcxt.c:1616
void * palloc(Size size)
Definition: mcxt.c:1387
size_t pg_strfold(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1348
pg_locale_t pg_database_locale(void)
Definition: pg_locale.c:1175

References a, Assert(), b, locale, palloc(), pfree(), pg_database_locale(), pg_strfold(), and repalloc().

Referenced by checkcondition_str(), and checkLevel().

◆ PG_FUNCTION_INFO_V1() [1/4]

PG_FUNCTION_INFO_V1 ( lt_q_regex  )

◆ PG_FUNCTION_INFO_V1() [2/4]

PG_FUNCTION_INFO_V1 ( lt_q_rregex  )

◆ PG_FUNCTION_INFO_V1() [3/4]

PG_FUNCTION_INFO_V1 ( ltq_regex  )

◆ PG_FUNCTION_INFO_V1() [4/4]

PG_FUNCTION_INFO_V1 ( ltq_rregex  )