~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to doc/src/sgml/html/plpgsql-porting.html

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
2
<HTML
 
3
><HEAD
 
4
><TITLE
 
5
>Porting from Oracle PL/SQL</TITLE
 
6
><META
 
7
NAME="GENERATOR"
 
8
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
 
9
REV="MADE"
 
10
HREF="mailto:pgsql-docs@postgresql.org"><LINK
 
11
REL="HOME"
 
12
TITLE="PostgreSQL 9.1beta1 Documentation"
 
13
HREF="index.html"><LINK
 
14
REL="UP"
 
15
TITLE="PL/pgSQL - SQL Procedural Language"
 
16
HREF="plpgsql.html"><LINK
 
17
REL="PREVIOUS"
 
18
TITLE="Tips for Developing in PL/pgSQL"
 
19
HREF="plpgsql-development-tips.html"><LINK
 
20
REL="NEXT"
 
21
TITLE="PL/Tcl - Tcl Procedural Language"
 
22
HREF="pltcl.html"><LINK
 
23
REL="STYLESHEET"
 
24
TYPE="text/css"
 
25
HREF="stylesheet.css"><META
 
26
HTTP-EQUIV="Content-Type"
 
27
CONTENT="text/html; charset=ISO-8859-1"><META
 
28
NAME="creation"
 
29
CONTENT="2011-04-27T21:20:33"></HEAD
 
30
><BODY
 
31
CLASS="SECT1"
 
32
><DIV
 
33
CLASS="NAVHEADER"
 
34
><TABLE
 
35
SUMMARY="Header navigation table"
 
36
WIDTH="100%"
 
37
BORDER="0"
 
38
CELLPADDING="0"
 
39
CELLSPACING="0"
 
40
><TR
 
41
><TH
 
42
COLSPAN="5"
 
43
ALIGN="center"
 
44
VALIGN="bottom"
 
45
><A
 
46
HREF="index.html"
 
47
>PostgreSQL 9.1beta1 Documentation</A
 
48
></TH
 
49
></TR
 
50
><TR
 
51
><TD
 
52
WIDTH="10%"
 
53
ALIGN="left"
 
54
VALIGN="top"
 
55
><A
 
56
TITLE="Tips for Developing in PL/pgSQL"
 
57
HREF="plpgsql-development-tips.html"
 
58
ACCESSKEY="P"
 
59
>Prev</A
 
60
></TD
 
61
><TD
 
62
WIDTH="10%"
 
63
ALIGN="left"
 
64
VALIGN="top"
 
65
><A
 
66
TITLE="PL/pgSQL - SQL Procedural Language"
 
67
HREF="plpgsql.html"
 
68
>Fast Backward</A
 
69
></TD
 
70
><TD
 
71
WIDTH="60%"
 
72
ALIGN="center"
 
73
VALIGN="bottom"
 
74
>Chapter 39. <SPAN
 
75
CLASS="APPLICATION"
 
76
>PL/pgSQL</SPAN
 
77
> - <ACRONYM
 
78
CLASS="ACRONYM"
 
79
>SQL</ACRONYM
 
80
> Procedural Language</TD
 
81
><TD
 
82
WIDTH="10%"
 
83
ALIGN="right"
 
84
VALIGN="top"
 
85
><A
 
86
TITLE="PL/pgSQL - SQL Procedural Language"
 
87
HREF="plpgsql.html"
 
88
>Fast Forward</A
 
89
></TD
 
90
><TD
 
91
WIDTH="10%"
 
92
ALIGN="right"
 
93
VALIGN="top"
 
94
><A
 
95
TITLE="PL/Tcl - Tcl Procedural Language"
 
96
HREF="pltcl.html"
 
97
ACCESSKEY="N"
 
98
>Next</A
 
99
></TD
 
100
></TR
 
101
></TABLE
 
102
><HR
 
103
ALIGN="LEFT"
 
104
WIDTH="100%"></DIV
 
105
><DIV
 
106
CLASS="SECT1"
 
107
><H1
 
108
CLASS="SECT1"
 
109
><A
 
110
NAME="PLPGSQL-PORTING"
 
111
>39.12. Porting from <SPAN
 
112
CLASS="PRODUCTNAME"
 
113
>Oracle</SPAN
 
114
> PL/SQL</A
 
115
></H1
 
116
><P
 
117
>   This section explains differences between
 
118
   <SPAN
 
119
CLASS="PRODUCTNAME"
 
120
>PostgreSQL</SPAN
 
121
>'s <SPAN
 
122
CLASS="APPLICATION"
 
123
>PL/pgSQL</SPAN
 
124
>
 
125
   language and Oracle's <SPAN
 
126
CLASS="APPLICATION"
 
127
>PL/SQL</SPAN
 
128
> language,
 
129
   to help developers who port applications from
 
130
   <SPAN
 
131
CLASS="TRADEMARK"
 
132
>Oracle</SPAN
 
133
>&reg; to <SPAN
 
134
CLASS="PRODUCTNAME"
 
135
>PostgreSQL</SPAN
 
136
>.
 
137
  </P
 
138
><P
 
139
>   <SPAN
 
140
CLASS="APPLICATION"
 
141
>PL/pgSQL</SPAN
 
142
> is similar to PL/SQL in many
 
143
   aspects. It is a block-structured, imperative language, and all
 
144
   variables have to be declared.  Assignments, loops, conditionals
 
145
   are similar.  The main differences you should keep in mind when
 
146
   porting from <SPAN
 
147
CLASS="APPLICATION"
 
148
>PL/SQL</SPAN
 
149
> to
 
150
   <SPAN
 
151
CLASS="APPLICATION"
 
152
>PL/pgSQL</SPAN
 
153
> are:
 
154
 
 
155
    <P
 
156
></P
 
157
></P><UL
 
158
><LI
 
159
><P
 
160
>       If a name used in a SQL command could be either a column name of a
 
161
       table or a reference to a variable of the function,
 
162
       <SPAN
 
163
CLASS="APPLICATION"
 
164
>PL/SQL</SPAN
 
165
> treats it as a column name.  This corresponds
 
166
       to <SPAN
 
167
CLASS="APPLICATION"
 
168
>PL/pgSQL</SPAN
 
169
>'s
 
170
       <TT
 
171
CLASS="LITERAL"
 
172
>plpgsql.variable_conflict</TT
 
173
> = <TT
 
174
CLASS="LITERAL"
 
175
>use_column</TT
 
176
>
 
177
       behavior, which is not the default,
 
178
       as explained in <A
 
179
HREF="plpgsql-implementation.html#PLPGSQL-VAR-SUBST"
 
180
>Section 39.10.1</A
 
181
>.
 
182
       It's often best to avoid such ambiguities in the first place,
 
183
       but if you have to port a large amount of code that depends on
 
184
       this behavior, setting <TT
 
185
CLASS="LITERAL"
 
186
>variable_conflict</TT
 
187
> may be the
 
188
       best solution.
 
189
      </P
 
190
></LI
 
191
><LI
 
192
><P
 
193
>       In <SPAN
 
194
CLASS="PRODUCTNAME"
 
195
>PostgreSQL</SPAN
 
196
> the function body must be written as
 
197
       a string literal.  Therefore you need to use dollar quoting or escape
 
198
       single quotes in the function body. (See <A
 
199
HREF="plpgsql-development-tips.html#PLPGSQL-QUOTE-TIPS"
 
200
>Section 39.11.1</A
 
201
>.)
 
202
      </P
 
203
></LI
 
204
><LI
 
205
><P
 
206
>       Instead of packages, use schemas to organize your functions
 
207
       into groups.
 
208
      </P
 
209
></LI
 
210
><LI
 
211
><P
 
212
>       Since there are no packages, there are no package-level variables
 
213
       either. This is somewhat annoying.  You can keep per-session state
 
214
       in temporary tables instead.
 
215
      </P
 
216
></LI
 
217
><LI
 
218
><P
 
219
>       Integer <TT
 
220
CLASS="COMMAND"
 
221
>FOR</TT
 
222
> loops with <TT
 
223
CLASS="LITERAL"
 
224
>REVERSE</TT
 
225
> work
 
226
       differently: <SPAN
 
227
CLASS="APPLICATION"
 
228
>PL/SQL</SPAN
 
229
> counts down from the second
 
230
       number to the first, while <SPAN
 
231
CLASS="APPLICATION"
 
232
>PL/pgSQL</SPAN
 
233
> counts down
 
234
       from the first number to the second, requiring the loop bounds
 
235
       to be swapped when porting.  This incompatibility is unfortunate
 
236
       but is unlikely to be changed. (See <A
 
237
HREF="plpgsql-control-structures.html#PLPGSQL-INTEGER-FOR"
 
238
>Section 39.6.3.5</A
 
239
>.)
 
240
      </P
 
241
></LI
 
242
><LI
 
243
><P
 
244
>       <TT
 
245
CLASS="COMMAND"
 
246
>FOR</TT
 
247
> loops over queries (other than cursors) also work
 
248
       differently: the target variable(s) must have been declared,
 
249
       whereas <SPAN
 
250
CLASS="APPLICATION"
 
251
>PL/SQL</SPAN
 
252
> always declares them implicitly.
 
253
       An advantage of this is that the variable values are still accessible
 
254
       after the loop exits.
 
255
      </P
 
256
></LI
 
257
><LI
 
258
><P
 
259
>       There are various notational differences for the use of cursor
 
260
       variables.
 
261
      </P
 
262
></LI
 
263
></UL
 
264
><P>
 
265
   </P
 
266
><DIV
 
267
CLASS="SECT2"
 
268
><H2
 
269
CLASS="SECT2"
 
270
><A
 
271
NAME="AEN55254"
 
272
>39.12.1. Porting Examples</A
 
273
></H2
 
274
><P
 
275
>    <A
 
276
HREF="plpgsql-porting.html#PGSQL-PORTING-EX1"
 
277
>Example 39-7</A
 
278
> shows how to port a simple
 
279
    function from <SPAN
 
280
CLASS="APPLICATION"
 
281
>PL/SQL</SPAN
 
282
> to <SPAN
 
283
CLASS="APPLICATION"
 
284
>PL/pgSQL</SPAN
 
285
>.
 
286
   </P
 
287
><DIV
 
288
CLASS="EXAMPLE"
 
289
><A
 
290
NAME="PGSQL-PORTING-EX1"
 
291
></A
 
292
><P
 
293
><B
 
294
>Example 39-7. Porting a Simple Function from <SPAN
 
295
CLASS="APPLICATION"
 
296
>PL/SQL</SPAN
 
297
> to <SPAN
 
298
CLASS="APPLICATION"
 
299
>PL/pgSQL</SPAN
 
300
></B
 
301
></P
 
302
><P
 
303
>     Here is an <SPAN
 
304
CLASS="PRODUCTNAME"
 
305
>Oracle</SPAN
 
306
> <SPAN
 
307
CLASS="APPLICATION"
 
308
>PL/SQL</SPAN
 
309
> function:
 
310
</P><PRE
 
311
CLASS="PROGRAMLISTING"
 
312
>CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,
 
313
                                                  v_version varchar)
 
314
RETURN varchar IS
 
315
BEGIN
 
316
    IF v_version IS NULL THEN
 
317
        RETURN v_name;
 
318
    END IF;
 
319
    RETURN v_name || '/' || v_version;
 
320
END;
 
321
/
 
322
show errors;</PRE
 
323
><P>
 
324
    </P
 
325
><P
 
326
>     Let's go through this function and see the differences compared to
 
327
     <SPAN
 
328
CLASS="APPLICATION"
 
329
>PL/pgSQL</SPAN
 
330
>:
 
331
 
 
332
     <P
 
333
></P
 
334
></P><UL
 
335
><LI
 
336
><P
 
337
>        The <TT
 
338
CLASS="LITERAL"
 
339
>RETURN</TT
 
340
> key word in the function
 
341
        prototype (not the function body) becomes
 
342
        <TT
 
343
CLASS="LITERAL"
 
344
>RETURNS</TT
 
345
> in
 
346
        <SPAN
 
347
CLASS="PRODUCTNAME"
 
348
>PostgreSQL</SPAN
 
349
>.
 
350
        Also, <TT
 
351
CLASS="LITERAL"
 
352
>IS</TT
 
353
> becomes <TT
 
354
CLASS="LITERAL"
 
355
>AS</TT
 
356
>, and you need to
 
357
        add a <TT
 
358
CLASS="LITERAL"
 
359
>LANGUAGE</TT
 
360
> clause because <SPAN
 
361
CLASS="APPLICATION"
 
362
>PL/pgSQL</SPAN
 
363
>
 
364
        is not the only possible function language.
 
365
       </P
 
366
></LI
 
367
><LI
 
368
><P
 
369
>        In <SPAN
 
370
CLASS="PRODUCTNAME"
 
371
>PostgreSQL</SPAN
 
372
>, the function body is considered
 
373
        to be a string literal, so you need to use quote marks or dollar
 
374
        quotes around it.  This substitutes for the terminating <TT
 
375
CLASS="LITERAL"
 
376
>/</TT
 
377
>
 
378
        in the Oracle approach.
 
379
       </P
 
380
></LI
 
381
><LI
 
382
><P
 
383
>        The <TT
 
384
CLASS="LITERAL"
 
385
>show errors</TT
 
386
> command does not exist in
 
387
        <SPAN
 
388
CLASS="PRODUCTNAME"
 
389
>PostgreSQL</SPAN
 
390
>, and is not needed since errors are
 
391
        reported automatically.
 
392
       </P
 
393
></LI
 
394
></UL
 
395
><P>
 
396
    </P
 
397
><P
 
398
>     This is how this function would look when ported to
 
399
     <SPAN
 
400
CLASS="PRODUCTNAME"
 
401
>PostgreSQL</SPAN
 
402
>:
 
403
 
 
404
</P><PRE
 
405
CLASS="PROGRAMLISTING"
 
406
>CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,
 
407
                                                  v_version varchar)
 
408
RETURNS varchar AS $$
 
409
BEGIN
 
410
    IF v_version IS NULL THEN
 
411
        RETURN v_name;
 
412
    END IF;
 
413
    RETURN v_name || '/' || v_version;
 
414
END;
 
415
$$ LANGUAGE plpgsql;</PRE
 
416
><P>
 
417
    </P
 
418
></DIV
 
419
><P
 
420
>    <A
 
421
HREF="plpgsql-porting.html#PLPGSQL-PORTING-EX2"
 
422
>Example 39-8</A
 
423
> shows how to port a
 
424
    function that creates another function and how to handle the
 
425
    ensuing quoting problems.
 
426
   </P
 
427
><DIV
 
428
CLASS="EXAMPLE"
 
429
><A
 
430
NAME="PLPGSQL-PORTING-EX2"
 
431
></A
 
432
><P
 
433
><B
 
434
>Example 39-8. Porting a Function that Creates Another Function from <SPAN
 
435
CLASS="APPLICATION"
 
436
>PL/SQL</SPAN
 
437
> to <SPAN
 
438
CLASS="APPLICATION"
 
439
>PL/pgSQL</SPAN
 
440
></B
 
441
></P
 
442
><P
 
443
>     The following procedure grabs rows from a
 
444
     <TT
 
445
CLASS="COMMAND"
 
446
>SELECT</TT
 
447
> statement and builds a large function
 
448
     with the results in <TT
 
449
CLASS="LITERAL"
 
450
>IF</TT
 
451
> statements, for the
 
452
     sake of efficiency.
 
453
    </P
 
454
><P
 
455
>     This is the Oracle version:
 
456
</P><PRE
 
457
CLASS="PROGRAMLISTING"
 
458
>CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
 
459
    CURSOR referrer_keys IS
 
460
        SELECT * FROM cs_referrer_keys
 
461
        ORDER BY try_order;
 
462
    func_cmd VARCHAR(4000);
 
463
BEGIN
 
464
    func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR,
 
465
                 v_domain IN VARCHAR, v_url IN VARCHAR) RETURN VARCHAR IS BEGIN';
 
466
 
 
467
    FOR referrer_key IN referrer_keys LOOP
 
468
        func_cmd := func_cmd ||
 
469
          ' IF v_' || referrer_key.kind
 
470
          || ' LIKE ''' || referrer_key.key_string
 
471
          || ''' THEN RETURN ''' || referrer_key.referrer_type
 
472
          || '''; END IF;';
 
473
    END LOOP;
 
474
 
 
475
    func_cmd := func_cmd || ' RETURN NULL; END;';
 
476
 
 
477
    EXECUTE IMMEDIATE func_cmd;
 
478
END;
 
479
/
 
480
show errors;</PRE
 
481
><P>
 
482
    </P
 
483
><P
 
484
>     Here is how this function would end up in <SPAN
 
485
CLASS="PRODUCTNAME"
 
486
>PostgreSQL</SPAN
 
487
>:
 
488
</P><PRE
 
489
CLASS="PROGRAMLISTING"
 
490
>CREATE OR REPLACE FUNCTION cs_update_referrer_type_proc() RETURNS void AS $func$
 
491
DECLARE
 
492
    referrer_keys CURSOR IS
 
493
        SELECT * FROM cs_referrer_keys
 
494
        ORDER BY try_order;
 
495
    func_body text;
 
496
    func_cmd text;
 
497
BEGIN
 
498
    func_body := 'BEGIN';
 
499
 
 
500
    FOR referrer_key IN referrer_keys LOOP
 
501
        func_body := func_body ||
 
502
          ' IF v_' || referrer_key.kind
 
503
          || ' LIKE ' || quote_literal(referrer_key.key_string)
 
504
          || ' THEN RETURN ' || quote_literal(referrer_key.referrer_type)
 
505
          || '; END IF;' ;
 
506
    END LOOP;
 
507
 
 
508
    func_body := func_body || ' RETURN NULL; END;';
 
509
 
 
510
    func_cmd :=
 
511
      'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host varchar,
 
512
                                                        v_domain varchar,
 
513
                                                        v_url varchar)
 
514
        RETURNS varchar AS '
 
515
      || quote_literal(func_body)
 
516
      || ' LANGUAGE plpgsql;' ;
 
517
 
 
518
    EXECUTE func_cmd;
 
519
END;
 
520
$func$ LANGUAGE plpgsql;</PRE
 
521
><P>
 
522
     Notice how the body of the function is built separately and passed
 
523
     through <TT
 
524
CLASS="LITERAL"
 
525
>quote_literal</TT
 
526
> to double any quote marks in it.  This
 
527
     technique is needed because we cannot safely use dollar quoting for
 
528
     defining the new function: we do not know for sure what strings will
 
529
     be interpolated from the <TT
 
530
CLASS="STRUCTFIELD"
 
531
>referrer_key.key_string</TT
 
532
> field.
 
533
     (We are assuming here that <TT
 
534
CLASS="STRUCTFIELD"
 
535
>referrer_key.kind</TT
 
536
> can be
 
537
     trusted to always be <TT
 
538
CLASS="LITERAL"
 
539
>host</TT
 
540
>, <TT
 
541
CLASS="LITERAL"
 
542
>domain</TT
 
543
>, or
 
544
     <TT
 
545
CLASS="LITERAL"
 
546
>url</TT
 
547
>, but <TT
 
548
CLASS="STRUCTFIELD"
 
549
>referrer_key.key_string</TT
 
550
> might be
 
551
     anything, in particular it might contain dollar signs.) This function
 
552
     is actually an improvement on the Oracle original, because it will
 
553
     not generate broken code when <TT
 
554
CLASS="STRUCTFIELD"
 
555
>referrer_key.key_string</TT
 
556
> or
 
557
     <TT
 
558
CLASS="STRUCTFIELD"
 
559
>referrer_key.referrer_type</TT
 
560
> contain quote marks.
 
561
    </P
 
562
></DIV
 
563
><P
 
564
>    <A
 
565
HREF="plpgsql-porting.html#PLPGSQL-PORTING-EX3"
 
566
>Example 39-9</A
 
567
> shows how to port a function
 
568
    with <TT
 
569
CLASS="LITERAL"
 
570
>OUT</TT
 
571
> parameters and string manipulation.
 
572
    <SPAN
 
573
CLASS="PRODUCTNAME"
 
574
>PostgreSQL</SPAN
 
575
> does not have a built-in
 
576
    <CODE
 
577
CLASS="FUNCTION"
 
578
>instr</CODE
 
579
> function, but you can create one
 
580
    using a combination of other
 
581
    functions. In <A
 
582
HREF="plpgsql-porting.html#PLPGSQL-PORTING-APPENDIX"
 
583
>Section 39.12.3</A
 
584
> there is a
 
585
    <SPAN
 
586
CLASS="APPLICATION"
 
587
>PL/pgSQL</SPAN
 
588
> implementation of
 
589
    <CODE
 
590
CLASS="FUNCTION"
 
591
>instr</CODE
 
592
> that you can use to make your porting
 
593
    easier.
 
594
   </P
 
595
><DIV
 
596
CLASS="EXAMPLE"
 
597
><A
 
598
NAME="PLPGSQL-PORTING-EX3"
 
599
></A
 
600
><P
 
601
><B
 
602
>Example 39-9. Porting a Procedure With String Manipulation and
 
603
    <TT
 
604
CLASS="LITERAL"
 
605
>OUT</TT
 
606
> Parameters from <SPAN
 
607
CLASS="APPLICATION"
 
608
>PL/SQL</SPAN
 
609
> to
 
610
    <SPAN
 
611
CLASS="APPLICATION"
 
612
>PL/pgSQL</SPAN
 
613
></B
 
614
></P
 
615
><P
 
616
>     The following <SPAN
 
617
CLASS="PRODUCTNAME"
 
618
>Oracle</SPAN
 
619
> PL/SQL procedure is used
 
620
     to parse a URL and return several elements (host, path, and query).
 
621
    </P
 
622
><P
 
623
>     This is the Oracle version:
 
624
</P><PRE
 
625
CLASS="PROGRAMLISTING"
 
626
>CREATE OR REPLACE PROCEDURE cs_parse_url(
 
627
    v_url IN VARCHAR,
 
628
    v_host OUT VARCHAR,  -- This will be passed back
 
629
    v_path OUT VARCHAR,  -- This one too
 
630
    v_query OUT VARCHAR) -- And this one
 
631
IS
 
632
    a_pos1 INTEGER;
 
633
    a_pos2 INTEGER;
 
634
BEGIN
 
635
    v_host := NULL;
 
636
    v_path := NULL;
 
637
    v_query := NULL;
 
638
    a_pos1 := instr(v_url, '//');
 
639
 
 
640
    IF a_pos1 = 0 THEN
 
641
        RETURN;
 
642
    END IF;
 
643
    a_pos2 := instr(v_url, '/', a_pos1 + 2);
 
644
    IF a_pos2 = 0 THEN
 
645
        v_host := substr(v_url, a_pos1 + 2);
 
646
        v_path := '/';
 
647
        RETURN;
 
648
    END IF;
 
649
 
 
650
    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
 
651
    a_pos1 := instr(v_url, '?', a_pos2 + 1);
 
652
 
 
653
    IF a_pos1 = 0 THEN
 
654
        v_path := substr(v_url, a_pos2);
 
655
        RETURN;
 
656
    END IF;
 
657
 
 
658
    v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
 
659
    v_query := substr(v_url, a_pos1 + 1);
 
660
END;
 
661
/
 
662
show errors;</PRE
 
663
><P>
 
664
    </P
 
665
><P
 
666
>     Here is a possible translation into <SPAN
 
667
CLASS="APPLICATION"
 
668
>PL/pgSQL</SPAN
 
669
>:
 
670
</P><PRE
 
671
CLASS="PROGRAMLISTING"
 
672
>CREATE OR REPLACE FUNCTION cs_parse_url(
 
673
    v_url IN VARCHAR,
 
674
    v_host OUT VARCHAR,  -- This will be passed back
 
675
    v_path OUT VARCHAR,  -- This one too
 
676
    v_query OUT VARCHAR) -- And this one
 
677
AS $$
 
678
DECLARE
 
679
    a_pos1 INTEGER;
 
680
    a_pos2 INTEGER;
 
681
BEGIN
 
682
    v_host := NULL;
 
683
    v_path := NULL;
 
684
    v_query := NULL;
 
685
    a_pos1 := instr(v_url, '//');
 
686
 
 
687
    IF a_pos1 = 0 THEN
 
688
        RETURN;
 
689
    END IF;
 
690
    a_pos2 := instr(v_url, '/', a_pos1 + 2);
 
691
    IF a_pos2 = 0 THEN
 
692
        v_host := substr(v_url, a_pos1 + 2);
 
693
        v_path := '/';
 
694
        RETURN;
 
695
    END IF;
 
696
 
 
697
    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
 
698
    a_pos1 := instr(v_url, '?', a_pos2 + 1);
 
699
 
 
700
    IF a_pos1 = 0 THEN
 
701
        v_path := substr(v_url, a_pos2);
 
702
        RETURN;
 
703
    END IF;
 
704
 
 
705
    v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
 
706
    v_query := substr(v_url, a_pos1 + 1);
 
707
END;
 
708
$$ LANGUAGE plpgsql;</PRE
 
709
><P>
 
710
 
 
711
     This function could be used like this:
 
712
</P><PRE
 
713
CLASS="PROGRAMLISTING"
 
714
>SELECT * FROM cs_parse_url('http://foobar.com/query.cgi?baz');</PRE
 
715
><P>
 
716
    </P
 
717
></DIV
 
718
><P
 
719
>    <A
 
720
HREF="plpgsql-porting.html#PLPGSQL-PORTING-EX4"
 
721
>Example 39-10</A
 
722
> shows how to port a procedure
 
723
    that uses numerous features that are specific to Oracle.
 
724
   </P
 
725
><DIV
 
726
CLASS="EXAMPLE"
 
727
><A
 
728
NAME="PLPGSQL-PORTING-EX4"
 
729
></A
 
730
><P
 
731
><B
 
732
>Example 39-10. Porting a Procedure from <SPAN
 
733
CLASS="APPLICATION"
 
734
>PL/SQL</SPAN
 
735
> to <SPAN
 
736
CLASS="APPLICATION"
 
737
>PL/pgSQL</SPAN
 
738
></B
 
739
></P
 
740
><P
 
741
>     The Oracle version:
 
742
 
 
743
</P><PRE
 
744
CLASS="PROGRAMLISTING"
 
745
>CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
 
746
    a_running_job_count INTEGER;
 
747
    PRAGMA AUTONOMOUS_TRANSACTION;<A
 
748
NAME="CO.PLPGSQL-PORTING-PRAGMA"
 
749
><B
 
750
>(1)</B
 
751
></A
 
752
>
 
753
BEGIN
 
754
    LOCK TABLE cs_jobs IN EXCLUSIVE MODE;<A
 
755
NAME="CO.PLPGSQL-PORTING-LOCKTABLE"
 
756
><B
 
757
>(2)</B
 
758
></A
 
759
>
 
760
 
 
761
    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
 
762
 
 
763
    IF a_running_job_count &gt; 0 THEN
 
764
        COMMIT; -- free lock<A
 
765
NAME="CO.PLPGSQL-PORTING-COMMIT"
 
766
><B
 
767
>(3)</B
 
768
></A
 
769
>
 
770
        raise_application_error(-20000,
 
771
                 'Unable to create a new job: a job is currently running.');
 
772
    END IF;
 
773
 
 
774
    DELETE FROM cs_active_job;
 
775
    INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
 
776
 
 
777
    BEGIN
 
778
        INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, sysdate);
 
779
    EXCEPTION
 
780
        WHEN dup_val_on_index THEN NULL; -- don't worry if it already exists
 
781
    END;
 
782
    COMMIT;
 
783
END;
 
784
/
 
785
show errors</PRE
 
786
><P>
 
787
   </P
 
788
><P
 
789
>    Procedures like this can easily be converted into <SPAN
 
790
CLASS="PRODUCTNAME"
 
791
>PostgreSQL</SPAN
 
792
>
 
793
    functions returning <TT
 
794
CLASS="TYPE"
 
795
>void</TT
 
796
>. This procedure in
 
797
    particular is interesting because it can teach us some things:
 
798
 
 
799
    <DIV
 
800
CLASS="CALLOUTLIST"
 
801
><DL
 
802
COMPACT="COMPACT"
 
803
><DT
 
804
><A
 
805
HREF="plpgsql-porting.html#CO.PLPGSQL-PORTING-PRAGMA"
 
806
><B
 
807
>(1)</B
 
808
></A
 
809
></DT
 
810
><DD
 
811
>       There is no <TT
 
812
CLASS="LITERAL"
 
813
>PRAGMA</TT
 
814
> statement in <SPAN
 
815
CLASS="PRODUCTNAME"
 
816
>PostgreSQL</SPAN
 
817
>.
 
818
      </DD
 
819
><DT
 
820
><A
 
821
HREF="plpgsql-porting.html#CO.PLPGSQL-PORTING-LOCKTABLE"
 
822
><B
 
823
>(2)</B
 
824
></A
 
825
></DT
 
826
><DD
 
827
>       If you do a <TT
 
828
CLASS="COMMAND"
 
829
>LOCK TABLE</TT
 
830
> in <SPAN
 
831
CLASS="APPLICATION"
 
832
>PL/pgSQL</SPAN
 
833
>,
 
834
       the lock will not be released until the calling transaction is
 
835
       finished.
 
836
      </DD
 
837
><DT
 
838
><A
 
839
HREF="plpgsql-porting.html#CO.PLPGSQL-PORTING-COMMIT"
 
840
><B
 
841
>(3)</B
 
842
></A
 
843
></DT
 
844
><DD
 
845
>       You cannot issue <TT
 
846
CLASS="COMMAND"
 
847
>COMMIT</TT
 
848
> in a
 
849
       <SPAN
 
850
CLASS="APPLICATION"
 
851
>PL/pgSQL</SPAN
 
852
> function.  The function is
 
853
       running within some outer transaction and so <TT
 
854
CLASS="COMMAND"
 
855
>COMMIT</TT
 
856
>
 
857
       would imply terminating the function's execution.  However, in
 
858
       this particular case it is not necessary anyway, because the lock
 
859
       obtained by the <TT
 
860
CLASS="COMMAND"
 
861
>LOCK TABLE</TT
 
862
> will be released when
 
863
       we raise an error.
 
864
      </DD
 
865
></DL
 
866
></DIV
 
867
>
 
868
   </P
 
869
><P
 
870
>    This is how we could port this procedure to <SPAN
 
871
CLASS="APPLICATION"
 
872
>PL/pgSQL</SPAN
 
873
>:
 
874
 
 
875
</P><PRE
 
876
CLASS="PROGRAMLISTING"
 
877
>CREATE OR REPLACE FUNCTION cs_create_job(v_job_id integer) RETURNS void AS $$
 
878
DECLARE
 
879
    a_running_job_count integer;
 
880
BEGIN
 
881
    LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
 
882
 
 
883
    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
 
884
 
 
885
    IF a_running_job_count &gt; 0 THEN
 
886
        RAISE EXCEPTION 'Unable to create a new job: a job is currently running';<A
 
887
NAME="CO.PLPGSQL-PORTING-RAISE"
 
888
><B
 
889
>(1)</B
 
890
></A
 
891
>
 
892
    END IF;
 
893
 
 
894
    DELETE FROM cs_active_job;
 
895
    INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
 
896
 
 
897
    BEGIN
 
898
        INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now());
 
899
    EXCEPTION
 
900
        WHEN unique_violation THEN <A
 
901
NAME="CO.PLPGSQL-PORTING-EXCEPTION"
 
902
><B
 
903
>(2)</B
 
904
></A
 
905
>
 
906
            -- don't worry if it already exists
 
907
    END;
 
908
END;
 
909
$$ LANGUAGE plpgsql;</PRE
 
910
><P>
 
911
 
 
912
    <DIV
 
913
CLASS="CALLOUTLIST"
 
914
><DL
 
915
COMPACT="COMPACT"
 
916
><DT
 
917
><A
 
918
HREF="plpgsql-porting.html#CO.PLPGSQL-PORTING-RAISE"
 
919
><B
 
920
>(1)</B
 
921
></A
 
922
></DT
 
923
><DD
 
924
>       The syntax of <TT
 
925
CLASS="LITERAL"
 
926
>RAISE</TT
 
927
> is considerably different from
 
928
       Oracle's statement, although the basic case <TT
 
929
CLASS="LITERAL"
 
930
>RAISE</TT
 
931
>
 
932
       <TT
 
933
CLASS="REPLACEABLE"
 
934
><I
 
935
>exception_name</I
 
936
></TT
 
937
> works
 
938
       similarly.
 
939
      </DD
 
940
><DT
 
941
><A
 
942
HREF="plpgsql-porting.html#CO.PLPGSQL-PORTING-EXCEPTION"
 
943
><B
 
944
>(2)</B
 
945
></A
 
946
></DT
 
947
><DD
 
948
>       The exception names supported by <SPAN
 
949
CLASS="APPLICATION"
 
950
>PL/pgSQL</SPAN
 
951
> are
 
952
       different from Oracle's.  The set of built-in exception names
 
953
       is much larger (see <A
 
954
HREF="errcodes-appendix.html"
 
955
>Appendix A</A
 
956
>).  There
 
957
       is not currently a way to declare user-defined exception names,
 
958
       although you can throw user-chosen SQLSTATE values instead.
 
959
      </DD
 
960
></DL
 
961
></DIV
 
962
>
 
963
 
 
964
    The main functional difference between this procedure and the
 
965
    Oracle equivalent is that the exclusive lock on the <TT
 
966
CLASS="LITERAL"
 
967
>cs_jobs</TT
 
968
>
 
969
    table will be held until the calling transaction completes.  Also, if
 
970
    the caller later aborts (for example due to an error), the effects of
 
971
    this procedure will be rolled back.
 
972
   </P
 
973
></DIV
 
974
></DIV
 
975
><DIV
 
976
CLASS="SECT2"
 
977
><H2
 
978
CLASS="SECT2"
 
979
><A
 
980
NAME="PLPGSQL-PORTING-OTHER"
 
981
>39.12.2. Other Things to Watch For</A
 
982
></H2
 
983
><P
 
984
>    This section explains a few other things to watch for when porting
 
985
    Oracle <SPAN
 
986
CLASS="APPLICATION"
 
987
>PL/SQL</SPAN
 
988
> functions to
 
989
    <SPAN
 
990
CLASS="PRODUCTNAME"
 
991
>PostgreSQL</SPAN
 
992
>.
 
993
   </P
 
994
><DIV
 
995
CLASS="SECT3"
 
996
><H3
 
997
CLASS="SECT3"
 
998
><A
 
999
NAME="PLPGSQL-PORTING-EXCEPTIONS"
 
1000
>39.12.2.1. Implicit Rollback after Exceptions</A
 
1001
></H3
 
1002
><P
 
1003
>     In <SPAN
 
1004
CLASS="APPLICATION"
 
1005
>PL/pgSQL</SPAN
 
1006
>, when an exception is caught by an
 
1007
     <TT
 
1008
CLASS="LITERAL"
 
1009
>EXCEPTION</TT
 
1010
> clause, all database changes since the block's
 
1011
     <TT
 
1012
CLASS="LITERAL"
 
1013
>BEGIN</TT
 
1014
> are automatically rolled back.  That is, the behavior
 
1015
     is equivalent to what you'd get in Oracle with:
 
1016
 
 
1017
</P><PRE
 
1018
CLASS="PROGRAMLISTING"
 
1019
>BEGIN
 
1020
    SAVEPOINT s1;
 
1021
    ... code here ...
 
1022
EXCEPTION
 
1023
    WHEN ... THEN
 
1024
        ROLLBACK TO s1;
 
1025
        ... code here ...
 
1026
    WHEN ... THEN
 
1027
        ROLLBACK TO s1;
 
1028
        ... code here ...
 
1029
END;</PRE
 
1030
><P>
 
1031
 
 
1032
     If you are translating an Oracle procedure that uses
 
1033
     <TT
 
1034
CLASS="COMMAND"
 
1035
>SAVEPOINT</TT
 
1036
> and <TT
 
1037
CLASS="COMMAND"
 
1038
>ROLLBACK TO</TT
 
1039
> in this style,
 
1040
     your task is easy: just omit the <TT
 
1041
CLASS="COMMAND"
 
1042
>SAVEPOINT</TT
 
1043
> and
 
1044
     <TT
 
1045
CLASS="COMMAND"
 
1046
>ROLLBACK TO</TT
 
1047
>.  If you have a procedure that uses
 
1048
     <TT
 
1049
CLASS="COMMAND"
 
1050
>SAVEPOINT</TT
 
1051
> and <TT
 
1052
CLASS="COMMAND"
 
1053
>ROLLBACK TO</TT
 
1054
> in a different way
 
1055
     then some actual thought will be required.
 
1056
    </P
 
1057
></DIV
 
1058
><DIV
 
1059
CLASS="SECT3"
 
1060
><H3
 
1061
CLASS="SECT3"
 
1062
><A
 
1063
NAME="AEN55400"
 
1064
>39.12.2.2. <TT
 
1065
CLASS="COMMAND"
 
1066
>EXECUTE</TT
 
1067
></A
 
1068
></H3
 
1069
><P
 
1070
>     The <SPAN
 
1071
CLASS="APPLICATION"
 
1072
>PL/pgSQL</SPAN
 
1073
> version of
 
1074
     <TT
 
1075
CLASS="COMMAND"
 
1076
>EXECUTE</TT
 
1077
> works similarly to the
 
1078
     <SPAN
 
1079
CLASS="APPLICATION"
 
1080
>PL/SQL</SPAN
 
1081
> version, but you have to remember to use
 
1082
     <CODE
 
1083
CLASS="FUNCTION"
 
1084
>quote_literal</CODE
 
1085
> and
 
1086
     <CODE
 
1087
CLASS="FUNCTION"
 
1088
>quote_ident</CODE
 
1089
> as described in <A
 
1090
HREF="plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN"
 
1091
>Section 39.5.4</A
 
1092
>.  Constructs of the
 
1093
     type <TT
 
1094
CLASS="LITERAL"
 
1095
>EXECUTE 'SELECT * FROM $1';</TT
 
1096
> will not work
 
1097
     reliably unless you use these functions.
 
1098
    </P
 
1099
></DIV
 
1100
><DIV
 
1101
CLASS="SECT3"
 
1102
><H3
 
1103
CLASS="SECT3"
 
1104
><A
 
1105
NAME="PLPGSQL-PORTING-OPTIMIZATION"
 
1106
>39.12.2.3. Optimizing <SPAN
 
1107
CLASS="APPLICATION"
 
1108
>PL/pgSQL</SPAN
 
1109
> Functions</A
 
1110
></H3
 
1111
><P
 
1112
>     <SPAN
 
1113
CLASS="PRODUCTNAME"
 
1114
>PostgreSQL</SPAN
 
1115
> gives you two function creation
 
1116
     modifiers to optimize execution: <SPAN
 
1117
CLASS="QUOTE"
 
1118
>"volatility"</SPAN
 
1119
> (whether
 
1120
     the function always returns the same result when given the same
 
1121
     arguments) and <SPAN
 
1122
CLASS="QUOTE"
 
1123
>"strictness"</SPAN
 
1124
> (whether the function
 
1125
     returns null if any argument is null).  Consult the <A
 
1126
HREF="sql-createfunction.html"
 
1127
>CREATE FUNCTION</A
 
1128
>
 
1129
     reference page for details.
 
1130
    </P
 
1131
><P
 
1132
>     When making use of these optimization attributes, your
 
1133
     <TT
 
1134
CLASS="COMMAND"
 
1135
>CREATE FUNCTION</TT
 
1136
> statement might look something
 
1137
     like this:
 
1138
 
 
1139
</P><PRE
 
1140
CLASS="PROGRAMLISTING"
 
1141
>CREATE FUNCTION foo(...) RETURNS integer AS $$
 
1142
...
 
1143
$$ LANGUAGE plpgsql STRICT IMMUTABLE;</PRE
 
1144
><P>
 
1145
    </P
 
1146
></DIV
 
1147
></DIV
 
1148
><DIV
 
1149
CLASS="SECT2"
 
1150
><H2
 
1151
CLASS="SECT2"
 
1152
><A
 
1153
NAME="PLPGSQL-PORTING-APPENDIX"
 
1154
>39.12.3. Appendix</A
 
1155
></H2
 
1156
><P
 
1157
>    This section contains the code for a set of Oracle-compatible
 
1158
    <CODE
 
1159
CLASS="FUNCTION"
 
1160
>instr</CODE
 
1161
> functions that you can use to simplify
 
1162
    your porting efforts.
 
1163
   </P
 
1164
><PRE
 
1165
CLASS="PROGRAMLISTING"
 
1166
>--
 
1167
-- instr functions that mimic Oracle's counterpart
 
1168
-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
 
1169
--
 
1170
-- Searches string1 beginning at the nth character for the mth occurrence
 
1171
-- of string2.  If n is negative, search backwards.  If m is not passed,
 
1172
-- assume 1 (search starts at first character).
 
1173
--
 
1174
 
 
1175
CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
 
1176
DECLARE
 
1177
    pos integer;
 
1178
BEGIN
 
1179
    pos:= instr($1, $2, 1);
 
1180
    RETURN pos;
 
1181
END;
 
1182
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
 
1183
 
 
1184
 
 
1185
CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer)
 
1186
RETURNS integer AS $$
 
1187
DECLARE
 
1188
    pos integer NOT NULL DEFAULT 0;
 
1189
    temp_str varchar;
 
1190
    beg integer;
 
1191
    length integer;
 
1192
    ss_length integer;
 
1193
BEGIN
 
1194
    IF beg_index &gt; 0 THEN
 
1195
        temp_str := substring(string FROM beg_index);
 
1196
        pos := position(string_to_search IN temp_str);
 
1197
 
 
1198
        IF pos = 0 THEN
 
1199
            RETURN 0;
 
1200
        ELSE
 
1201
            RETURN pos + beg_index - 1;
 
1202
        END IF;
 
1203
    ELSE
 
1204
        ss_length := char_length(string_to_search);
 
1205
        length := char_length(string);
 
1206
        beg := length + beg_index - ss_length + 2;
 
1207
 
 
1208
        WHILE beg &gt; 0 LOOP
 
1209
            temp_str := substring(string FROM beg FOR ss_length);
 
1210
            pos := position(string_to_search IN temp_str);
 
1211
 
 
1212
            IF pos &gt; 0 THEN
 
1213
                RETURN beg;
 
1214
            END IF;
 
1215
 
 
1216
            beg := beg - 1;
 
1217
        END LOOP;
 
1218
 
 
1219
        RETURN 0;
 
1220
    END IF;
 
1221
END;
 
1222
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
 
1223
 
 
1224
 
 
1225
CREATE FUNCTION instr(string varchar, string_to_search varchar,
 
1226
                      beg_index integer, occur_index integer)
 
1227
RETURNS integer AS $$
 
1228
DECLARE
 
1229
    pos integer NOT NULL DEFAULT 0;
 
1230
    occur_number integer NOT NULL DEFAULT 0;
 
1231
    temp_str varchar;
 
1232
    beg integer;
 
1233
    i integer;
 
1234
    length integer;
 
1235
    ss_length integer;
 
1236
BEGIN
 
1237
    IF beg_index &gt; 0 THEN
 
1238
        beg := beg_index;
 
1239
        temp_str := substring(string FROM beg_index);
 
1240
 
 
1241
        FOR i IN 1..occur_index LOOP
 
1242
            pos := position(string_to_search IN temp_str);
 
1243
 
 
1244
            IF i = 1 THEN
 
1245
                beg := beg + pos - 1;
 
1246
            ELSE
 
1247
                beg := beg + pos;
 
1248
            END IF;
 
1249
 
 
1250
            temp_str := substring(string FROM beg + 1);
 
1251
        END LOOP;
 
1252
 
 
1253
        IF pos = 0 THEN
 
1254
            RETURN 0;
 
1255
        ELSE
 
1256
            RETURN beg;
 
1257
        END IF;
 
1258
    ELSE
 
1259
        ss_length := char_length(string_to_search);
 
1260
        length := char_length(string);
 
1261
        beg := length + beg_index - ss_length + 2;
 
1262
 
 
1263
        WHILE beg &gt; 0 LOOP
 
1264
            temp_str := substring(string FROM beg FOR ss_length);
 
1265
            pos := position(string_to_search IN temp_str);
 
1266
 
 
1267
            IF pos &gt; 0 THEN
 
1268
                occur_number := occur_number + 1;
 
1269
 
 
1270
                IF occur_number = occur_index THEN
 
1271
                    RETURN beg;
 
1272
                END IF;
 
1273
            END IF;
 
1274
 
 
1275
            beg := beg - 1;
 
1276
        END LOOP;
 
1277
 
 
1278
        RETURN 0;
 
1279
    END IF;
 
1280
END;
 
1281
$$ LANGUAGE plpgsql STRICT IMMUTABLE;</PRE
 
1282
></DIV
 
1283
></DIV
 
1284
><DIV
 
1285
CLASS="NAVFOOTER"
 
1286
><HR
 
1287
ALIGN="LEFT"
 
1288
WIDTH="100%"><TABLE
 
1289
SUMMARY="Footer navigation table"
 
1290
WIDTH="100%"
 
1291
BORDER="0"
 
1292
CELLPADDING="0"
 
1293
CELLSPACING="0"
 
1294
><TR
 
1295
><TD
 
1296
WIDTH="33%"
 
1297
ALIGN="left"
 
1298
VALIGN="top"
 
1299
><A
 
1300
HREF="plpgsql-development-tips.html"
 
1301
ACCESSKEY="P"
 
1302
>Prev</A
 
1303
></TD
 
1304
><TD
 
1305
WIDTH="34%"
 
1306
ALIGN="center"
 
1307
VALIGN="top"
 
1308
><A
 
1309
HREF="index.html"
 
1310
ACCESSKEY="H"
 
1311
>Home</A
 
1312
></TD
 
1313
><TD
 
1314
WIDTH="33%"
 
1315
ALIGN="right"
 
1316
VALIGN="top"
 
1317
><A
 
1318
HREF="pltcl.html"
 
1319
ACCESSKEY="N"
 
1320
>Next</A
 
1321
></TD
 
1322
></TR
 
1323
><TR
 
1324
><TD
 
1325
WIDTH="33%"
 
1326
ALIGN="left"
 
1327
VALIGN="top"
 
1328
>Tips for Developing in <SPAN
 
1329
CLASS="APPLICATION"
 
1330
>PL/pgSQL</SPAN
 
1331
></TD
 
1332
><TD
 
1333
WIDTH="34%"
 
1334
ALIGN="center"
 
1335
VALIGN="top"
 
1336
><A
 
1337
HREF="plpgsql.html"
 
1338
ACCESSKEY="U"
 
1339
>Up</A
 
1340
></TD
 
1341
><TD
 
1342
WIDTH="33%"
 
1343
ALIGN="right"
 
1344
VALIGN="top"
 
1345
>PL/Tcl - Tcl Procedural Language</TD
 
1346
></TR
 
1347
></TABLE
 
1348
></DIV
 
1349
></BODY
 
1350
></HTML
 
1351
>
 
 
b'\\ No newline at end of file'