Skip to content

Commit bad3b30

Browse files
committed
Repair recently-introduced error in makeIndexable for LIKE:
a non-leading % would be put into the >=/<= patterns. Also, repair longstanding confusion about whether %% means a literal %%. The SQL92 doesn't say any such thing, and textlike() knows that, but gram.y didn't.
1 parent 43c135e commit bad3b30

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

src/backend/parser/gram.y

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.83 1999/05/22 05:06:43 momjian Exp $
13+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.84 1999/06/07 14:28:25 tgl Exp $
1414
*
1515
* HISTORY
1616
* AUTHOR DATE MAJOR EVENT
@@ -5357,6 +5357,7 @@ static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr)
53575357
int pos, match_pos=0;
53585358
bool found_special = false;
53595359

5360+
/* Cannot optimize if unquoted | { } is present in pattern */
53605361
for (pos = 1; n->val.val.str[pos]; pos++)
53615362
{
53625363
if (n->val.val.str[pos] == '|' ||
@@ -5367,12 +5368,16 @@ static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr)
53675368
break;
53685369
}
53695370
if (n->val.val.str[pos] == '\\')
5371+
{
53705372
pos++;
5373+
if (n->val.val.str[pos] == '\0')
5374+
break;
5375+
}
53715376
}
53725377

5373-
/* skip leading ^ */
53745378
if (!found_special)
53755379
{
5380+
/* note start at pos 1 to skip leading ^ */
53765381
for (pos = 1; n->val.val.str[pos]; pos++)
53775382
{
53785383
if (n->val.val.str[pos] == '.' ||
@@ -5383,9 +5388,11 @@ static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr)
53835388
(strcmp(opname,"~*") == 0 && isalpha(n->val.val.str[pos])))
53845389
break;
53855390
if (n->val.val.str[pos] == '\\')
5391+
{
53865392
pos++;
5387-
if (n->val.val.str[pos] == '\0')
5388-
break;
5393+
if (n->val.val.str[pos] == '\0')
5394+
break;
5395+
}
53895396
match_least[match_pos] = n->val.val.str[pos];
53905397
match_most[match_pos++] = n->val.val.str[pos];
53915398
}
@@ -5430,16 +5437,22 @@ static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr)
54305437

54315438
for (pos = 0; n->val.val.str[pos]; pos++)
54325439
{
5433-
if (n->val.val.str[pos] == '%' &&
5434-
n->val.val.str[pos+1] != '%')
5435-
break;
5436-
if(n->val.val.str[pos] == '_')
5440+
/* % and _ are wildcard characters in LIKE */
5441+
if (n->val.val.str[pos] == '%' ||
5442+
n->val.val.str[pos] == '_')
54375443
break;
5438-
if (n->val.val.str[pos] == '\\' ||
5439-
n->val.val.str[pos+1] == '%')
5444+
/* Backslash quotes the next character */
5445+
if (n->val.val.str[pos] == '\\')
5446+
{
54405447
pos++;
5441-
if (n->val.val.str[pos] == '\0')
5442-
break;
5448+
if (n->val.val.str[pos] == '\0')
5449+
break;
5450+
}
5451+
/*
5452+
* NOTE: this code used to think that %% meant a literal %,
5453+
* but textlike() itself does not think that, and the SQL92
5454+
* spec doesn't say any such thing either.
5455+
*/
54435456
match_least[match_pos] = n->val.val.str[pos];
54445457
match_most[match_pos++] = n->val.val.str[pos];
54455458
}

src/backend/utils/adt/like.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ textnlike(struct varlena * s, struct varlena * p)
111111
}
112112

113113

114-
/* $Revision: 1.24 $
114+
/* $Revision: 1.25 $
115115
** "like.c" A first attempt at a LIKE operator for Postgres95.
116116
**
117117
** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
@@ -191,7 +191,9 @@ DoMatch(pg_wchar * text, pg_wchar * p)
191191
else
192192
{
193193
/* End of input string. Do we have matching string remaining? */
194-
if (p[0] == '\0' || (p[0] == '%' && p[1] == '\0'))
194+
while (*p == '%') /* allow multiple %'s at end of pattern */
195+
p++;
196+
if (*p == '\0')
195197
return LIKE_TRUE;
196198
else
197199
return LIKE_ABORT;

0 commit comments

Comments
 (0)