1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>41.13. Porting from Oracle PL/SQL</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="plpgsql-development-tips.html" title="41.12. Tips for Developing in PL/pgSQL" /><link rel="next" href="pltcl.html" title="Chapter 42. PL/Tcl — Tcl Procedural Language" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">41.13. Porting from <span class="productname">Oracle</span> PL/SQL</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="plpgsql-development-tips.html" title="41.12. Tips for Developing in PL/pgSQL">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="plpgsql.html" title="Chapter 41. PL/pgSQL — SQL Procedural Language">Up</a></td><th width="60%" align="center">Chapter 41. <span class="application">PL/pgSQL</span> — <acronym class="acronym">SQL</acronym> Procedural Language</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="pltcl.html" title="Chapter 42. PL/Tcl — Tcl Procedural Language">Next</a></td></tr></table><hr /></div><div class="sect1" id="PLPGSQL-PORTING"><div class="titlepage"><div><div><h2 class="title" style="clear: both">41.13. Porting from <span class="productname">Oracle</span> PL/SQL <a href="#PLPGSQL-PORTING" class="id_link">#</a></h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="plpgsql-porting.html#PLPGSQL-PORTING-EXAMPLES">41.13.1. Porting Examples</a></span></dt><dt><span class="sect2"><a href="plpgsql-porting.html#PLPGSQL-PORTING-OTHER">41.13.2. Other Things to Watch For</a></span></dt><dt><span class="sect2"><a href="plpgsql-porting.html#PLPGSQL-PORTING-APPENDIX">41.13.3. Appendix</a></span></dt></dl></div><a id="id-1.8.8.15.2" class="indexterm"></a><a id="id-1.8.8.15.3" class="indexterm"></a><p>
3 This section explains differences between
4 <span class="productname">PostgreSQL</span>'s <span class="application">PL/pgSQL</span>
5 language and Oracle's <span class="application">PL/SQL</span> language,
6 to help developers who port applications from
7 <span class="trademark">Oracle</span>® to <span class="productname">PostgreSQL</span>.
9 <span class="application">PL/pgSQL</span> is similar to PL/SQL in many
10 aspects. It is a block-structured, imperative language, and all
11 variables have to be declared. Assignments, loops, and conditionals
12 are similar. The main differences you should keep in mind when
13 porting from <span class="application">PL/SQL</span> to
14 <span class="application">PL/pgSQL</span> are:
16 </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
17 If a name used in an SQL command could be either a column name of a
18 table used in the command or a reference to a variable of the function,
19 <span class="application">PL/SQL</span> treats it as a column name.
20 By default, <span class="application">PL/pgSQL</span> will throw an error
21 complaining that the name is ambiguous. You can specify
22 <code class="literal">plpgsql.variable_conflict</code> = <code class="literal">use_column</code>
23 to change this behavior to match <span class="application">PL/SQL</span>,
24 as explained in <a class="xref" href="plpgsql-implementation.html#PLPGSQL-VAR-SUBST" title="41.11.1. Variable Substitution">Section 41.11.1</a>.
25 It's often best to avoid such ambiguities in the first place,
26 but if you have to port a large amount of code that depends on
27 this behavior, setting <code class="literal">variable_conflict</code> may be the
29 </p></li><li class="listitem"><p>
30 In <span class="productname">PostgreSQL</span> the function body must be written as
31 a string literal. Therefore you need to use dollar quoting or escape
32 single quotes in the function body. (See <a class="xref" href="plpgsql-development-tips.html#PLPGSQL-QUOTE-TIPS" title="41.12.1. Handling of Quotation Marks">Section 41.12.1</a>.)
33 </p></li><li class="listitem"><p>
34 Data type names often need translation. For example, in Oracle string
35 values are commonly declared as being of type <code class="type">varchar2</code>, which
36 is a non-SQL-standard type. In <span class="productname">PostgreSQL</span>,
37 use type <code class="type">varchar</code> or <code class="type">text</code> instead. Similarly, replace
38 type <code class="type">number</code> with <code class="type">numeric</code>, or use some other numeric
39 data type if there's a more appropriate one.
40 </p></li><li class="listitem"><p>
41 Instead of packages, use schemas to organize your functions
43 </p></li><li class="listitem"><p>
44 Since there are no packages, there are no package-level variables
45 either. This is somewhat annoying. You can keep per-session state
46 in temporary tables instead.
47 </p></li><li class="listitem"><p>
48 Integer <code class="command">FOR</code> loops with <code class="literal">REVERSE</code> work
49 differently: <span class="application">PL/SQL</span> counts down from the second
50 number to the first, while <span class="application">PL/pgSQL</span> counts down
51 from the first number to the second, requiring the loop bounds
52 to be swapped when porting. This incompatibility is unfortunate
53 but is unlikely to be changed. (See <a class="xref" href="plpgsql-control-structures.html#PLPGSQL-INTEGER-FOR" title="41.6.5.5. FOR (Integer Variant)">Section 41.6.5.5</a>.)
54 </p></li><li class="listitem"><p>
55 <code class="command">FOR</code> loops over queries (other than cursors) also work
56 differently: the target variable(s) must have been declared,
57 whereas <span class="application">PL/SQL</span> always declares them implicitly.
58 An advantage of this is that the variable values are still accessible
60 </p></li><li class="listitem"><p>
61 There are various notational differences for the use of cursor
63 </p></li></ul></div><p>
64 </p><div class="sect2" id="PLPGSQL-PORTING-EXAMPLES"><div class="titlepage"><div><div><h3 class="title">41.13.1. Porting Examples <a href="#PLPGSQL-PORTING-EXAMPLES" class="id_link">#</a></h3></div></div></div><p>
65 <a class="xref" href="plpgsql-porting.html#PGSQL-PORTING-EX1" title="Example 41.9. Porting a Simple Function from PL/SQL to PL/pgSQL">Example 41.9</a> shows how to port a simple
66 function from <span class="application">PL/SQL</span> to <span class="application">PL/pgSQL</span>.
67 </p><div class="example" id="PGSQL-PORTING-EX1"><p class="title"><strong>Example 41.9. Porting a Simple Function from <span class="application">PL/SQL</span> to <span class="application">PL/pgSQL</span></strong></p><div class="example-contents"><p>
68 Here is an <span class="productname">Oracle</span> <span class="application">PL/SQL</span> function:
69 </p><pre class="programlisting">
70 CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar2,
74 IF v_version IS NULL THEN
77 RETURN v_name || '/' || v_version;
83 Let's go through this function and see the differences compared to
84 <span class="application">PL/pgSQL</span>:
86 </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
87 The type name <code class="type">varchar2</code> has to be changed to <code class="type">varchar</code>
88 or <code class="type">text</code>. In the examples in this section, we'll
89 use <code class="type">varchar</code>, but <code class="type">text</code> is often a better choice if
90 you do not need specific string length limits.
91 </p></li><li class="listitem"><p>
92 The <code class="literal">RETURN</code> key word in the function
93 prototype (not the function body) becomes
94 <code class="literal">RETURNS</code> in
95 <span class="productname">PostgreSQL</span>.
96 Also, <code class="literal">IS</code> becomes <code class="literal">AS</code>, and you need to
97 add a <code class="literal">LANGUAGE</code> clause because <span class="application">PL/pgSQL</span>
98 is not the only possible function language.
99 </p></li><li class="listitem"><p>
100 In <span class="productname">PostgreSQL</span>, the function body is considered
101 to be a string literal, so you need to use quote marks or dollar
102 quotes around it. This substitutes for the terminating <code class="literal">/</code>
103 in the Oracle approach.
104 </p></li><li class="listitem"><p>
105 The <code class="literal">show errors</code> command does not exist in
106 <span class="productname">PostgreSQL</span>, and is not needed since errors are
107 reported automatically.
108 </p></li></ul></div><p>
110 This is how this function would look when ported to
111 <span class="productname">PostgreSQL</span>:
113 </p><pre class="programlisting">
114 CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,
116 RETURNS varchar AS $$
118 IF v_version IS NULL THEN
121 RETURN v_name || '/' || v_version;
125 </p></div></div><br class="example-break" /><p>
126 <a class="xref" href="plpgsql-porting.html#PLPGSQL-PORTING-EX2" title="Example 41.10. Porting a Function that Creates Another Function from PL/SQL to PL/pgSQL">Example 41.10</a> shows how to port a
127 function that creates another function and how to handle the
128 ensuing quoting problems.
129 </p><div class="example" id="PLPGSQL-PORTING-EX2"><p class="title"><strong>Example 41.10. Porting a Function that Creates Another Function from <span class="application">PL/SQL</span> to <span class="application">PL/pgSQL</span></strong></p><div class="example-contents"><p>
130 The following procedure grabs rows from a
131 <code class="command">SELECT</code> statement and builds a large function
132 with the results in <code class="literal">IF</code> statements, for the
135 This is the Oracle version:
136 </p><pre class="programlisting">
137 CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
138 CURSOR referrer_keys IS
139 SELECT * FROM cs_referrer_keys
141 func_cmd VARCHAR(4000);
143 func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR2,
144 v_domain IN VARCHAR2, v_url IN VARCHAR2) RETURN VARCHAR2 IS BEGIN';
146 FOR referrer_key IN referrer_keys LOOP
147 func_cmd := func_cmd ||
148 ' IF v_' || referrer_key.kind
149 || ' LIKE ''' || referrer_key.key_string
150 || ''' THEN RETURN ''' || referrer_key.referrer_type
154 func_cmd := func_cmd || ' RETURN NULL; END;';
156 EXECUTE IMMEDIATE func_cmd;
162 Here is how this function would end up in <span class="productname">PostgreSQL</span>:
163 </p><pre class="programlisting">
164 CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc() AS $func$
166 referrer_keys CURSOR IS
167 SELECT * FROM cs_referrer_keys
172 func_body := 'BEGIN';
174 FOR referrer_key IN referrer_keys LOOP
175 func_body := func_body ||
176 ' IF v_' || referrer_key.kind
177 || ' LIKE ' || quote_literal(referrer_key.key_string)
178 || ' THEN RETURN ' || quote_literal(referrer_key.referrer_type)
182 func_body := func_body || ' RETURN NULL; END;';
185 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host varchar,
189 || quote_literal(func_body)
190 || ' LANGUAGE plpgsql;' ;
194 $func$ LANGUAGE plpgsql;
196 Notice how the body of the function is built separately and passed
197 through <code class="literal">quote_literal</code> to double any quote marks in it. This
198 technique is needed because we cannot safely use dollar quoting for
199 defining the new function: we do not know for sure what strings will
200 be interpolated from the <code class="structfield">referrer_key.key_string</code> field.
201 (We are assuming here that <code class="structfield">referrer_key.kind</code> can be
202 trusted to always be <code class="literal">host</code>, <code class="literal">domain</code>, or
203 <code class="literal">url</code>, but <code class="structfield">referrer_key.key_string</code> might be
204 anything, in particular it might contain dollar signs.) This function
205 is actually an improvement on the Oracle original, because it will
206 not generate broken code when <code class="structfield">referrer_key.key_string</code> or
207 <code class="structfield">referrer_key.referrer_type</code> contain quote marks.
208 </p></div></div><br class="example-break" /><p>
209 <a class="xref" href="plpgsql-porting.html#PLPGSQL-PORTING-EX3" title="Example 41.11. Porting a Procedure With String Manipulation and OUT Parameters from PL/SQL to PL/pgSQL">Example 41.11</a> shows how to port a function
210 with <code class="literal">OUT</code> parameters and string manipulation.
211 <span class="productname">PostgreSQL</span> does not have a built-in
212 <code class="function">instr</code> function, but you can create one
213 using a combination of other
214 functions. In <a class="xref" href="plpgsql-porting.html#PLPGSQL-PORTING-APPENDIX" title="41.13.3. Appendix">Section 41.13.3</a> there is a
215 <span class="application">PL/pgSQL</span> implementation of
216 <code class="function">instr</code> that you can use to make your porting
218 </p><div class="example" id="PLPGSQL-PORTING-EX3"><p class="title"><strong>Example 41.11. Porting a Procedure With String Manipulation and
219 <code class="literal">OUT</code> Parameters from <span class="application">PL/SQL</span> to
220 <span class="application">PL/pgSQL</span></strong></p><div class="example-contents"><p>
221 The following <span class="productname">Oracle</span> PL/SQL procedure is used
222 to parse a URL and return several elements (host, path, and query).
224 This is the Oracle version:
225 </p><pre class="programlisting">
226 CREATE OR REPLACE PROCEDURE cs_parse_url(
228 v_host OUT VARCHAR2, -- This will be passed back
229 v_path OUT VARCHAR2, -- This one too
230 v_query OUT VARCHAR2) -- And this one
238 a_pos1 := instr(v_url, '//');
243 a_pos2 := instr(v_url, '/', a_pos1 + 2);
245 v_host := substr(v_url, a_pos1 + 2);
250 v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
251 a_pos1 := instr(v_url, '?', a_pos2 + 1);
254 v_path := substr(v_url, a_pos2);
258 v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
259 v_query := substr(v_url, a_pos1 + 1);
265 Here is a possible translation into <span class="application">PL/pgSQL</span>:
266 </p><pre class="programlisting">
267 CREATE OR REPLACE FUNCTION cs_parse_url(
269 v_host OUT VARCHAR, -- This will be passed back
270 v_path OUT VARCHAR, -- This one too
271 v_query OUT VARCHAR) -- And this one
280 a_pos1 := instr(v_url, '//');
285 a_pos2 := instr(v_url, '/', a_pos1 + 2);
287 v_host := substr(v_url, a_pos1 + 2);
292 v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
293 a_pos1 := instr(v_url, '?', a_pos2 + 1);
296 v_path := substr(v_url, a_pos2);
300 v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
301 v_query := substr(v_url, a_pos1 + 1);
306 This function could be used like this:
307 </p><pre class="programlisting">
308 SELECT * FROM cs_parse_url('http://foobar.com/query.cgi?baz');
310 </p></div></div><br class="example-break" /><p>
311 <a class="xref" href="plpgsql-porting.html#PLPGSQL-PORTING-EX4" title="Example 41.12. Porting a Procedure from PL/SQL to PL/pgSQL">Example 41.12</a> shows how to port a procedure
312 that uses numerous features that are specific to Oracle.
313 </p><div class="example" id="PLPGSQL-PORTING-EX4"><p class="title"><strong>Example 41.12. Porting a Procedure from <span class="application">PL/SQL</span> to <span class="application">PL/pgSQL</span></strong></p><div class="example-contents"><p>
316 </p><pre class="programlisting">
317 CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
318 a_running_job_count INTEGER;
320 LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
322 SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
324 IF a_running_job_count > 0 THEN
326 raise_application_error(-20000,
327 'Unable to create a new job: a job is currently running.');
330 DELETE FROM cs_active_job;
331 INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
334 INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now());
336 WHEN dup_val_on_index THEN NULL; -- don't worry if it already exists
344 This is how we could port this procedure to <span class="application">PL/pgSQL</span>:
346 </p><pre class="programlisting">
347 CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id integer) AS $$
349 a_running_job_count integer;
351 LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
353 SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
355 IF a_running_job_count > 0 THEN
357 RAISE EXCEPTION 'Unable to create a new job: a job is currently running'; -- <span id="co.plpgsql-porting-raise"></span>(1)
360 DELETE FROM cs_active_job;
361 INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
364 INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now());
366 WHEN unique_violation THEN -- <span id="co.plpgsql-porting-exception"></span>(2)
367 -- don't worry if it already exists
374 </p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#co.plpgsql-porting-raise">(1)</a> </p></td><td valign="top" align="left"><p>
375 The syntax of <code class="literal">RAISE</code> is considerably different from
376 Oracle's statement, although the basic case <code class="literal">RAISE</code>
377 <em class="replaceable"><code>exception_name</code></em> works
379 </p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#co.plpgsql-porting-exception">(2)</a> </p></td><td valign="top" align="left"><p>
380 The exception names supported by <span class="application">PL/pgSQL</span> are
381 different from Oracle's. The set of built-in exception names
382 is much larger (see <a class="xref" href="errcodes-appendix.html" title="Appendix A. PostgreSQL Error Codes">Appendix A</a>). There
383 is not currently a way to declare user-defined exception names,
384 although you can throw user-chosen SQLSTATE values instead.
385 </p></td></tr></table></div><p>
386 </p></div></div><br class="example-break" /></div><div class="sect2" id="PLPGSQL-PORTING-OTHER"><div class="titlepage"><div><div><h3 class="title">41.13.2. Other Things to Watch For <a href="#PLPGSQL-PORTING-OTHER" class="id_link">#</a></h3></div></div></div><p>
387 This section explains a few other things to watch for when porting
388 Oracle <span class="application">PL/SQL</span> functions to
389 <span class="productname">PostgreSQL</span>.
390 </p><div class="sect3" id="PLPGSQL-PORTING-EXCEPTIONS"><div class="titlepage"><div><div><h4 class="title">41.13.2.1. Implicit Rollback after Exceptions <a href="#PLPGSQL-PORTING-EXCEPTIONS" class="id_link">#</a></h4></div></div></div><p>
391 In <span class="application">PL/pgSQL</span>, when an exception is caught by an
392 <code class="literal">EXCEPTION</code> clause, all database changes since the block's
393 <code class="literal">BEGIN</code> are automatically rolled back. That is, the behavior
394 is equivalent to what you'd get in Oracle with:
396 </p><pre class="programlisting">
410 If you are translating an Oracle procedure that uses
411 <code class="command">SAVEPOINT</code> and <code class="command">ROLLBACK TO</code> in this style,
412 your task is easy: just omit the <code class="command">SAVEPOINT</code> and
413 <code class="command">ROLLBACK TO</code>. If you have a procedure that uses
414 <code class="command">SAVEPOINT</code> and <code class="command">ROLLBACK TO</code> in a different way
415 then some actual thought will be required.
416 </p></div><div class="sect3" id="PLPGSQL-PORTING-OTHER-EXECUTE"><div class="titlepage"><div><div><h4 class="title">41.13.2.2. <code class="command">EXECUTE</code> <a href="#PLPGSQL-PORTING-OTHER-EXECUTE" class="id_link">#</a></h4></div></div></div><p>
417 The <span class="application">PL/pgSQL</span> version of
418 <code class="command">EXECUTE</code> works similarly to the
419 <span class="application">PL/SQL</span> version, but you have to remember to use
420 <code class="function">quote_literal</code> and
421 <code class="function">quote_ident</code> as described in <a class="xref" href="plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN" title="41.5.4. Executing Dynamic Commands">Section 41.5.4</a>. Constructs of the
422 type <code class="literal">EXECUTE 'SELECT * FROM $1';</code> will not work
423 reliably unless you use these functions.
424 </p></div><div class="sect3" id="PLPGSQL-PORTING-OPTIMIZATION"><div class="titlepage"><div><div><h4 class="title">41.13.2.3. Optimizing <span class="application">PL/pgSQL</span> Functions <a href="#PLPGSQL-PORTING-OPTIMIZATION" class="id_link">#</a></h4></div></div></div><p>
425 <span class="productname">PostgreSQL</span> gives you two function creation
426 modifiers to optimize execution: <span class="quote">“<span class="quote">volatility</span>”</span> (whether
427 the function always returns the same result when given the same
428 arguments) and <span class="quote">“<span class="quote">strictness</span>”</span> (whether the function
429 returns null if any argument is null). Consult the <a class="xref" href="sql-createfunction.html" title="CREATE FUNCTION"><span class="refentrytitle">CREATE FUNCTION</span></a>
430 reference page for details.
432 When making use of these optimization attributes, your
433 <code class="command">CREATE FUNCTION</code> statement might look something
436 </p><pre class="programlisting">
437 CREATE FUNCTION foo(...) RETURNS integer AS $$
439 $$ LANGUAGE plpgsql STRICT IMMUTABLE;
441 </p></div></div><div class="sect2" id="PLPGSQL-PORTING-APPENDIX"><div class="titlepage"><div><div><h3 class="title">41.13.3. Appendix <a href="#PLPGSQL-PORTING-APPENDIX" class="id_link">#</a></h3></div></div></div><p>
442 This section contains the code for a set of Oracle-compatible
443 <code class="function">instr</code> functions that you can use to simplify
444 your porting efforts.
445 </p><a id="id-1.8.8.15.8.3" class="indexterm"></a><pre class="programlisting">
447 -- instr functions that mimic Oracle's counterpart
448 -- Syntax: instr(string1, string2 [, n [, m]])
449 -- where [] denotes optional parameters.
451 -- Search string1, beginning at the nth character, for the mth occurrence
452 -- of string2. If n is negative, search backwards, starting at the abs(n)'th
453 -- character from the end of string1.
454 -- If n is not passed, assume 1 (search starts at first character).
455 -- If m is not passed, assume 1 (find first occurrence).
456 -- Returns starting index of string2 in string1, or 0 if string2 is not found.
459 CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
461 RETURN instr($1, $2, 1);
463 $$ LANGUAGE plpgsql STRICT IMMUTABLE;
466 CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
468 RETURNS integer AS $$
470 pos integer NOT NULL DEFAULT 0;
476 IF beg_index > 0 THEN
477 temp_str := substring(string FROM beg_index);
478 pos := position(string_to_search_for IN temp_str);
483 RETURN pos + beg_index - 1;
485 ELSIF beg_index < 0 THEN
486 ss_length := char_length(string_to_search_for);
487 length := char_length(string);
488 beg := length + 1 + beg_index;
490 WHILE beg > 0 LOOP
491 temp_str := substring(string FROM beg FOR ss_length);
492 IF string_to_search_for = temp_str THEN
504 $$ LANGUAGE plpgsql STRICT IMMUTABLE;
507 CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
508 beg_index integer, occur_index integer)
509 RETURNS integer AS $$
511 pos integer NOT NULL DEFAULT 0;
512 occur_number integer NOT NULL DEFAULT 0;
519 IF occur_index <= 0 THEN
520 RAISE 'argument ''%'' is out of range', occur_index
521 USING ERRCODE = '22003';
524 IF beg_index > 0 THEN
525 beg := beg_index - 1;
526 FOR i IN 1..occur_index LOOP
527 temp_str := substring(string FROM beg + 1);
528 pos := position(string_to_search_for IN temp_str);
536 ELSIF beg_index < 0 THEN
537 ss_length := char_length(string_to_search_for);
538 length := char_length(string);
539 beg := length + 1 + beg_index;
541 WHILE beg > 0 LOOP
542 temp_str := substring(string FROM beg FOR ss_length);
543 IF string_to_search_for = temp_str THEN
544 occur_number := occur_number + 1;
545 IF occur_number = occur_index THEN
558 $$ LANGUAGE plpgsql STRICT IMMUTABLE;
560 </pre></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="plpgsql-development-tips.html" title="41.12. Tips for Developing in PL/pgSQL">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="plpgsql.html" title="Chapter 41. PL/pgSQL — SQL Procedural Language">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="pltcl.html" title="Chapter 42. PL/Tcl — Tcl Procedural Language">Next</a></td></tr><tr><td width="40%" align="left" valign="top">41.12. Tips for Developing in <span class="application">PL/pgSQL</span> </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> Chapter 42. PL/Tcl — Tcl Procedural Language</td></tr></table></div></body></html>