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-2000, PostgreSQL, Inc
11 * Portions Copyright (c) 1994, Regents of the University of California
14 * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.34 2000/04/12 17:15:50 momjian Exp $
16 *-------------------------------------------------------------------------
19 #include "mb/pg_wchar.h"
20 #include "utils/builtins.h"
22 static int like(pg_wchar * text, pg_wchar * p);
25 * interface routines called by the function manager
31 a generic fixed length like routine
32 s - the string to match against (not necessarily null-terminated)
34 charlen - the length of the string
37 fixedlen_like(char *s, struct varlena * p, int charlen)
47 /* be sure sterm is null-terminated */
49 sterm = (pg_wchar *) palloc((charlen + 1) * sizeof(pg_wchar));
50 (void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
52 sterm = (char *) palloc(charlen + 1);
53 StrNCpy(sterm, s, charlen + 1);
57 * p is a text = varlena, not a string so we have to make a string
58 * from the vl_data field of the struct.
61 /* palloc the length of the text + the null character */
62 len = VARSIZE(p) - VARHDRSZ;
64 pterm = (pg_wchar *) palloc((len + 1) * sizeof(pg_wchar));
65 (void) pg_mb2wchar_with_len((unsigned char *) VARDATA(p), pterm, len);
67 pterm = (char *) palloc(len + 1);
68 memmove(pterm, VARDATA(p), len);
69 *(pterm + len) = (char) NULL;
72 /* do the regexp matching */
73 result = like(sterm, pterm);
82 namelike(NameData *n, struct varlena * p)
86 return fixedlen_like(NameStr(*n), p, NAMEDATALEN);
90 namenlike(NameData *s, struct varlena * p)
92 return !namelike(s, p);
96 textlike(struct varlena * s, struct varlena * p)
100 return fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ);
104 textnlike(struct varlena * s, struct varlena * p)
106 return !textlike(s, p);
111 ** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
112 ** Rich $alz is now <rsalz@bbn.com>.
113 ** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
115 ** This code was shamelessly stolen from the "pql" code by myself and
116 ** slightly modified :)
118 ** All references to the word "star" were replaced by "percent"
119 ** All references to the word "wild" were replaced by "like"
121 ** All the nice shell RE matching stuff was replaced by just "_" and "%"
123 ** As I don't have a copy of the SQL standard handy I wasn't sure whether
124 ** to leave in the '\' escape character handling.
126 ** Keith Parks. <keith@mtcc.demon.co.uk>
128 ** [SQL92 lets you specify the escape character by saying
129 ** LIKE <pattern> ESCAPE <escape character>. We are a small operation
130 ** so we force you to use '\'. - ay 7/95]
136 #define LIKE_ABORT -1
138 /*--------------------
139 * Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
141 * LIKE_TRUE: they match
142 * LIKE_FALSE: they don't match
143 * LIKE_ABORT: not only don't they match, but the text is too short.
145 * If LIKE_ABORT is returned, then no suffix of the text can match the
146 * pattern either, so an upper-level % scan can stop scanning now.
147 *--------------------
150 DoMatch(pg_wchar * text, pg_wchar * p)
152 for (; *p && *text; text ++, p++)
157 /* Literal match with following character. */
165 /* Match any single character. */
168 /* %% is the same as % according to the SQL standard */
169 /* Advance past all %'s */
172 /* Trailing percent matches everything. */
177 * Otherwise, scan for a text position at which we can
178 * match the rest of the pattern.
180 for (; *text; text ++)
184 * Optimization to prevent most recursion: don't
185 * recurse unless first pattern char might match this
188 if (*text == *p || *p == '\\' || *p == '_')
190 int matched = DoMatch(text, p);
192 if (matched != LIKE_FALSE)
193 return matched; /* TRUE or ABORT */
198 * End of text with no match, so no point in trying later
199 * places to start matching this pattern.
206 return LIKE_FALSE; /* end of pattern, but not of text */
208 /* End of input string. Do we have matching pattern remaining? */
209 while (*p == '%') /* allow multiple %'s at end of pattern */
215 * End of text with no match, so no point in trying later places to
216 * start matching this pattern.
222 ** User-level routine. Returns TRUE or FALSE.
225 like(pg_wchar * text, pg_wchar * p)
227 /* Fast path for match-everything pattern */
228 if (p[0] == '%' && p[1] == '\0')
230 return DoMatch(text, p) == LIKE_TRUE;