1/*-------------------------------------------------------------------------
4 * like expression handling code.
7 * A big hack of the regexp.c code!! Contributed by
8 * Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
10 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
14 * src/backend/utils/adt/like.c
16 *-------------------------------------------------------------------------
25#include "utils/fmgrprotos.h"
32 #define LIKE_ABORT (-1)
35 static int SB_MatchText(
const char *t,
int tlen,
const char *p,
int plen,
39 static int MB_MatchText(
const char *t,
int tlen,
const char *p,
int plen,
46 static int SB_IMatchText(
const char *t,
int tlen,
const char *p,
int plen,
49static int GenericMatchText(
const char *s,
int slen,
const char *p,
int plen,
Oid collation);
53 * Support routine for MatchText. Compares given multibyte streams
54 * as wide characters. If they match, returns 1 otherwise returns 0.
62 /* Optimization: quickly compare the first byte. */
70 /* They are the same length */
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.
90 * We do handle case-insensitive matching for single-byte encodings using
91 * fold-on-the-fly processing, however.
98 else if (
locale->is_default)
105 #define NextByte(p, plen) ((p)++, (plen)--)
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); \
115 *(dst)++ = *(src)++; \
118#define MatchText MB_MatchText
119#define do_like_escape MB_do_like_escape
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)--)
128#define MatchText SB_MatchText
129 #define do_like_escape SB_do_like_escape
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
140/* setup to compile like_match.c for UTF8 encoding, using fast NextChar */
142 #define NextChar(p, plen) \
143 do { (p)++; (plen)--; } while ((plen) > 0 && (*(p) & 0xC0) == 0x80 )
144 #define MatchText UTF8_MatchText
148/* Generic for all cases not requiring inline case-folding */
157 * This typically means that the parser could not resolve a conflict
158 * of implicit collations, so report it that way.
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.")));
188 * This typically means that the parser could not resolve a conflict
189 * of implicit collations, so report it that way.
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.")));
199 if (!
locale->deterministic)
201 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
202 errmsg(
"nondeterministic collations are not supported for ILIKE")));
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
240 * interface routines called by the function manager
370 * Case-insensitive versions
428 * like_escape() --- given a pattern and an ESCAPE string,
429 * convert the pattern to use Postgres' standard backslash escape convention.
447 * like_escape_bytea() --- given a pattern and an ESCAPE string,
448 * convert the pattern to use Postgres' standard backslash escape convention.
#define OidIsValid(objectId)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
#define PG_GETARG_BYTEA_PP(n)
#define PG_GETARG_TEXT_PP(n)
#define PG_RETURN_BYTEA_P(x)
#define DatumGetTextPP(X)
#define DirectFunctionCall1(func, arg1)
#define PG_GETARG_NAME(n)
#define PG_RETURN_TEXT_P(x)
#define PG_GET_COLLATION()
#define PG_RETURN_BOOL(x)
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)
Datum texticnlike(PG_FUNCTION_ARGS)
Datum textlike(PG_FUNCTION_ARGS)
Datum namelike(PG_FUNCTION_ARGS)
Datum nameiclike(PG_FUNCTION_ARGS)
Datum byteanlike(PG_FUNCTION_ARGS)
Datum like_escape(PG_FUNCTION_ARGS)
static int wchareq(const char *p1, const char *p2)
Datum namenlike(PG_FUNCTION_ARGS)
Datum textnlike(PG_FUNCTION_ARGS)
static int SB_IMatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
Datum nameicnlike(PG_FUNCTION_ARGS)
static char SB_lower_char(unsigned char c, pg_locale_t locale)
Datum like_escape_bytea(PG_FUNCTION_ARGS)
static text * SB_do_like_escape(text *pat, text *esc)
Datum texticlike(PG_FUNCTION_ARGS)
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)
Datum bytealike(PG_FUNCTION_ARGS)
static int GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation)
int GetDatabaseEncoding(void)
int pg_database_encoding_max_length(void)
int pg_mblen(const char *mbstr)
Datum lower(PG_FUNCTION_ARGS)
char char_tolower(unsigned char ch, pg_locale_t locale)
pg_locale_t pg_newlocale_from_collation(Oid collid)
bool char_tolower_enabled(pg_locale_t locale)
unsigned char pg_tolower(unsigned char ch)
unsigned char pg_ascii_tolower(unsigned char ch)
static Datum PointerGetDatum(const void *X)
static Datum NameGetDatum(const NameData *X)
static Size VARSIZE_ANY_EXHDR(const void *PTR)
static char * VARDATA_ANY(const void *PTR)
Datum name_text(PG_FUNCTION_ARGS)