Skip to content

Commit bee7cd2

Browse files
committed
Repair logic error in LIKE: should not return LIKE_ABORT
when reach end of pattern before end of text. Improve code comments.
1 parent ea582ad commit bee7cd2

File tree

1 file changed

+50
-41
lines changed

1 file changed

+50
-41
lines changed

src/backend/utils/adt/like.c

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@
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+
*/
146148
static int
147149
DoMatch(pg_wchar * text, pg_wchar * p)
148150
{
149-
int matched;
150-
151-
for (; *p && *text; text ++, p++)
151+
for (; *p && *text; text++, p++)
152152
{
153153
switch (*p)
154154
{
@@ -157,54 +157,63 @@ DoMatch(pg_wchar * text, pg_wchar * p)
157157
p++;
158158
/* FALLTHROUGH */
159159
default:
160-
if (*text !=*p)
160+
if (*text != *p)
161161
return LIKE_FALSE;
162162
break;
163163
case '_':
164-
/* Match anything. */
164+
/* Match any single character. */
165165
break;
166166
case '%':
167167
/* %% is the same as % according to the SQL standard */
168168
/* Advance past all %'s */
169169
while (*p == '%')
170170
p++;
171+
/* Trailing percent matches everything. */
171172
if (*p == '\0')
172-
/* Trailing percent matches everything. */
173173
return 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+
*/
183192
return 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
*/
205213
static int
206214
like(pg_wchar * text, pg_wchar * p)
207215
{
216+
/* Fast path for match-everything pattern */
208217
if (p[0] == '%' && p[1] == '\0')
209218
return TRUE;
210219
return DoMatch(text, p) == LIKE_TRUE;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy