Repair logic error in LIKE: should not return LIKE_ABORT
when reach end of pattern before end of text. Improve code comments.
This commit is contained in:
parent
ea582ad7e7
commit
bee7cd2a36
@ -3,17 +3,14 @@
|
|||||||
* like.c
|
* like.c
|
||||||
* like expression handling code.
|
* like expression handling code.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
* /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* NOTES
|
* NOTES
|
||||||
* A big hack of the regexp.c code!! Contributed by
|
* A big hack of the regexp.c code!! Contributed by
|
||||||
* Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
|
* Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.31 1999/09/07 19:09:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -109,9 +106,7 @@ textnlike(struct varlena * s, struct varlena * p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* $Revision: 1.30 $
|
/*
|
||||||
** "like.c" A first attempt at a LIKE operator for Postgres95.
|
|
||||||
**
|
|
||||||
** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
|
** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
|
||||||
** Rich $alz is now <rsalz@bbn.com>.
|
** Rich $alz is now <rsalz@bbn.com>.
|
||||||
** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
|
** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
|
||||||
@ -125,8 +120,7 @@ textnlike(struct varlena * s, struct varlena * p)
|
|||||||
** All the nice shell RE matching stuff was replaced by just "_" and "%"
|
** All the nice shell RE matching stuff was replaced by just "_" and "%"
|
||||||
**
|
**
|
||||||
** As I don't have a copy of the SQL standard handy I wasn't sure whether
|
** As I don't have a copy of the SQL standard handy I wasn't sure whether
|
||||||
** to leave in the '\' escape character handling. (I suspect the standard
|
** to leave in the '\' escape character handling.
|
||||||
** handles "%%" as a single literal percent)
|
|
||||||
**
|
**
|
||||||
** Keith Parks. <keith@mtcc.demon.co.uk>
|
** Keith Parks. <keith@mtcc.demon.co.uk>
|
||||||
**
|
**
|
||||||
@ -140,15 +134,21 @@ textnlike(struct varlena * s, struct varlena * p)
|
|||||||
#define LIKE_FALSE 0
|
#define LIKE_FALSE 0
|
||||||
#define LIKE_ABORT -1
|
#define LIKE_ABORT -1
|
||||||
|
|
||||||
/*
|
/*--------------------
|
||||||
** Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
|
* Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
|
||||||
*/
|
*
|
||||||
|
* LIKE_TRUE: they match
|
||||||
|
* LIKE_FALSE: they don't match
|
||||||
|
* LIKE_ABORT: not only don't they match, but the text is too short.
|
||||||
|
*
|
||||||
|
* If LIKE_ABORT is returned, then no suffix of the text can match the
|
||||||
|
* pattern either, so an upper-level % scan can stop scanning now.
|
||||||
|
*--------------------
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
DoMatch(pg_wchar * text, pg_wchar * p)
|
DoMatch(pg_wchar * text, pg_wchar * p)
|
||||||
{
|
{
|
||||||
int matched;
|
for (; *p && *text; text++, p++)
|
||||||
|
|
||||||
for (; *p && *text; text ++, p++)
|
|
||||||
{
|
{
|
||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
@ -157,54 +157,63 @@ DoMatch(pg_wchar * text, pg_wchar * p)
|
|||||||
p++;
|
p++;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
if (*text !=*p)
|
if (*text != *p)
|
||||||
return LIKE_FALSE;
|
return LIKE_FALSE;
|
||||||
break;
|
break;
|
||||||
case '_':
|
case '_':
|
||||||
/* Match anything. */
|
/* Match any single character. */
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
/* %% is the same as % according to the SQL standard */
|
/* %% is the same as % according to the SQL standard */
|
||||||
/* Advance past all %'s */
|
/* Advance past all %'s */
|
||||||
while (*p == '%')
|
while (*p == '%')
|
||||||
p++;
|
p++;
|
||||||
if (*p == '\0')
|
|
||||||
/* Trailing percent matches everything. */
|
/* Trailing percent matches everything. */
|
||||||
|
if (*p == '\0')
|
||||||
return LIKE_TRUE;
|
return LIKE_TRUE;
|
||||||
while (*text)
|
/* Otherwise, scan for a text position at which we
|
||||||
|
* can match the rest of the pattern.
|
||||||
|
*/
|
||||||
|
for (; *text; text++)
|
||||||
{
|
{
|
||||||
/* Optimization to prevent most recursion */
|
/* Optimization to prevent most recursion: don't recurse
|
||||||
if ((*text == *p ||
|
* unless first pattern char might match this text char.
|
||||||
*p == '\\' || *p == '%' || *p == '_') &&
|
*/
|
||||||
(matched = DoMatch(text, p)) != LIKE_FALSE)
|
if (*text == *p || *p == '\\' || *p == '_')
|
||||||
return matched;
|
{
|
||||||
text ++;
|
int matched = DoMatch(text, p);
|
||||||
|
if (matched != LIKE_FALSE)
|
||||||
|
return matched; /* TRUE or ABORT */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* End of text with no match, so no point in trying later
|
||||||
|
* places to start matching this pattern.
|
||||||
|
*/
|
||||||
return LIKE_ABORT;
|
return LIKE_ABORT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*text !='\0')
|
if (*text != '\0')
|
||||||
return LIKE_ABORT;
|
return LIKE_FALSE; /* end of pattern, but not of text */
|
||||||
else
|
|
||||||
{
|
/* End of input string. Do we have matching pattern remaining? */
|
||||||
/* End of input string. Do we have matching string remaining? */
|
|
||||||
while (*p == '%') /* allow multiple %'s at end of pattern */
|
while (*p == '%') /* allow multiple %'s at end of pattern */
|
||||||
p++;
|
p++;
|
||||||
if (*p == '\0')
|
if (*p == '\0')
|
||||||
return LIKE_TRUE;
|
return LIKE_TRUE;
|
||||||
else
|
/* End of text with no match, so no point in trying later
|
||||||
|
* places to start matching this pattern.
|
||||||
|
*/
|
||||||
return LIKE_ABORT;
|
return LIKE_ABORT;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** User-level routine. Returns TRUE or FALSE.
|
** User-level routine. Returns TRUE or FALSE.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
like(pg_wchar * text, pg_wchar * p)
|
like(pg_wchar * text, pg_wchar * p)
|
||||||
{
|
{
|
||||||
|
/* Fast path for match-everything pattern */
|
||||||
if (p[0] == '%' && p[1] == '\0')
|
if (p[0] == '%' && p[1] == '\0')
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return DoMatch(text, p) == LIKE_TRUE;
|
return DoMatch(text, p) == LIKE_TRUE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user