1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* like.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* like expression handling code.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* NOTES
|
|
|
|
* A big hack of the regexp.c code!! Contributed by
|
|
|
|
* Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2021-01-02 19:06:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1999-09-07 21:09:46 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/like.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1999-07-16 05:14:30 +02:00
|
|
|
#include "postgres.h"
|
2000-09-15 20:45:31 +02:00
|
|
|
|
2000-08-07 03:45:00 +02:00
|
|
|
#include <ctype.h>
|
2000-09-15 20:45:31 +02:00
|
|
|
|
2011-04-09 23:12:39 +02:00
|
|
|
#include "catalog/pg_collation.h"
|
1998-07-24 05:32:46 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
2015-10-02 21:00:51 +02:00
|
|
|
#include "miscadmin.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/builtins.h"
|
2011-04-09 23:12:39 +02:00
|
|
|
#include "utils/pg_locale.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-08-06 20:06:44 +02:00
|
|
|
|
|
|
|
#define LIKE_TRUE 1
|
|
|
|
#define LIKE_FALSE 0
|
|
|
|
#define LIKE_ABORT (-1)
|
|
|
|
|
|
|
|
|
2019-05-22 19:04:48 +02:00
|
|
|
static int SB_MatchText(const char *t, int tlen, const char *p, int plen,
|
|
|
|
pg_locale_t locale, bool locale_is_c);
|
2007-06-02 04:03:42 +02:00
|
|
|
static text *SB_do_like_escape(text *, text *);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
2019-05-22 19:04:48 +02:00
|
|
|
static int MB_MatchText(const char *t, int tlen, const char *p, int plen,
|
|
|
|
pg_locale_t locale, bool locale_is_c);
|
2001-10-04 04:15:47 +02:00
|
|
|
static text *MB_do_like_escape(text *, text *);
|
|
|
|
|
2019-05-22 19:04:48 +02:00
|
|
|
static int UTF8_MatchText(const char *t, int tlen, const char *p, int plen,
|
|
|
|
pg_locale_t locale, bool locale_is_c);
|
2007-06-02 04:03:42 +02:00
|
|
|
|
2019-05-22 19:04:48 +02:00
|
|
|
static int SB_IMatchText(const char *t, int tlen, const char *p, int plen,
|
|
|
|
pg_locale_t locale, bool locale_is_c);
|
2007-09-22 05:58:34 +02:00
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
static int GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation);
|
2011-02-08 22:04:18 +01:00
|
|
|
static int Generic_Text_IC_like(text *str, text *pat, Oid collation);
|
2007-06-02 04:03:42 +02:00
|
|
|
|
2000-09-15 20:45:31 +02:00
|
|
|
/*--------------------
|
|
|
|
* Support routine for MatchText. Compares given multibyte streams
|
|
|
|
* as wide characters. If they match, returns 1 otherwise returns 0.
|
|
|
|
*--------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2007-06-02 04:03:42 +02:00
|
|
|
static inline int
|
2019-02-08 10:13:24 +01:00
|
|
|
wchareq(const char *p1, const char *p2)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2005-05-26 00:59:33 +02:00
|
|
|
int p1_len;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2005-05-26 00:59:33 +02:00
|
|
|
/* Optimization: quickly compare the first byte. */
|
2005-10-15 04:49:52 +02:00
|
|
|
if (*p1 != *p2)
|
2006-01-11 09:43:13 +01:00
|
|
|
return 0;
|
2005-05-26 00:59:33 +02:00
|
|
|
|
|
|
|
p1_len = pg_mblen(p1);
|
|
|
|
if (pg_mblen(p2) != p1_len)
|
2006-01-11 09:43:13 +01:00
|
|
|
return 0;
|
2005-05-26 00:59:33 +02:00
|
|
|
|
|
|
|
/* They are the same length */
|
|
|
|
while (p1_len--)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2000-09-15 20:45:31 +02:00
|
|
|
if (*p1++ != *p2++)
|
2006-01-11 09:43:13 +01:00
|
|
|
return 0;
|
2000-09-15 20:45:31 +02:00
|
|
|
}
|
2006-01-11 09:43:13 +01:00
|
|
|
return 1;
|
2000-09-15 20:45:31 +02:00
|
|
|
}
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2006-09-04 20:32:55 +02:00
|
|
|
/*
|
|
|
|
* Formerly we had a routine iwchareq() here that tried to do case-insensitive
|
2014-05-06 18:12:18 +02:00
|
|
|
* comparison of multibyte characters. It did not work at all, however,
|
2006-09-04 20:32:55 +02:00
|
|
|
* because it relied on tolower() which has a single-byte API ... and
|
|
|
|
* towlower() wouldn't be much better since we have no suitably cheap way
|
|
|
|
* of getting a single character transformed to the system's wchar_t format.
|
|
|
|
* So now, we just downcase the strings using lower() and apply regular LIKE
|
2014-05-06 18:12:18 +02:00
|
|
|
* comparison. This should be revisited when we install better locale support.
|
2000-09-15 20:45:31 +02:00
|
|
|
*/
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2011-04-09 23:12:39 +02:00
|
|
|
/*
|
|
|
|
* We do handle case-insensitive matching for single-byte encodings using
|
|
|
|
* fold-on-the-fly processing, however.
|
|
|
|
*/
|
|
|
|
static char
|
|
|
|
SB_lower_char(unsigned char c, pg_locale_t locale, bool locale_is_c)
|
|
|
|
{
|
|
|
|
if (locale_is_c)
|
|
|
|
return pg_ascii_tolower(c);
|
|
|
|
#ifdef HAVE_LOCALE_T
|
|
|
|
else if (locale)
|
2017-03-23 20:25:34 +01:00
|
|
|
return tolower_l(c, locale->info.lt);
|
2011-04-09 23:12:39 +02:00
|
|
|
#endif
|
|
|
|
else
|
|
|
|
return pg_tolower(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-02 04:03:42 +02:00
|
|
|
#define NextByte(p, plen) ((p)++, (plen)--)
|
|
|
|
|
2006-09-04 20:32:55 +02:00
|
|
|
/* Set up to compile like_match.c for multibyte characters */
|
2007-06-02 04:03:42 +02:00
|
|
|
#define CHAREQ(p1, p2) wchareq((p1), (p2))
|
2000-09-15 20:45:31 +02:00
|
|
|
#define NextChar(p, plen) \
|
|
|
|
do { int __l = pg_mblen(p); (p) +=__l; (plen) -=__l; } while (0)
|
|
|
|
#define CopyAdvChar(dst, src, srclen) \
|
|
|
|
do { int __l = pg_mblen(src); \
|
|
|
|
(srclen) -= __l; \
|
|
|
|
while (__l-- > 0) \
|
|
|
|
*(dst)++ = *(src)++; \
|
|
|
|
} while (0)
|
2001-10-04 04:15:47 +02:00
|
|
|
|
2007-06-02 04:03:42 +02:00
|
|
|
#define MatchText MB_MatchText
|
2001-10-04 04:15:47 +02:00
|
|
|
#define do_like_escape MB_do_like_escape
|
2006-09-04 20:32:55 +02:00
|
|
|
|
2001-10-04 04:15:47 +02:00
|
|
|
#include "like_match.c"
|
2006-09-04 20:32:55 +02:00
|
|
|
|
|
|
|
/* Set up to compile like_match.c for single-byte characters */
|
2000-09-15 20:45:31 +02:00
|
|
|
#define CHAREQ(p1, p2) (*(p1) == *(p2))
|
2007-06-02 04:03:42 +02:00
|
|
|
#define NextChar(p, plen) NextByte((p), (plen))
|
2000-09-15 20:45:31 +02:00
|
|
|
#define CopyAdvChar(dst, src, srclen) (*(dst)++ = *(src)++, (srclen)--)
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2007-06-02 04:03:42 +02:00
|
|
|
#define MatchText SB_MatchText
|
|
|
|
#define do_like_escape SB_do_like_escape
|
|
|
|
|
|
|
|
#include "like_match.c"
|
|
|
|
|
2007-09-22 05:58:34 +02:00
|
|
|
/* setup to compile like_match.c for single byte case insensitive matches */
|
2011-04-09 23:12:39 +02:00
|
|
|
#define MATCH_LOWER(t) SB_lower_char((unsigned char) (t), locale, locale_is_c)
|
2007-09-22 05:58:34 +02:00
|
|
|
#define NextChar(p, plen) NextByte((p), (plen))
|
|
|
|
#define MatchText SB_IMatchText
|
|
|
|
|
|
|
|
#include "like_match.c"
|
2007-06-02 04:03:42 +02:00
|
|
|
|
|
|
|
/* setup to compile like_match.c for UTF8 encoding, using fast NextChar */
|
|
|
|
|
|
|
|
#define NextChar(p, plen) \
|
2007-11-15 22:14:46 +01:00
|
|
|
do { (p)++; (plen)--; } while ((plen) > 0 && (*(p) & 0xC0) == 0x80 )
|
2007-06-02 04:03:42 +02:00
|
|
|
#define MatchText UTF8_MatchText
|
|
|
|
|
2006-09-04 20:32:55 +02:00
|
|
|
#include "like_match.c"
|
|
|
|
|
2011-04-09 23:12:39 +02:00
|
|
|
/* Generic for all cases not requiring inline case-folding */
|
2007-06-02 04:03:42 +02:00
|
|
|
static inline int
|
2019-03-22 12:09:32 +01:00
|
|
|
GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation)
|
2007-06-02 04:03:42 +02:00
|
|
|
{
|
2019-03-22 12:09:32 +01:00
|
|
|
if (collation && !lc_ctype_is_c(collation) && collation != DEFAULT_COLLATION_OID)
|
|
|
|
{
|
2019-05-22 18:55:34 +02:00
|
|
|
pg_locale_t locale = pg_newlocale_from_collation(collation);
|
2019-03-22 12:09:32 +01:00
|
|
|
|
|
|
|
if (locale && !locale->deterministic)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("nondeterministic collations are not supported for LIKE")));
|
|
|
|
}
|
|
|
|
|
2007-06-02 04:03:42 +02:00
|
|
|
if (pg_database_encoding_max_length() == 1)
|
2011-04-09 23:12:39 +02:00
|
|
|
return SB_MatchText(s, slen, p, plen, 0, true);
|
2007-06-02 04:03:42 +02:00
|
|
|
else if (GetDatabaseEncoding() == PG_UTF8)
|
2011-04-09 23:12:39 +02:00
|
|
|
return UTF8_MatchText(s, slen, p, plen, 0, true);
|
2007-06-02 04:03:42 +02:00
|
|
|
else
|
2011-04-09 23:12:39 +02:00
|
|
|
return MB_MatchText(s, slen, p, plen, 0, true);
|
2007-06-02 04:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2011-02-08 22:04:18 +01:00
|
|
|
Generic_Text_IC_like(text *str, text *pat, Oid collation)
|
2007-06-02 04:03:42 +02:00
|
|
|
{
|
|
|
|
char *s,
|
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
2017-03-23 20:25:34 +01:00
|
|
|
pg_locale_t locale = 0;
|
|
|
|
bool locale_is_c = false;
|
|
|
|
|
|
|
|
if (lc_ctype_is_c(collation))
|
|
|
|
locale_is_c = true;
|
|
|
|
else if (collation != DEFAULT_COLLATION_OID)
|
|
|
|
{
|
|
|
|
if (!OidIsValid(collation))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This typically means that the parser could not resolve a
|
|
|
|
* conflict of implicit collations, so report it that way.
|
|
|
|
*/
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("could not determine which collation to use for ILIKE"),
|
2017-03-23 20:25:34 +01:00
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
}
|
|
|
|
locale = pg_newlocale_from_collation(collation);
|
2019-03-22 12:09:32 +01:00
|
|
|
|
|
|
|
if (locale && !locale->deterministic)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("nondeterministic collations are not supported for ILIKE")));
|
2017-03-23 20:25:34 +01:00
|
|
|
}
|
2007-06-02 04:03:42 +02:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
|
|
|
* For efficiency reasons, in the single byte case we don't call lower()
|
2011-04-09 23:12:39 +02:00
|
|
|
* on the pattern and text, but instead call SB_lower_char on each
|
2017-05-17 22:31:56 +02:00
|
|
|
* character. In the multi-byte case we don't have much choice :-(. Also,
|
|
|
|
* ICU does not support single-character case folding, so we go the long
|
|
|
|
* way.
|
2007-09-22 05:58:34 +02:00
|
|
|
*/
|
2006-09-04 20:32:55 +02:00
|
|
|
|
2017-03-23 21:31:39 +01:00
|
|
|
if (pg_database_encoding_max_length() > 1 || (locale && locale->provider == COLLPROVIDER_ICU))
|
2007-09-22 05:58:34 +02:00
|
|
|
{
|
2017-03-13 00:35:34 +01:00
|
|
|
pat = DatumGetTextPP(DirectFunctionCall1Coll(lower, collation,
|
|
|
|
PointerGetDatum(pat)));
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
|
|
|
str = DatumGetTextPP(DirectFunctionCall1Coll(lower, collation,
|
|
|
|
PointerGetDatum(str)));
|
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
2007-09-22 05:58:34 +02:00
|
|
|
if (GetDatabaseEncoding() == PG_UTF8)
|
2011-04-09 23:12:39 +02:00
|
|
|
return UTF8_MatchText(s, slen, p, plen, 0, true);
|
2007-09-22 05:58:34 +02:00
|
|
|
else
|
2011-04-09 23:12:39 +02:00
|
|
|
return MB_MatchText(s, slen, p, plen, 0, true);
|
2007-09-22 05:58:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
2011-04-09 23:12:39 +02:00
|
|
|
return SB_IMatchText(s, slen, p, plen, locale, locale_is_c);
|
2007-09-22 05:58:34 +02:00
|
|
|
}
|
2007-06-02 04:03:42 +02:00
|
|
|
}
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2000-09-15 20:45:31 +02:00
|
|
|
/*
|
|
|
|
* interface routines called by the function manager
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-06 20:06:44 +02:00
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
namelike(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2000-08-09 16:13:03 +02:00
|
|
|
Name str = PG_GETARG_NAME(0);
|
2007-09-22 00:52:52 +02:00
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-09-15 20:45:31 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-03-22 05:01:46 +01:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
s = NameStr(*str);
|
|
|
|
slen = strlen(s);
|
2007-09-22 00:52:52 +02:00
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) == LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-08-06 20:06:44 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-06 20:06:44 +02:00
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
namenlike(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2000-08-09 16:13:03 +02:00
|
|
|
Name str = PG_GETARG_NAME(0);
|
2007-09-22 00:52:52 +02:00
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-09-15 20:45:31 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-03-22 05:01:46 +01:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
s = NameStr(*str);
|
|
|
|
slen = strlen(s);
|
2007-09-22 00:52:52 +02:00
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) != LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-07-06 07:48:31 +02:00
|
|
|
Datum
|
2000-08-06 20:06:44 +02:00
|
|
|
textlike(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *str = PG_GETARG_TEXT_PP(0);
|
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-08-09 16:13:03 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-03-22 05:01:46 +01:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2007-09-22 00:52:52 +02:00
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) == LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-08-06 20:06:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
textnlike(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *str = PG_GETARG_TEXT_PP(0);
|
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-08-09 16:13:03 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-03-22 05:01:46 +01:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2007-09-22 00:52:52 +02:00
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
result = (GenericMatchText(s, slen, p, plen, PG_GET_COLLATION()) != LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-08-06 20:06:44 +02:00
|
|
|
}
|
|
|
|
|
2001-09-14 19:46:40 +02:00
|
|
|
Datum
|
|
|
|
bytealike(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
bytea *str = PG_GETARG_BYTEA_PP(0);
|
|
|
|
bytea *pat = PG_GETARG_BYTEA_PP(1);
|
2001-09-14 19:46:40 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-09-14 19:46:40 +02:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
|
|
|
|
2007-09-22 00:52:52 +02:00
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2001-09-14 19:46:40 +02:00
|
|
|
|
2011-04-09 23:12:39 +02:00
|
|
|
result = (SB_MatchText(s, slen, p, plen, 0, true) == LIKE_TRUE);
|
2001-09-14 19:46:40 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
byteanlike(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
bytea *str = PG_GETARG_BYTEA_PP(0);
|
|
|
|
bytea *pat = PG_GETARG_BYTEA_PP(1);
|
2001-09-14 19:46:40 +02:00
|
|
|
bool result;
|
2005-09-24 19:53:28 +02:00
|
|
|
char *s,
|
2001-09-14 19:46:40 +02:00
|
|
|
*p;
|
|
|
|
int slen,
|
|
|
|
plen;
|
|
|
|
|
2007-09-22 00:52:52 +02:00
|
|
|
s = VARDATA_ANY(str);
|
|
|
|
slen = VARSIZE_ANY_EXHDR(str);
|
|
|
|
p = VARDATA_ANY(pat);
|
|
|
|
plen = VARSIZE_ANY_EXHDR(pat);
|
2001-09-14 19:46:40 +02:00
|
|
|
|
2011-04-09 23:12:39 +02:00
|
|
|
result = (SB_MatchText(s, slen, p, plen, 0, true) != LIKE_TRUE);
|
2001-09-14 19:46:40 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|
2000-08-06 20:06:44 +02:00
|
|
|
/*
|
|
|
|
* Case-insensitive versions
|
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
nameiclike(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-09 16:13:03 +02:00
|
|
|
Name str = PG_GETARG_NAME(0);
|
2007-09-22 00:52:52 +02:00
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-08-09 16:13:03 +02:00
|
|
|
bool result;
|
2007-06-02 04:03:42 +02:00
|
|
|
text *strtext;
|
2006-09-04 20:32:55 +02:00
|
|
|
|
2017-03-13 00:35:34 +01:00
|
|
|
strtext = DatumGetTextPP(DirectFunctionCall1(name_text,
|
|
|
|
NameGetDatum(str)));
|
2011-02-08 22:04:18 +01:00
|
|
|
result = (Generic_Text_IC_like(strtext, pat, PG_GET_COLLATION()) == LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-07-06 07:48:31 +02:00
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
nameicnlike(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2000-08-09 16:13:03 +02:00
|
|
|
Name str = PG_GETARG_NAME(0);
|
2007-09-22 00:52:52 +02:00
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-08-09 16:13:03 +02:00
|
|
|
bool result;
|
2007-06-02 04:03:42 +02:00
|
|
|
text *strtext;
|
2006-09-04 20:32:55 +02:00
|
|
|
|
2017-03-13 00:35:34 +01:00
|
|
|
strtext = DatumGetTextPP(DirectFunctionCall1(name_text,
|
|
|
|
NameGetDatum(str)));
|
2011-02-08 22:04:18 +01:00
|
|
|
result = (Generic_Text_IC_like(strtext, pat, PG_GET_COLLATION()) != LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-08-06 20:06:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
texticlike(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *str = PG_GETARG_TEXT_PP(0);
|
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-09-15 20:45:31 +02:00
|
|
|
bool result;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2011-02-08 22:04:18 +01:00
|
|
|
result = (Generic_Text_IC_like(str, pat, PG_GET_COLLATION()) == LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-07-06 07:48:31 +02:00
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
texticnlike(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *str = PG_GETARG_TEXT_PP(0);
|
|
|
|
text *pat = PG_GETARG_TEXT_PP(1);
|
2000-09-15 20:45:31 +02:00
|
|
|
bool result;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2011-02-08 22:04:18 +01:00
|
|
|
result = (Generic_Text_IC_like(str, pat, PG_GET_COLLATION()) != LIKE_TRUE);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-08-06 20:06:44 +02:00
|
|
|
}
|
|
|
|
|
2000-09-15 20:45:31 +02:00
|
|
|
/*
|
|
|
|
* like_escape() --- given a pattern and an ESCAPE string,
|
|
|
|
* convert the pattern to use Postgres' standard backslash escape convention.
|
|
|
|
*/
|
2000-08-06 20:06:44 +02:00
|
|
|
Datum
|
2000-09-15 20:45:31 +02:00
|
|
|
like_escape(PG_FUNCTION_ARGS)
|
2000-08-06 20:06:44 +02:00
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *pat = PG_GETARG_TEXT_PP(0);
|
|
|
|
text *esc = PG_GETARG_TEXT_PP(1);
|
2000-09-15 20:45:31 +02:00
|
|
|
text *result;
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2001-10-04 04:15:47 +02:00
|
|
|
if (pg_database_encoding_max_length() == 1)
|
2007-06-02 04:03:42 +02:00
|
|
|
result = SB_do_like_escape(pat, esc);
|
2000-09-15 20:45:31 +02:00
|
|
|
else
|
2001-10-25 07:50:21 +02:00
|
|
|
result = MB_do_like_escape(pat, esc);
|
2000-08-09 16:13:03 +02:00
|
|
|
|
2000-09-15 20:45:31 +02:00
|
|
|
PG_RETURN_TEXT_P(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-09-14 19:46:40 +02:00
|
|
|
/*
|
|
|
|
* like_escape_bytea() --- given a pattern and an ESCAPE string,
|
|
|
|
* convert the pattern to use Postgres' standard backslash escape convention.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
like_escape_bytea(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
bytea *pat = PG_GETARG_BYTEA_PP(0);
|
|
|
|
bytea *esc = PG_GETARG_BYTEA_PP(1);
|
2007-11-15 22:14:46 +01:00
|
|
|
bytea *result = SB_do_like_escape((text *) pat, (text *) esc);
|
2001-09-14 19:46:40 +02:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
PG_RETURN_BYTEA_P((bytea *) result);
|
2001-09-14 19:46:40 +02:00
|
|
|
}
|