PostgreSQL Source Code git master
Loading...
Searching...
No Matches
like_match.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * like_match.c
4 * LIKE pattern matching internal code.
5 *
6 * This file is included by like.c four times, to provide matching code for
7 * (1) single-byte encodings, (2) UTF8, (3) other multi-byte encodings,
8 * and (4) case insensitive matches in single-byte encodings.
9 * (UTF8 is a special case because we can use a much more efficient version
10 * of NextChar than can be used for general multi-byte encodings.)
11 *
12 * Before the inclusion, we need to define the following macros:
13 *
14 * NextChar
15 * MatchText - to name of function wanted
16 * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar
17 * MATCH_LOWER - define for case (4) to specify case folding for 1-byte chars
18 *
19 * Copyright (c) 1996-2026, PostgreSQL Global Development Group
20 *
21 * IDENTIFICATION
22 * src/backend/utils/adt/like_match.c
23 *
24 *-------------------------------------------------------------------------
25 */
26
27/*
28 * Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
29 * Rich $alz is now <rsalz@bbn.com>.
30 * Special thanks to Lars Mathiesen <thorinn@diku.dk> for the
31 * LIKE_ABORT code.
32 *
33 * This code was shamelessly stolen from the "pql" code by myself and
34 * slightly modified :)
35 *
36 * All references to the word "star" were replaced by "percent"
37 * All references to the word "wild" were replaced by "like"
38 *
39 * All the nice shell RE matching stuff was replaced by just "_" and "%"
40 *
41 * As I don't have a copy of the SQL standard handy I wasn't sure whether
42 * to leave in the '\' escape character handling.
43 *
44 * Keith Parks. <keith@mtcc.demon.co.uk>
45 *
46 * SQL lets you specify the escape character by saying
47 * LIKE <pattern> ESCAPE <escape character>. We are a small operation
48 * so we force you to use '\'. - ay 7/95
49 *
50 * Now we have the like_escape() function that converts patterns with
51 * any specified escape character (or none at all) to the internal
52 * default escape character, which is still '\'. - tgl 9/2000
53 *
54 * The code is rewritten to avoid requiring null-terminated strings,
55 * which in turn allows us to leave out some memcpy() operations.
56 * This code should be faster and take less memory, but no promises...
57 * - thomas 2000-08-06
58 */
59
60
61/*--------------------
62 * Match text and pattern, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
63 *
64 * LIKE_TRUE: they match
65 * LIKE_FALSE: they don't match
66 * LIKE_ABORT: not only don't they match, but the text is too short.
67 *
68 * If LIKE_ABORT is returned, then no suffix of the text can match the
69 * pattern either, so an upper-level % scan can stop scanning now.
70 *--------------------
71 */
72
73/*
74 * MATCH_LOWER is defined for ILIKE in the C locale as an optimization. Other
75 * locales must casefold the inputs before matching.
76 */
77#ifdef MATCH_LOWER
78#define GETCHAR(t) pg_ascii_tolower(t)
79#else
80#define GETCHAR(t) (t)
81#endif
82
83static int
84MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
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() */
400
401/*
402 * like_escape() --- given a pattern and an ESCAPE string,
403 * convert the pattern to use Postgres' standard backslash escape convention.
404 */
405#ifdef do_like_escape
406
407static text *
409{
410 text *result;
411 char *p,
412 *e,
413 *r;
414 int plen,
415 elen;
416 bool afterescape;
417
418 p = VARDATA_ANY(pat);
419 plen = VARSIZE_ANY_EXHDR(pat);
420 e = VARDATA_ANY(esc);
422
423 /*
424 * Worst-case pattern growth is 2x --- unlikely, but it's hardly worth
425 * trying to calculate the size more accurately than that.
426 */
427 result = (text *) palloc(plen * 2 + VARHDRSZ);
428 r = VARDATA(result);
429
430 if (elen == 0)
431 {
432 /*
433 * No escape character is wanted. Double any backslashes in the
434 * pattern to make them act like ordinary characters.
435 */
436 while (plen > 0)
437 {
438 if (*p == '\\')
439 *r++ = '\\';
440 CopyAdvChar(r, p, plen);
441 }
442 }
443 else
444 {
445 /*
446 * The specified escape must be only a single character.
447 */
448 NextChar(e, elen);
449 if (elen != 0)
452 errmsg("invalid escape string"),
453 errhint("Escape string must be empty or one character.")));
454
455 e = VARDATA_ANY(esc);
457
458 /*
459 * If specified escape is '\', just copy the pattern as-is.
460 */
461 if (*e == '\\')
462 {
464 return result;
465 }
466
467 /*
468 * Otherwise, convert occurrences of the specified escape character to
469 * '\', and double occurrences of '\' --- unless they immediately
470 * follow an escape character!
471 */
472 afterescape = false;
473 while (plen > 0)
474 {
475 if (CHAREQ(p, plen, e, elen) && !afterescape)
476 {
477 *r++ = '\\';
478 NextChar(p, plen);
479 afterescape = true;
480 }
481 else if (*p == '\\')
482 {
483 *r++ = '\\';
484 if (!afterescape)
485 *r++ = '\\';
486 NextChar(p, plen);
487 afterescape = false;
488 }
489 else
490 {
491 CopyAdvChar(r, p, plen);
492 afterescape = false;
493 }
494 }
495 }
496
497 SET_VARSIZE(result, r - ((char *) result));
498
499 return result;
500}
501#endif /* do_like_escape */
502
503#ifdef CHAREQ
504#undef CHAREQ
505#endif
506
507#undef NextChar
508#undef CopyAdvChar
509#undef MatchText
510
511#ifdef do_like_escape
512#undef do_like_escape
513#endif
514
515#undef GETCHAR
516
517#ifdef MATCH_LOWER
518#undef MATCH_LOWER
519
520#endif
#define VARHDRSZ
Definition c.h:840
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#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 CopyAdvChar(dst, src, srclen)
Definition like.c:99
#define MatchText
Definition like.c:106
#define LIKE_TRUE
Definition like.c:30
#define LIKE_FALSE
Definition like.c:31
#define CHAREQ(p1, p1len, p2, p2len)
Definition like.c:96
#define NextByte(p, plen)
Definition like.c:93
#define do_like_escape
Definition like.c:107
#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
e
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
Definition c.h:835
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432