PostgreSQL Source Code git master
Loading...
Searching...
No Matches
like_match.c File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define GETCHAR(t)   (t)
 

Functions

static int MatchText (const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
 

Macro Definition Documentation

◆ GETCHAR

#define GETCHAR (   t)    (t)

Definition at line 80 of file like_match.c.

Function Documentation

◆ MatchText()

static int MatchText ( const char t,
int  tlen,
const char p,
int  plen,
pg_locale_t  locale 
)
static

Definition at line 84 of file like_match.c.

85{
86 bool nondeterministic = (locale && !locale->deterministic);
87
88 /* Fast path for match-everything pattern */
89 if (plen == 1 && *p == '%')
90 return LIKE_TRUE;
91
92 /* Since this function recurses, it could be driven to stack overflow */
94
95 /*
96 * In this loop, we advance by char when matching wildcards (and thus on
97 * recursive entry to this function we are properly char-synced). On other
98 * occasions it is safe to advance by byte, as the text and pattern will
99 * be in lockstep. This allows us to perform all comparisons between the
100 * text and pattern on a byte by byte basis, even for multi-byte
101 * encodings. (But that doesn't work in a nondeterministic locale, so the
102 * nondeterministic case below has to advance the text by chars.)
103 */
104 while (tlen > 0 && plen > 0)
105 {
106 /*
107 * At the top of this loop, we are not positioned immediately after an
108 * escape, so we may take wildcards at face value.
109 */
110 if (*p == '%')
111 {
112 char firstpat;
113
114 /*
115 * % processing is essentially a search for a text position at
116 * which the remainder of the text matches the remainder of the
117 * pattern, using a recursive call to check each potential match.
118 *
119 * If there are wildcards immediately following the %, we can skip
120 * over them first, using the idea that any sequence of N _'s and
121 * one or more %'s is equivalent to N _'s and one % (ie, it will
122 * match any sequence of at least N text characters). In this way
123 * we will always run the recursive search loop using a pattern
124 * fragment that begins with a literal character-to-match, thereby
125 * not recursing more than we have to.
126 */
127 NextByte(p, plen);
128
129 while (plen > 0)
130 {
131 if (*p == '%')
132 NextByte(p, plen);
133 else if (*p == '_')
134 {
135 /* If not enough text left to match the pattern, ABORT */
136 if (tlen <= 0)
137 return LIKE_ABORT;
138 NextChar(t, tlen);
139 NextByte(p, plen);
140 }
141 else
142 break; /* Reached a non-wildcard pattern char */
143 }
144
145 /*
146 * If we're at end of pattern, match: we have a trailing % which
147 * matches any remaining text string.
148 */
149 if (plen <= 0)
150 return LIKE_TRUE;
151
152 /*
153 * Otherwise, scan for a text position at which we can match the
154 * rest of the pattern. The first remaining pattern char is known
155 * to be a regular or escaped literal character, so we can compare
156 * the first pattern byte to each text byte to avoid recursing
157 * more than we have to. This fact also guarantees that we don't
158 * have to consider a match to the zero-length substring at the
159 * end of the text. But with a nondeterministic locale, we can't
160 * rely on the first byte of a match being equal, so we have to
161 * recurse in any case.
162 */
163 if (*p == '\\')
164 {
165 if (plen < 2)
168 errmsg("LIKE pattern must not end with escape character")));
169 firstpat = GETCHAR(p[1]);
170 }
171 else
172 firstpat = GETCHAR(*p);
173
174 while (tlen > 0)
175 {
176 if (GETCHAR(*t) == firstpat || nondeterministic)
177 {
178 int matched = MatchText(t, tlen, p, plen, locale);
179
180 if (matched != LIKE_FALSE)
181 return matched; /* TRUE or ABORT */
182 }
183
184 NextChar(t, tlen);
185 }
186
187 /*
188 * End of text with no match, so no point in trying later places
189 * to start matching this pattern.
190 */
191 return LIKE_ABORT;
192 }
193 else if (*p == '_')
194 {
195 /* _ matches any single character, and we know there is one */
196 NextChar(t, tlen);
197 NextByte(p, plen);
198 continue;
199 }
200 else if (nondeterministic)
201 {
202 /*
203 * For nondeterministic locales, we find the next substring of the
204 * pattern that does not contain wildcards and try to find a
205 * matching substring in the text. Crucially, we cannot do this
206 * character by character, as in the normal case, but must do it
207 * substring by substring, partitioned by the wildcard characters.
208 * (This is per SQL standard.)
209 */
210 const char *p1;
211 size_t p1len;
212 const char *t1;
213 size_t t1len;
214 bool found_escape;
215 const char *subpat;
216 size_t subpatlen;
217 char *buf = NULL;
218
219 /*
220 * Determine length of substring of pattern without wildcards. p
221 * is the start of the subpattern, p1 will advance to one past its
222 * last byte. Also track if we found an escape character.
223 */
224 p1 = p;
225 p1len = plen;
226 found_escape = false;
227 while (p1len > 0)
228 {
229 if (*p1 == '\\')
230 {
231 found_escape = true;
232 NextByte(p1, p1len);
233 if (p1len == 0)
236 errmsg("LIKE pattern must not end with escape character")));
237 }
238 else if (*p1 == '_' || *p1 == '%')
239 break;
240 /* Advance over regular or escaped character */
241 NextByte(p1, p1len);
242 }
243
244 /*
245 * If we found an escape character, then make a de-escaped copy of
246 * the subpattern that we can use to match literally. Otherwise
247 * we can use the subpattern in-place. (buf holds the de-escaped
248 * copy; be sure to pfree it before returning.)
249 */
250 if (found_escape)
251 {
252 char *b;
253
254 b = buf = palloc(p1 - p);
255 for (const char *c = p; c < p1; c++)
256 {
257 if (*c == '\\')
258 c++; /* we already checked this isn't the end */
259 *(b++) = *c;
260 }
261
262 subpat = buf;
263 subpatlen = b - buf;
264 }
265 else
266 {
267 subpat = p;
268 subpatlen = p1 - p;
269 }
270
271 /*
272 * Shortcut: If this is the end of the pattern, then the rest of
273 * the text has to match the rest of the pattern.
274 */
275 if (p1len == 0)
276 {
277 int cmp;
278
279 cmp = pg_strncoll(subpat, subpatlen, t, tlen, locale);
280
281 if (buf)
282 pfree(buf);
283 if (cmp == 0)
284 return LIKE_TRUE;
285 else
286 return LIKE_FALSE;
287 }
288
289 /*
290 * Consider each successively-longer substring of the remaining
291 * text and try to match it against the subpattern. t is the
292 * start of the substring, t1 is one past its last byte. We start
293 * with a zero-length substring.
294 */
295 t1 = t;
296 t1len = tlen;
297 for (;;)
298 {
299 int cmp;
300
301 /* This could be slow, so allow interrupts */
303
304 cmp = pg_strncoll(subpat, subpatlen, t, (t1 - t), locale);
305
306 /*
307 * If we found a match, we have to test if the rest of pattern
308 * can match against the rest of the text. If not, we have to
309 * continue and try the next longer substring. (This is
310 * similar to the recursion for the '%' wildcard above.)
311 *
312 * Note that we can't just wind forward p and t and continue
313 * with the main loop. This would fail for example with
314 *
315 * U&'\0061\0308bc' LIKE U&'\00E4_c' COLLATE ignore_accents
316 *
317 * You'd find that t=\0061 matches p=\00E4, but then the rest
318 * won't match; but t=\0061\0308 also matches p=\00E4, and
319 * then the rest will match.
320 */
321 if (cmp == 0)
322 {
323 int matched = MatchText(t1, t1len, p1, p1len, locale);
324
325 if (matched == LIKE_TRUE)
326 {
327 if (buf)
328 pfree(buf);
329 return matched;
330 }
331 }
332
333 /*
334 * Didn't match. If we used up the whole text, then the match
335 * fails. Otherwise, try again with a longer substring.
336 */
337 if (t1len == 0)
338 {
339 if (buf)
340 pfree(buf);
341 return LIKE_FALSE;
342 }
343 else
344 NextChar(t1, t1len);
345 } /* end loop over substrings starting at t */
346 }
347 /* the rest of this loop considers only deterministic cases */
348 else if (*p == '\\')
349 {
350 /* Next pattern byte must match literally, whatever it is */
351 NextByte(p, plen);
352 /* ... and there had better be one, per SQL standard */
353 if (plen <= 0)
356 errmsg("LIKE pattern must not end with escape character")));
357 if (GETCHAR(*p) != GETCHAR(*t))
358 return LIKE_FALSE;
359 }
360 else if (GETCHAR(*p) != GETCHAR(*t))
361 {
362 /* non-wildcard pattern char fails to match text char */
363 return LIKE_FALSE;
364 }
365
366 /*
367 * Pattern and text match, so advance.
368 *
369 * It is safe to use NextByte instead of NextChar here, even for
370 * multi-byte character sets, because we are not following immediately
371 * after a wildcard character. If we are in the middle of a multibyte
372 * character, we must already have matched at least one byte of the
373 * character from both text and pattern; so we cannot get out-of-sync
374 * on character boundaries. And we know that no backend-legal
375 * encoding allows ASCII characters such as '%' to appear as non-first
376 * bytes of characters, so we won't mistakenly detect a new wildcard.
377 */
378 NextByte(t, tlen);
379 NextByte(p, plen);
380 }
381
382 if (tlen > 0)
383 return LIKE_FALSE; /* end of pattern, but not of text */
384
385 /*
386 * End of text, but perhaps not of pattern. Match iff the remaining
387 * pattern can match a zero-length string, ie, it's zero or more %'s.
388 */
389 while (plen > 0 && *p == '%')
390 NextByte(p, plen);
391 if (plen <= 0)
392 return LIKE_TRUE;
393
394 /*
395 * End of text with no match, so no point in trying later places to start
396 * matching this pattern.
397 */
398 return LIKE_ABORT;
399} /* MatchText() */
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
int b
Definition isn.c:74
#define LIKE_ABORT
Definition like.c:32
#define MatchText
Definition like.c:106
#define LIKE_TRUE
Definition like.c:30
#define LIKE_FALSE
Definition like.c:31
#define NextByte(p, plen)
Definition like.c:93
#define NextChar(p, plen)
Definition like.c:97
#define GETCHAR(t)
Definition like_match.c:80
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static char * errmsg
int pg_strncoll(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale)
Definition pg_locale.c:1406
static char buf[DEFAULT_XLOG_SEG_SIZE]
char * c
static int fb(int x)
static int cmp(const chr *x, const chr *y, size_t len)
void check_stack_depth(void)
Definition stack_depth.c:96

References b, buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), cmp(), pg_locale_struct::deterministic, ereport, errcode(), errmsg, ERROR, fb(), GETCHAR, LIKE_ABORT, LIKE_FALSE, LIKE_TRUE, MatchText, NextByte, NextChar, palloc(), pfree(), and pg_strncoll().