Skip to content

Commit 45bfef7

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/[email protected]
1 parent 469fa9a commit 45bfef7

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
@@ -5268,27 +5268,33 @@ $$ LANGUAGE plpgsql STRICT IMMUTABLE;
52685268
your porting efforts.
52695269
</para>
52705270

5271-
<programlisting>
5271+
<indexterm>
5272+
<primary><function>instr</> function</primary>
5273+
</indexterm>
5274+
5275+
<programlisting><![CDATA[
52725276
--
52735277
-- instr functions that mimic Oracle's counterpart
5274-
-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
5278+
-- Syntax: instr(string1, string2 [, n [, m]])
5279+
-- where [] denotes optional parameters.
52755280
--
5276-
-- Searches string1 beginning at the nth character for the mth occurrence
5277-
-- of string2. If n is negative, search backwards. If m is not passed,
5278-
-- assume 1 (search starts at first character).
5281+
-- Search string1, beginning at the nth character, for the mth occurrence
5282+
-- of string2. If n is negative, search backwards, starting at the abs(n)'th
5283+
-- character from the end of string1.
5284+
-- If n is not passed, assume 1 (search starts at first character).
5285+
-- If m is not passed, assume 1 (find first occurrence).
5286+
-- Returns starting index of string2 in string1, or 0 if string2 is not found.
52795287
--
52805288

52815289
CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
5282-
DECLARE
5283-
pos integer;
52845290
BEGIN
5285-
pos:= instr($1, $2, 1);
5286-
RETURN pos;
5291+
RETURN instr($1, $2, 1);
52875292
END;
52885293
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
52895294

52905295

5291-
CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer)
5296+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
5297+
beg_index integer)
52925298
RETURNS integer AS $$
52935299
DECLARE
52945300
pos integer NOT NULL DEFAULT 0;
@@ -5297,25 +5303,23 @@ DECLARE
52975303
length integer;
52985304
ss_length integer;
52995305
BEGIN
5300-
IF beg_index &gt; 0 THEN
5306+
IF beg_index > 0 THEN
53015307
temp_str := substring(string FROM beg_index);
5302-
pos := position(string_to_search IN temp_str);
5308+
pos := position(string_to_search_for IN temp_str);
53035309

53045310
IF pos = 0 THEN
53055311
RETURN 0;
53065312
ELSE
53075313
RETURN pos + beg_index - 1;
53085314
END IF;
5309-
ELSIF beg_index &lt; 0 THEN
5310-
ss_length := char_length(string_to_search);
5315+
ELSIF beg_index < 0 THEN
5316+
ss_length := char_length(string_to_search_for);
53115317
length := char_length(string);
5312-
beg := length + beg_index - ss_length + 2;
5318+
beg := length + 1 + beg_index;
53135319

5314-
WHILE beg &gt; 0 LOOP
5320+
WHILE beg > 0 LOOP
53155321
temp_str := substring(string FROM beg FOR ss_length);
5316-
pos := position(string_to_search IN temp_str);
5317-
5318-
IF pos &gt; 0 THEN
5322+
IF string_to_search_for = temp_str THEN
53195323
RETURN beg;
53205324
END IF;
53215325

@@ -5330,7 +5334,7 @@ END;
53305334
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
53315335

53325336

5333-
CREATE FUNCTION instr(string varchar, string_to_search varchar,
5337+
CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
53345338
beg_index integer, occur_index integer)
53355339
RETURNS integer AS $$
53365340
DECLARE
@@ -5342,39 +5346,32 @@ DECLARE
53425346
length integer;
53435347
ss_length integer;
53445348
BEGIN
5345-
IF beg_index &gt; 0 THEN
5346-
beg := beg_index;
5347-
temp_str := substring(string FROM beg_index);
5349+
IF occur_index <= 0 THEN
5350+
RAISE 'argument ''%'' is out of range', occur_index
5351+
USING ERRCODE = '22003';
5352+
END IF;
53485353

5354+
IF beg_index > 0 THEN
5355+
beg := beg_index - 1;
53495356
FOR i IN 1..occur_index LOOP
5350-
pos := position(string_to_search IN temp_str);
5351-
5352-
IF i = 1 THEN
5353-
beg := beg + pos - 1;
5354-
ELSE
5355-
beg := beg + pos;
5356-
END IF;
5357-
53585357
temp_str := substring(string FROM beg + 1);
5358+
pos := position(string_to_search_for IN temp_str);
5359+
IF pos = 0 THEN
5360+
RETURN 0;
5361+
END IF;
5362+
beg := beg + pos;
53595363
END LOOP;
53605364

5361-
IF pos = 0 THEN
5362-
RETURN 0;
5363-
ELSE
5364-
RETURN beg;
5365-
END IF;
5366-
ELSIF beg_index &lt; 0 THEN
5367-
ss_length := char_length(string_to_search);
5365+
RETURN beg;
5366+
ELSIF beg_index < 0 THEN
5367+
ss_length := char_length(string_to_search_for);
53685368
length := char_length(string);
5369-
beg := length + beg_index - ss_length + 2;
5369+
beg := length + 1 + beg_index;
53705370

5371-
WHILE beg &gt; 0 LOOP
5371+
WHILE beg > 0 LOOP
53725372
temp_str := substring(string FROM beg FOR ss_length);
5373-
pos := position(string_to_search IN temp_str);
5374-
5375-
IF pos &gt; 0 THEN
5373+
IF string_to_search_for = temp_str THEN
53765374
occur_number := occur_number + 1;
5377-
53785375
IF occur_number = occur_index THEN
53795376
RETURN beg;
53805377
END IF;
@@ -5389,6 +5386,7 @@ BEGIN
53895386
END IF;
53905387
END;
53915388
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
5389+
]]>
53925390
</programlisting>
53935391
</sect2>
53945392

0 commit comments

Comments
 (0)