33 * like.c
44 * like expression handling code.
55 *
6- * Copyright (c) 1994, Regents of the University of California
7- *
8- *
9- * IDENTIFICATION
10- * /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
11- *
12- *
136 * NOTES
147 *A big hack of the regexp.c code!! Contributed by
158 *Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
169 *
10+ * Copyright (c) 1994, Regents of the University of California
11+ *
12+ * IDENTIFICATION
13+ *$Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.31 1999/09/07 19:09:46 tgl Exp $
1714 *
1815 *-------------------------------------------------------------------------
1916 */
@@ -109,9 +106,7 @@ textnlike(struct varlena * s, struct varlena * p)
109106}
110107
111108
112- /*$Revision: 1.30 $
113- **"like.c" A first attempt at a LIKE operator for Postgres95.
114- **
109+ /*
115110**Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
116111**Rich $alz is now <rsalz@bbn.com>.
117112**Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
@@ -125,8 +120,7 @@ textnlike(struct varlena * s, struct varlena * p)
125120**All the nice shell RE matching stuff was replaced by just "_" and "%"
126121**
127122**As I don't have a copy of the SQL standard handy I wasn't sure whether
128- **to leave in the '\' escape character handling. (I suspect the standard
129- **handles "%%" as a single literal percent)
123+ **to leave in the '\' escape character handling.
130124**
131125**Keith Parks. <keith@mtcc.demon.co.uk>
132126**
@@ -140,15 +134,21 @@ textnlike(struct varlena * s, struct varlena * p)
140134#define LIKE_FALSE 0
141135#define LIKE_ABORT -1
142136
143- /*
144- **Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
145- */
137+ /*--------------------
138+ *Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
139+ *
140+ *LIKE_TRUE: they match
141+ *LIKE_FALSE: they don't match
142+ *LIKE_ABORT: not only don't they match, but the text is too short.
143+ *
144+ * If LIKE_ABORT is returned, then no suffix of the text can match the
145+ * pattern either, so an upper-level % scan can stop scanning now.
146+ *--------------------
147+ */
146148static int
147149DoMatch (pg_wchar * text ,pg_wchar * p )
148150{
149- int matched ;
150-
151- for (;* p && * text ;text ++ ,p ++ )
151+ for (;* p && * text ;text ++ ,p ++ )
152152{
153153switch (* p )
154154{
@@ -157,54 +157,63 @@ DoMatch(pg_wchar * text, pg_wchar * p)
157157p ++ ;
158158/* FALLTHROUGH */
159159default :
160- if (* text != * p )
160+ if (* text != * p )
161161return LIKE_FALSE ;
162162break ;
163163case '_' :
164- /* Matchanything . */
164+ /* Matchany single character . */
165165break ;
166166case '%' :
167167/* %% is the same as % according to the SQL standard */
168168/* Advance past all %'s */
169169while (* p == '%' )
170170p ++ ;
171+ /* Trailing percent matches everything. */
171172if (* p == '\0' )
172- /* Trailing percent matches everything. */
173173return LIKE_TRUE ;
174- while (* text )
174+ /* Otherwise, scan for a text position at which we
175+ * can match the rest of the pattern.
176+ */
177+ for (;* text ;text ++ )
175178{
176- /* Optimization to prevent most recursion */
177- if ((* text == * p ||
178- * p == '\\' || * p == '%' || * p == '_' )&&
179- (matched = DoMatch (text ,p ))!= LIKE_FALSE )
180- return matched ;
181- text ++ ;
179+ /* Optimization to prevent most recursion: don't recurse
180+ * unless first pattern char might match this text char.
181+ */
182+ if (* text == * p || * p == '\\' || * p == '_' )
183+ {
184+ int matched = DoMatch (text ,p );
185+ if (matched != LIKE_FALSE )
186+ return matched ;/* TRUE or ABORT */
187+ }
182188}
189+ /* End of text with no match, so no point in trying later
190+ * places to start matching this pattern.
191+ */
183192return LIKE_ABORT ;
184193}
185194}
186195
187- if (* text != '\0' )
188- return LIKE_ABORT ;
189- else
190- {
191- /* End of input string. Do we have matching string remaining? */
192- while (* p == '%' )/* allow multiple %'s at end of pattern */
193- p ++ ;
194- if (* p == '\0' )
195- return LIKE_TRUE ;
196- else
197- return LIKE_ABORT ;
198- }
199- }
196+ if (* text != '\0' )
197+ return LIKE_FALSE ;/* end of pattern, but not of text */
200198
199+ /* End of input string. Do we have matching pattern remaining? */
200+ while (* p == '%' )/* allow multiple %'s at end of pattern */
201+ p ++ ;
202+ if (* p == '\0' )
203+ return LIKE_TRUE ;
204+ /* End of text with no match, so no point in trying later
205+ * places to start matching this pattern.
206+ */
207+ return LIKE_ABORT ;
208+ }
201209
202210/*
203211**User-level routine. Returns TRUE or FALSE.
204212*/
205213static int
206214like (pg_wchar * text ,pg_wchar * p )
207215{
216+ /* Fast path for match-everything pattern */
208217if (p [0 ]== '%' && p [1 ]== '\0' )
209218return TRUE;
210219return DoMatch (text ,p )== LIKE_TRUE ;