Skip to content

Commit 493cdc8

Browse files
committed
Fix sample INSTR() functions in the plpgsql documentation.
These functions are stated to be Oracle-compatible, but they weren't. Yugo Nagata noticed that while our code returns zero for a zero or negative fourth parameter (occur_index), Oracle throws an error. Further testing by me showed that there was also a discrepancy in the interpretation of a negative third parameter (beg_index): Oracle thinks that a negative beg_index indicates the last place where the target substring can *begin*, whereas our code thinks it is the last place where the target can *end*. Adjust the sample code to behave like Oracle in both these respects. Also change it to be a CDATA[] section, simplifying copying-and-pasting out of the documentation source file. And fix minor problems in the introductory comment, which wasn't very complete or accurate. Back-patch to all supported branches. Although this patch only touches documentation, we should probably call it out as a bug fix in the next minor release notes, since users who have adopted the functions will likely want to update their versions. Yugo Nagata and Tom Lane Discussion: https://postgr.es/m/20171229191705.c0b43a8c.nagata@sraoss.co.jp
1 parent c618796 commit 493cdc8

File tree

1 file changed

+42
-44
lines changed

1 file changed

+42
-44
lines changed

doc/src/sgml/plpgsql.sgml

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5438,27 +5438,33 @@ $$ LANGUAGE plpgsql STRICT IMMUTABLE;
54385438
your porting efforts.
54395439
</para>
54405440

5441-
<programlisting>
5441+
<indexterm>
5442+
<primary><function>instr</> function</primary>
5443+
</indexterm>
5444+
5445+
<programlisting><![CDATA[
54425446
--
54435447
-- instr functions that mimic Oracle's counterpart
5444-
-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
5448+
-- Syntax: instr(string1, string2 [, n [, m]])
5449+
-- where [] denotes optional parameters.
54455450
--
5446-
-- Searches string1 beginning at the nth character for the mth occurrence
5447-
-- of string2. If n is negative, search backwards. If m is not passed,
5448-
-- assume 1 (search starts at first character).
5451+
-- Search string1, beginning at the nth character, for the mth occurrence
5452+
-- of string2. If n is negative, search backwards, starting at the abs(n)'th
5453+
-- character from the end of string1.
5454+
-- If n is not passed, assume 1 (search starts at first character).
5455+
-- If m is not passed, assume 1 (find first occurrence).
5456+
-- Returns starting index of string2 in string1, or 0 if string2 is not found.
54495457
--
54505458

54515459
CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
5452-
DECLARE
5453-
pos integer;
54545460
BEGIN
5455-
pos:= instr($1, $2, 1);
5456-
RETURN pos;
5461+
RETURN instr($1, $2, 1);
54575462
END;
54585463
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
54595464

54605465

5461-
CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer)
5466+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
5467+
beg_index integer)
54625468
RETURNS integer AS $$
54635469
DECLARE
54645470
pos integer NOT NULL DEFAULT 0;
@@ -5467,25 +5473,23 @@ DECLARE
54675473
length integer;
54685474
ss_length integer;
54695475
BEGIN
5470-
IF beg_index &gt; 0 THEN
5476+
IF beg_index > 0 THEN
54715477
temp_str := substring(string FROM beg_index);
5472-
pos := position(string_to_search IN temp_str);
5478+
pos := position(string_to_search_for IN temp_str);
54735479

54745480
IF pos = 0 THEN
54755481
RETURN 0;
54765482
ELSE
54775483
RETURN pos + beg_index - 1;
54785484
END IF;
5479-
ELSIF beg_index &lt; 0 THEN
5480-
ss_length := char_length(string_to_search);
5485+
ELSIF beg_index < 0 THEN
5486+
ss_length := char_length(string_to_search_for);
54815487
length := char_length(string);
5482-
beg := length + beg_index - ss_length + 2;
5488+
beg := length + 1 + beg_index;
54835489

5484-
WHILE beg &gt; 0 LOOP
5490+
WHILE beg > 0 LOOP
54855491
temp_str := substring(string FROM beg FOR ss_length);
5486-
pos := position(string_to_search IN temp_str);
5487-
5488-
IF pos &gt; 0 THEN
5492+
IF string_to_search_for = temp_str THEN
54895493
RETURN beg;
54905494
END IF;
54915495

@@ -5500,7 +5504,7 @@ END;
55005504
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
55015505

55025506

5503-
CREATE FUNCTION instr(string varchar, string_to_search varchar,
5507+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
55045508
beg_index integer, occur_index integer)
55055509
RETURNS integer AS $$
55065510
DECLARE
@@ -5512,39 +5516,32 @@ DECLARE
55125516
length integer;
55135517
ss_length integer;
55145518
BEGIN
5515-
IF beg_index &gt; 0 THEN
5516-
beg := beg_index;
5517-
temp_str := substring(string FROM beg_index);
5519+
IF occur_index <= 0 THEN
5520+
RAISE 'argument ''%'' is out of range', occur_index
5521+
USING ERRCODE = '22003';
5522+
END IF;
55185523

5524+
IF beg_index > 0 THEN
5525+
beg := beg_index - 1;
55195526
FOR i IN 1..occur_index LOOP
5520-
pos := position(string_to_search IN temp_str);
5521-
5522-
IF i = 1 THEN
5523-
beg := beg + pos - 1;
5524-
ELSE
5525-
beg := beg + pos;
5526-
END IF;
5527-
55285527
temp_str := substring(string FROM beg + 1);
5528+
pos := position(string_to_search_for IN temp_str);
5529+
IF pos = 0 THEN
5530+
RETURN 0;
5531+
END IF;
5532+
beg := beg + pos;
55295533
END LOOP;
55305534

5531-
IF pos = 0 THEN
5532-
RETURN 0;
5533-
ELSE
5534-
RETURN beg;
5535-
END IF;
5536-
ELSIF beg_index &lt; 0 THEN
5537-
ss_length := char_length(string_to_search);
5535+
RETURN beg;
5536+
ELSIF beg_index < 0 THEN
5537+
ss_length := char_length(string_to_search_for);
55385538
length := char_length(string);
5539-
beg := length + beg_index - ss_length + 2;
5539+
beg := length + 1 + beg_index;
55405540

5541-
WHILE beg &gt; 0 LOOP
5541+
WHILE beg > 0 LOOP
55425542
temp_str := substring(string FROM beg FOR ss_length);
5543-
pos := position(string_to_search IN temp_str);
5544-
5545-
IF pos &gt; 0 THEN
5543+
IF string_to_search_for = temp_str THEN
55465544
occur_number := occur_number + 1;
5547-
55485545
IF occur_number = occur_index THEN
55495546
RETURN beg;
55505547
END IF;
@@ -5559,6 +5556,7 @@ BEGIN
55595556
END IF;
55605557
END;
55615558
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
5559+
]]>
55625560
</programlisting>
55635561
</sect2>
55645562

0 commit comments

Comments
 (0)