Skip to content

Commit bd1ef57

Browse files
committed
Handle empty-string edge cases correctly in strpos().
Commit 9556aa0 rearranged the innards of text_position() in a way that would make it not work for empty search strings. Which is fine, because all callers of that code special-case an empty pattern in some way. However, the primary use-case (text_position itself) got special-cased incorrectly: historically it's returned 1 not 0 for an empty search string. Restore the historical behavior. Per complaint from Austin Drenski (via Shay Rojansky). Back-patch to v12 where it got broken. Discussion: https://postgr.es/m/CADT4RqAz7oN4vkPir86Kg1_mQBmBxCp-L_=9vRpgSNPJf0KRkw@mail.gmail.com
1 parent 61ecea4 commit bd1ef57

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

src/backend/utils/adt/varlena.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,12 @@ text_position(text *t1, text *t2, Oid collid)
11181118
TextPositionState state;
11191119
int result;
11201120

1121-
if (VARSIZE_ANY_EXHDR(t1) < 1 || VARSIZE_ANY_EXHDR(t2) < 1)
1121+
/* Empty needle always matches at position 1 */
1122+
if (VARSIZE_ANY_EXHDR(t2) < 1)
1123+
return 1;
1124+
1125+
/* Otherwise, can't match if haystack is shorter than needle */
1126+
if (VARSIZE_ANY_EXHDR(t1) < VARSIZE_ANY_EXHDR(t2))
11221127
return 0;
11231128

11241129
text_position_setup(t1, t2, collid, &state);
@@ -1272,6 +1277,9 @@ text_position_setup(text *t1, text *t2, Oid collid, TextPositionState *state)
12721277
* Advance to the next match, starting from the end of the previous match
12731278
* (or the beginning of the string, on first call). Returns true if a match
12741279
* is found.
1280+
*
1281+
* Note that this refuses to match an empty-string needle. Most callers
1282+
* will have handled that case specially and we'll never see it here.
12751283
*/
12761284
static bool
12771285
text_position_next(TextPositionState *state)

src/test/regress/expected/strings.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,24 @@ SELECT strpos('abcdef', 'xy') AS "pos_0";
14201420
0
14211421
(1 row)
14221422

1423+
SELECT strpos('abcdef', '') AS "pos_1";
1424+
pos_1
1425+
-------
1426+
1
1427+
(1 row)
1428+
1429+
SELECT strpos('', 'xy') AS "pos_0";
1430+
pos_0
1431+
-------
1432+
0
1433+
(1 row)
1434+
1435+
SELECT strpos('', '') AS "pos_1";
1436+
pos_1
1437+
-------
1438+
1
1439+
(1 row)
1440+
14231441
--
14241442
-- test replace
14251443
--

src/test/regress/sql/strings.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,12 @@ SELECT strpos('abcdef', 'cd') AS "pos_3";
492492

493493
SELECT strpos('abcdef', 'xy') AS "pos_0";
494494

495+
SELECT strpos('abcdef', '') AS "pos_1";
496+
497+
SELECT strpos('', 'xy') AS "pos_0";
498+
499+
SELECT strpos('', '') AS "pos_1";
500+
495501
--
496502
-- test replace
497503
--

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