PostgreSQL Source Code: src/backend/utils/adt/like.c Source File

PostgreSQL Source Code git master
like.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * like.c
4 * like expression handling code.
5 *
6 * NOTES
7 * A big hack of the regexp.c code!! Contributed by
8 * Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
9 *
10 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
12 *
13 * IDENTIFICATION
14 * src/backend/utils/adt/like.c
15 *
16 *-------------------------------------------------------------------------
17 */
18#include "postgres.h"
19
20#include <ctype.h>
21
22#include "catalog/pg_collation.h"
23#include "mb/pg_wchar.h"
24#include "miscadmin.h"
25#include "utils/fmgrprotos.h"
26#include "utils/pg_locale.h"
27#include "varatt.h"
28
29
30 #define LIKE_TRUE 1
31 #define LIKE_FALSE 0
32 #define LIKE_ABORT (-1)
33
34
35 static int SB_MatchText(const char *t, int tlen, const char *p, int plen,
36 pg_locale_t locale);
37 static text *SB_do_like_escape(text *pat, text *esc);
38
39 static int MB_MatchText(const char *t, int tlen, const char *p, int plen,
40 pg_locale_t locale);
41 static text *MB_do_like_escape(text *pat, text *esc);
42
43 static int UTF8_MatchText(const char *t, int tlen, const char *p, int plen,
44 pg_locale_t locale);
45
46 static int SB_IMatchText(const char *t, int tlen, const char *p, int plen,
47 pg_locale_t locale);
48
49static int GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation);
50static int Generic_Text_IC_like(text *str, text *pat, Oid collation);
51
52/*--------------------
53 * Support routine for MatchText. Compares given multibyte streams
54 * as wide characters. If they match, returns 1 otherwise returns 0.
55 *--------------------
56 */
57static inline int
58 wchareq(const char *p1, const char *p2)
59{
60 int p1_len;
61
62 /* Optimization: quickly compare the first byte. */
63 if (*p1 != *p2)
64 return 0;
65
66 p1_len = pg_mblen(p1);
67 if (pg_mblen(p2) != p1_len)
68 return 0;
69
70 /* They are the same length */
71 while (p1_len--)
72 {
73 if (*p1++ != *p2++)
74 return 0;
75 }
76 return 1;
77}
78
79/*
80 * Formerly we had a routine iwchareq() here that tried to do case-insensitive
81 * comparison of multibyte characters. It did not work at all, however,
82 * because it relied on tolower() which has a single-byte API ... and
83 * towlower() wouldn't be much better since we have no suitably cheap way
84 * of getting a single character transformed to the system's wchar_t format.
85 * So now, we just downcase the strings using lower() and apply regular LIKE
86 * comparison. This should be revisited when we install better locale support.
87 */
88
89/*
90 * We do handle case-insensitive matching for single-byte encodings using
91 * fold-on-the-fly processing, however.
92 */
93static char
94 SB_lower_char(unsigned char c, pg_locale_t locale)
95{
96 if (locale->ctype_is_c)
97 return pg_ascii_tolower(c);
98 else if (locale->is_default)
99 return pg_tolower(c);
100 else
101 return char_tolower(c, locale);
102}
103
104
105 #define NextByte(p, plen) ((p)++, (plen)--)
106
107/* Set up to compile like_match.c for multibyte characters */
108#define CHAREQ(p1, p2) wchareq((p1), (p2))
109#define NextChar(p, plen) \
110 do { int __l = pg_mblen(p); (p) +=__l; (plen) -=__l; } while (0)
111#define CopyAdvChar(dst, src, srclen) \
112 do { int __l = pg_mblen(src); \
113 (srclen) -= __l; \
114 while (__l-- > 0) \
115 *(dst)++ = *(src)++; \
116 } while (0)
117
118#define MatchText MB_MatchText
119#define do_like_escape MB_do_like_escape
120
121#include "like_match.c"
122
123/* Set up to compile like_match.c for single-byte characters */
124 #define CHAREQ(p1, p2) (*(p1) == *(p2))
125#define NextChar(p, plen) NextByte((p), (plen))
126 #define CopyAdvChar(dst, src, srclen) (*(dst)++ = *(src)++, (srclen)--)
127
128#define MatchText SB_MatchText
129 #define do_like_escape SB_do_like_escape
130
131#include "like_match.c"
132
133/* setup to compile like_match.c for single byte case insensitive matches */
134 #define MATCH_LOWER(t, locale) SB_lower_char((unsigned char) (t), locale)
135#define NextChar(p, plen) NextByte((p), (plen))
136#define MatchText SB_IMatchText
137
138#include "like_match.c"
139
140/* setup to compile like_match.c for UTF8 encoding, using fast NextChar */
141
142 #define NextChar(p, plen) \
143 do { (p)++; (plen)--; } while ((plen) > 0 && (*(p) & 0xC0) == 0x80 )
144 #define MatchText UTF8_MatchText
145
146#include "like_match.c"
147
148/* Generic for all cases not requiring inline case-folding */
149static inline int
150 GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation)
151{
152 pg_locale_t locale;
153
154 if (!OidIsValid(collation))
155 {
156 /*
157 * This typically means that the parser could not resolve a conflict
158 * of implicit collations, so report it that way.
159 */
160 ereport(ERROR,
161 (errcode(ERRCODE_INDETERMINATE_COLLATION),
162 errmsg("could not determine which collation to use for LIKE"),
163 errhint("Use the COLLATE clause to set the collation explicitly.")));
164 }
165
166 locale = pg_newlocale_from_collation(collation);
167
168 if (pg_database_encoding_max_length() == 1)
169 return SB_MatchText(s, slen, p, plen, locale);
170 else if (GetDatabaseEncoding() == PG_UTF8)
171 return UTF8_MatchText(s, slen, p, plen, locale);
172 else
173 return MB_MatchText(s, slen, p, plen, locale);
174}
175
176static inline int
177 Generic_Text_IC_like(text *str, text *pat, Oid collation)
178{
179 char *s,
180 *p;
181 int slen,
182 plen;
183 pg_locale_t locale;
184
185 if (!OidIsValid(collation))
186 {
187 /*
188 * This typically means that the parser could not resolve a conflict
189 * of implicit collations, so report it that way.
190 */
191 ereport(ERROR,
192 (errcode(ERRCODE_INDETERMINATE_COLLATION),
193 errmsg("could not determine which collation to use for ILIKE"),
194 errhint("Use the COLLATE clause to set the collation explicitly.")));
195 }
196
197 locale = pg_newlocale_from_collation(collation);
198
199 if (!locale->deterministic)
200 ereport(ERROR,
201 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
202 errmsg("nondeterministic collations are not supported for ILIKE")));
203
204 /*
205 * For efficiency reasons, in the single byte case we don't call lower()
206 * on the pattern and text, but instead call SB_lower_char on each
207 * character. In the multi-byte case we don't have much choice :-(. Also,
208 * ICU does not support single-character case folding, so we go the long
209 * way.
210 */
211
212 if (locale->ctype_is_c ||
213 (char_tolower_enabled(locale) &&
214 pg_database_encoding_max_length() == 1))
215 {
216 p = VARDATA_ANY(pat);
217 plen = VARSIZE_ANY_EXHDR(pat);
218 s = VARDATA_ANY(str);
219 slen = VARSIZE_ANY_EXHDR(str);
220 return SB_IMatchText(s, slen, p, plen, locale);
221 }
222 else
223 {
224 pat = DatumGetTextPP(DirectFunctionCall1Coll(lower, collation,
225 PointerGetDatum(pat)));
226 p = VARDATA_ANY(pat);
227 plen = VARSIZE_ANY_EXHDR(pat);
228 str = DatumGetTextPP(DirectFunctionCall1Coll(lower, collation,
229 PointerGetDatum(str)));
230 s = VARDATA_ANY(str);
231 slen = VARSIZE_ANY_EXHDR(str);
232 if (GetDatabaseEncoding() == PG_UTF8)
233 return UTF8_MatchText(s, slen, p, plen, 0);
234 else
235 return MB_MatchText(s, slen, p, plen, 0);
236 }
237}
238
239/*
240 * interface routines called by the function manager
241 */
242
243Datum
244 namelike(PG_FUNCTION_ARGS)
245{
246 Name str = PG_GETARG_NAME(0);
247 text *pat = PG_GETARG_TEXT_PP(1);
248 bool result;
249 char *s,
250 *p;
251 int slen,
252 plen;
253
254 s = NameStr(*str);
255 slen = strlen(s);
256 p = VARDATA_ANY(pat);
257 plen = VARSIZE_ANY_EXHDR(pat);
258
259 result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) == LIKE_TRUE);
260
261 PG_RETURN_BOOL(result);
262}
263
264Datum
265 namenlike(PG_FUNCTION_ARGS)
266{
267 Name str = PG_GETARG_NAME(0);
268 text *pat = PG_GETARG_TEXT_PP(1);
269 bool result;
270 char *s,
271 *p;
272 int slen,
273 plen;
274
275 s = NameStr(*str);
276 slen = strlen(s);
277 p = VARDATA_ANY(pat);
278 plen = VARSIZE_ANY_EXHDR(pat);
279
280 result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) != LIKE_TRUE);
281
282 PG_RETURN_BOOL(result);
283}
284
285Datum
286 textlike(PG_FUNCTION_ARGS)
287{
288 text *str = PG_GETARG_TEXT_PP(0);
289 text *pat = PG_GETARG_TEXT_PP(1);
290 bool result;
291 char *s,
292 *p;
293 int slen,
294 plen;
295
296 s = VARDATA_ANY(str);
297 slen = VARSIZE_ANY_EXHDR(str);
298 p = VARDATA_ANY(pat);
299 plen = VARSIZE_ANY_EXHDR(pat);
300
301 result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) == LIKE_TRUE);
302
303 PG_RETURN_BOOL(result);
304}
305
306Datum
307 textnlike(PG_FUNCTION_ARGS)
308{
309 text *str = PG_GETARG_TEXT_PP(0);
310 text *pat = PG_GETARG_TEXT_PP(1);
311 bool result;
312 char *s,
313 *p;
314 int slen,
315 plen;
316
317 s = VARDATA_ANY(str);
318 slen = VARSIZE_ANY_EXHDR(str);
319 p = VARDATA_ANY(pat);
320 plen = VARSIZE_ANY_EXHDR(pat);
321
322 result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) != LIKE_TRUE);
323
324 PG_RETURN_BOOL(result);
325}
326
327Datum
328 bytealike(PG_FUNCTION_ARGS)
329{
330 bytea *str = PG_GETARG_BYTEA_PP(0);
331 bytea *pat = PG_GETARG_BYTEA_PP(1);
332 bool result;
333 char *s,
334 *p;
335 int slen,
336 plen;
337
338 s = VARDATA_ANY(str);
339 slen = VARSIZE_ANY_EXHDR(str);
340 p = VARDATA_ANY(pat);
341 plen = VARSIZE_ANY_EXHDR(pat);
342
343 result = (SB_MatchText(s, slen, p, plen, 0) == LIKE_TRUE);
344
345 PG_RETURN_BOOL(result);
346}
347
348Datum
349 byteanlike(PG_FUNCTION_ARGS)
350{
351 bytea *str = PG_GETARG_BYTEA_PP(0);
352 bytea *pat = PG_GETARG_BYTEA_PP(1);
353 bool result;
354 char *s,
355 *p;
356 int slen,
357 plen;
358
359 s = VARDATA_ANY(str);
360 slen = VARSIZE_ANY_EXHDR(str);
361 p = VARDATA_ANY(pat);
362 plen = VARSIZE_ANY_EXHDR(pat);
363
364 result = (SB_MatchText(s, slen, p, plen, 0) != LIKE_TRUE);
365
366 PG_RETURN_BOOL(result);
367}
368
369/*
370 * Case-insensitive versions
371 */
372
373Datum
374 nameiclike(PG_FUNCTION_ARGS)
375{
376 Name str = PG_GETARG_NAME(0);
377 text *pat = PG_GETARG_TEXT_PP(1);
378 bool result;
379 text *strtext;
380
381 strtext = DatumGetTextPP(DirectFunctionCall1(name_text,
382 NameGetDatum(str)));
383 result = (Generic_Text_IC_like(strtext, pat, PG_GET_COLLATION()) == LIKE_TRUE);
384
385 PG_RETURN_BOOL(result);
386}
387
388Datum
389 nameicnlike(PG_FUNCTION_ARGS)
390{
391 Name str = PG_GETARG_NAME(0);
392 text *pat = PG_GETARG_TEXT_PP(1);
393 bool result;
394 text *strtext;
395
396 strtext = DatumGetTextPP(DirectFunctionCall1(name_text,
397 NameGetDatum(str)));
398 result = (Generic_Text_IC_like(strtext, pat, PG_GET_COLLATION()) != LIKE_TRUE);
399
400 PG_RETURN_BOOL(result);
401}
402
403Datum
404 texticlike(PG_FUNCTION_ARGS)
405{
406 text *str = PG_GETARG_TEXT_PP(0);
407 text *pat = PG_GETARG_TEXT_PP(1);
408 bool result;
409
410 result = (Generic_Text_IC_like(str, pat, PG_GET_COLLATION()) == LIKE_TRUE);
411
412 PG_RETURN_BOOL(result);
413}
414
415Datum
416 texticnlike(PG_FUNCTION_ARGS)
417{
418 text *str = PG_GETARG_TEXT_PP(0);
419 text *pat = PG_GETARG_TEXT_PP(1);
420 bool result;
421
422 result = (Generic_Text_IC_like(str, pat, PG_GET_COLLATION()) != LIKE_TRUE);
423
424 PG_RETURN_BOOL(result);
425}
426
427/*
428 * like_escape() --- given a pattern and an ESCAPE string,
429 * convert the pattern to use Postgres' standard backslash escape convention.
430 */
431Datum
432 like_escape(PG_FUNCTION_ARGS)
433{
434 text *pat = PG_GETARG_TEXT_PP(0);
435 text *esc = PG_GETARG_TEXT_PP(1);
436 text *result;
437
438 if (pg_database_encoding_max_length() == 1)
439 result = SB_do_like_escape(pat, esc);
440 else
441 result = MB_do_like_escape(pat, esc);
442
443 PG_RETURN_TEXT_P(result);
444}
445
446/*
447 * like_escape_bytea() --- given a pattern and an ESCAPE string,
448 * convert the pattern to use Postgres' standard backslash escape convention.
449 */
450Datum
451 like_escape_bytea(PG_FUNCTION_ARGS)
452{
453 bytea *pat = PG_GETARG_BYTEA_PP(0);
454 bytea *esc = PG_GETARG_BYTEA_PP(1);
455 bytea *result = SB_do_like_escape((text *) pat, (text *) esc);
456
457 PG_RETURN_BYTEA_P((bytea *) result);
458}
#define NameStr(name)
Definition: c.h:751
#define OidIsValid(objectId)
Definition: c.h:774
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
Definition: fmgr.c:793
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define DatumGetTextPP(X)
Definition: fmgr.h:292
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
const char * str
static char * locale
Definition: initdb.c:140
static int UTF8_MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
static int MB_MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
static text * MB_do_like_escape(text *pat, text *esc)
#define LIKE_TRUE
Definition: like.c:30
Datum texticnlike(PG_FUNCTION_ARGS)
Definition: like.c:416
Datum textlike(PG_FUNCTION_ARGS)
Definition: like.c:286
Datum namelike(PG_FUNCTION_ARGS)
Definition: like.c:244
Datum nameiclike(PG_FUNCTION_ARGS)
Definition: like.c:374
Datum byteanlike(PG_FUNCTION_ARGS)
Definition: like.c:349
Datum like_escape(PG_FUNCTION_ARGS)
Definition: like.c:432
static int wchareq(const char *p1, const char *p2)
Definition: like.c:58
Datum namenlike(PG_FUNCTION_ARGS)
Definition: like.c:265
Datum textnlike(PG_FUNCTION_ARGS)
Definition: like.c:307
static int SB_IMatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
Datum nameicnlike(PG_FUNCTION_ARGS)
Definition: like.c:389
static char SB_lower_char(unsigned char c, pg_locale_t locale)
Definition: like.c:94
Datum like_escape_bytea(PG_FUNCTION_ARGS)
Definition: like.c:451
static text * SB_do_like_escape(text *pat, text *esc)
Datum texticlike(PG_FUNCTION_ARGS)
Definition: like.c:404
static int SB_MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
static int Generic_Text_IC_like(text *str, text *pat, Oid collation)
Definition: like.c:177
Datum bytealike(PG_FUNCTION_ARGS)
Definition: like.c:328
static int GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation)
Definition: like.c:150
int GetDatabaseEncoding(void)
Definition: mbutils.c:1262
int pg_database_encoding_max_length(void)
Definition: mbutils.c:1547
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:49
char char_tolower(unsigned char ch, pg_locale_t locale)
Definition: pg_locale.c:1428
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1166
bool char_tolower_enabled(pg_locale_t locale)
Definition: pg_locale.c:1417
@ PG_UTF8
Definition: pg_wchar.h:232
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122
unsigned char pg_ascii_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:146
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:383
uint64_t Datum
Definition: postgres.h:70
unsigned int Oid
Definition: postgres_ext.h:32
c
char * c
Definition: preproc-cursor.c:31
Definition: c.h:746
Definition: c.h:692
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486
Datum name_text(PG_FUNCTION_ARGS)
Definition: varlena.c:2669

AltStyle によって変換されたページ (->オリジナル) /