Skip to content

Commit 10bcd41

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 38a2379 commit 10bcd41

File tree

1 file changed

+38
-44
lines changed

1 file changed

+38
-44
lines changed

doc/src/sgml/plpgsql.sgml

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5531,27 +5531,29 @@ $$ LANGUAGE plpgsql STRICT IMMUTABLE;
55315531
<primary><function>instr</> function</primary>
55325532
</indexterm>
55335533

5534-
<programlisting>
5534+
<programlisting><![CDATA[
55355535
--
55365536
-- instr functions that mimic Oracle's counterpart
5537-
-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
5537+
-- Syntax: instr(string1, string2 [, n [, m]])
5538+
-- where [] denotes optional parameters.
55385539
--
5539-
-- Searches string1 beginning at the nth character for the mth occurrence
5540-
-- of string2. If n is negative, search backwards. If m is not passed,
5541-
-- assume 1 (search starts at first character).
5540+
-- Search string1, beginning at the nth character, for the mth occurrence
5541+
-- of string2. If n is negative, search backwards, starting at the abs(n)'th
5542+
-- character from the end of string1.
5543+
-- If n is not passed, assume 1 (search starts at first character).
5544+
-- If m is not passed, assume 1 (find first occurrence).
5545+
-- Returns starting index of string2 in string1, or 0 if string2 is not found.
55425546
--
55435547

55445548
CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
5545-
DECLARE
5546-
pos integer;
55475549
BEGIN
5548-
pos:= instr($1, $2, 1);
5549-
RETURN pos;
5550+
RETURN instr($1, $2, 1);
55505551
END;
55515552
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
55525553

55535554

5554-
CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer)
5555+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
5556+
beg_index integer)
55555557
RETURNS integer AS $$
55565558
DECLARE
55575559
pos integer NOT NULL DEFAULT 0;
@@ -5560,25 +5562,23 @@ DECLARE
55605562
length integer;
55615563
ss_length integer;
55625564
BEGIN
5563-
IF beg_index &gt; 0 THEN
5565+
IF beg_index > 0 THEN
55645566
temp_str := substring(string FROM beg_index);
5565-
pos := position(string_to_search IN temp_str);
5567+
pos := position(string_to_search_for IN temp_str);
55665568

55675569
IF pos = 0 THEN
55685570
RETURN 0;
55695571
ELSE
55705572
RETURN pos + beg_index - 1;
55715573
END IF;
5572-
ELSIF beg_index &lt; 0 THEN
5573-
ss_length := char_length(string_to_search);
5574+
ELSIF beg_index < 0 THEN
5575+
ss_length := char_length(string_to_search_for);
55745576
length := char_length(string);
5575-
beg := length + beg_index - ss_length + 2;
5577+
beg := length + 1 + beg_index;
55765578

5577-
WHILE beg &gt; 0 LOOP
5579+
WHILE beg > 0 LOOP
55785580
temp_str := substring(string FROM beg FOR ss_length);
5579-
pos := position(string_to_search IN temp_str);
5580-
5581-
IF pos &gt; 0 THEN
5581+
IF string_to_search_for = temp_str THEN
55825582
RETURN beg;
55835583
END IF;
55845584

@@ -5593,7 +5593,7 @@ END;
55935593
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
55945594

55955595

5596-
CREATE FUNCTION instr(string varchar, string_to_search varchar,
5596+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
55975597
beg_index integer, occur_index integer)
55985598
RETURNS integer AS $$
55995599
DECLARE
@@ -5605,39 +5605,32 @@ DECLARE
56055605
length integer;
56065606
ss_length integer;
56075607
BEGIN
5608-
IF beg_index &gt; 0 THEN
5609-
beg := beg_index;
5610-
temp_str := substring(string FROM beg_index);
5608+
IF occur_index <= 0 THEN
5609+
RAISE 'argument ''%'' is out of range', occur_index
5610+
USING ERRCODE = '22003';
5611+
END IF;
56115612

5613+
IF beg_index > 0 THEN
5614+
beg := beg_index - 1;
56125615
FOR i IN 1..occur_index LOOP
5613-
pos := position(string_to_search IN temp_str);
5614-
5615-
IF i = 1 THEN
5616-
beg := beg + pos - 1;
5617-
ELSE
5618-
beg := beg + pos;
5619-
END IF;
5620-
56215616
temp_str := substring(string FROM beg + 1);
5617+
pos := position(string_to_search_for IN temp_str);
5618+
IF pos = 0 THEN
5619+
RETURN 0;
5620+
END IF;
5621+
beg := beg + pos;
56225622
END LOOP;
56235623

5624-
IF pos = 0 THEN
5625-
RETURN 0;
5626-
ELSE
5627-
RETURN beg;
5628-
END IF;
5629-
ELSIF beg_index &lt; 0 THEN
5630-
ss_length := char_length(string_to_search);
5624+
RETURN beg;
5625+
ELSIF beg_index < 0 THEN
5626+
ss_length := char_length(string_to_search_for);
56315627
length := char_length(string);
5632-
beg := length + beg_index - ss_length + 2;
5628+
beg := length + 1 + beg_index;
56335629

5634-
WHILE beg &gt; 0 LOOP
5630+
WHILE beg > 0 LOOP
56355631
temp_str := substring(string FROM beg FOR ss_length);
5636-
pos := position(string_to_search IN temp_str);
5637-
5638-
IF pos &gt; 0 THEN
5632+
IF string_to_search_for = temp_str THEN
56395633
occur_number := occur_number + 1;
5640-
56415634
IF occur_number = occur_index THEN
56425635
RETURN beg;
56435636
END IF;
@@ -5652,6 +5645,7 @@ BEGIN
56525645
END IF;
56535646
END;
56545647
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
5648+
]]>
56555649
</programlisting>
56565650
</sect2>
56575651

0 commit comments

Comments
 (0)