-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplpgsql.sgml
4072 lines (3561 loc) · 145 KB
/
plpgsql.sgml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!--
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.57 2005/01/15 03:38:44 tgl Exp $
-->
<chapter id="plpgsql">
<title>PL/pgSQL - Linguagem procedural SQL</title>
<indexterm zone="plpgsql">
<primary>PL/pgSQL</primary>
</indexterm>
<para>
<application>PL/pgSQL</application> é uma linguagem procedural carregável
desenvolvida para o sistema de banco de dados <productname>PostgreSQL</>.
Os objetivos de projeto da linguagem <application>PL/pgSQL</application> foram
no sentido de criar uma linguagem procedural carregável que pudesse:
<itemizedlist>
<listitem>
<para>
ser utilizada para criar procedimentos de funções e de gatilhos;
</para>
</listitem>
<listitem>
<para>
adicionar estruturas de controle à linguagem <acronym>SQL</acronym>;
</para>
</listitem>
<listitem>
<para>
realizar processamentos complexos;
</para>
</listitem>
<listitem>
<para>
herdar todos os tipos de dado, funções e operadores definidos pelo usuário;
</para>
</listitem>
<listitem>
<para>
ser definida como confiável pelo servidor;
</para>
</listitem>
<listitem>
<para>
ser fácil de utilizar.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Exceto pelas funções de conversão de entrada/saída e cálculos para os
tipos definidos pelo usuário, tudo mais que pode ser definido por uma função
escrita na linguagem C também pode ser feito usando
<application>PL/pgSQL</application>.
Por exemplo, é possível criar funções para cálculos condicionais complexos
e depois usá-las para definir operadores ou em expressões de índice.
</para>
<sect1 id="plpgsql-overview">
<title>Visão geral</title>
<para>
O tratador de chamadas da linguagem <application>PL/pgSQL</application>
analisa o texto do código fonte da função e produz uma árvore de instruções
binária interna, na primeira vez em que a função é chamada (em cada sessão).
A árvore de instruções traduz inteiramente a estrutura da declaração
<application>PL/pgSQL</application>, mas as expressões
<acronym>SQL</acronym> individuais e os comandos <acronym>SQL</acronym>
utilizados na função não são traduzidos imediatamente.
</para>
<para>
Assim que cada expressão ou comando <acronym>SQL</acronym> é utilizado pela
primeira vez na função, o interpretador do <application>PL/pgSQL</>
cria um plano de execução preparado (utilizando as funções
<function>SPI_prepare</function> e <function>SPI_saveplan</function>
do gerenciador da Interface de Programação do Servidor -
<acronym>SPI</acronym>).
<indexterm>
<primary>preparação do comando</primary>
<secondary>no PL/pgSQL</secondary>
</indexterm>
As execuções posteriores da expressão ou do comando reutilizam o plano
preparado.
Por isso, uma função com código condicional, contendo muitas declarações que
podem requerer um plano de execução, somente prepara e salva os planos
realmente utilizados durante o espaço de tempo da conexão com o banco de
dados.
Isto pode reduzir muito a quantidade total de tempo necessário para analisar
e gerar os planos de execução para as declarações na função
<application>PL/pgSQL</application>.
A desvantagem é que erros em uma determinada expressão ou comando podem não
ser detectados até que a parte da função onde se encontram seja executada.
</para>
<para>
Uma vez que o <application>PL/pgSQL</application> tenha construído um plano
de execução para um determinado comando da função, este plano será
reutilizado enquanto durar a conexão com o banco de dados.
Normalmente há um ganho de desempenho, mas pode causar problema se o
esquema do banco de dados for modificado dinamicamente.
Por exemplo:
<programlisting>
CREATE FUNCTION populate() RETURNS integer AS $$
DECLARE
-- declarações
BEGIN
PERFORM minha_funcao();
END;
$$ LANGUAGE plpgsql;
</programlisting>
Se a função acima for executada fará referência ao OID da
<function>minha_funcao()</function> no plano de execução gerado para a
instrução <command>PERFORM</command>. Mais tarde, se a função
<function>minha_funcao()</function> for removida e recriada, então
<function>populate()</function> não vai mais conseguir encontrar
<function>minha_funcao()</function>. Por isso é necessário recriar
<function>populate()</function>, ou pelo menos começar uma nova sessão de
banco de dados para que a função seja compilada novamente.
Outra forma de evitar este problema é utilizar
<command>CREATE OR REPLACE FUNCTION</command> ao atualizar a definição de
<function>minha_funcao</function> (quando a função é
<quote>substituída</quote> o OID não muda).
</para>
<para>
Uma vez que o <application>PL/pgSQL</application> salva os planos de
execução desta maneira, os comandos SQL que aparecem diretamente na função
<application>PL/pgSQL</application> devem fazer referência às mesmas
tabelas e colunas em todas as execuções; ou seja, não pode ser utilizado um
parâmetro como nome de tabela ou de coluna no comando SQL. Para contornar
esta restrição podem ser construídos comandos dinâmicos utilizando a
instrução <command>EXECUTE</command> do <application>PL/pgSQL</application>
— o preço a ser pago é a construção de um novo plano de execução a
cada execução.
</para>
<note>
<para>
A instrução <command>EXECUTE</command> do
<application>PL/pgSQL</application> não tem relação com a instrução
<xref linkend="sql-execute" endterm="sql-execute-title"> do SQL suportada
pelo servidor <productname>PostgreSQL</productname>. A instrução
<command>EXECUTE</command> do servidor não pode ser utilizada dentro das
funções <application>PL/pgSQL</application> (e não é necessário).
</para>
</note>
<sect2 id="plpgsql-advantages">
<title>Vantagens da utilização da linguagem PL/pgSQL</title>
<para>
A linguagem <acronym>SQL</acronym> é a que o <productname>PostgreSQL</>
(e a maioria dos bancos de dados relacionais) utiliza como linguagem de
comandos. É portável e fácil de ser aprendida. Entretanto, todas as
declarações <acronym>SQL</acronym> devem ser executadas individualmente
pelo servidor de banco de dados.
</para>
<para>
Isto significa que o aplicativo cliente deve enviar o comando para
o servidor de banco de dados, aguardar que seja processado, receber os
resultados, realizar algum processamento, e enviar o próximo comando
para o servidor. Tudo isto envolve comunicação entre processos e pode,
também, envolver tráfego na rede se o cliente não estiver na mesma
máquina onde se encontra o servidor de banco de dados.
</para>
<para>
Usando a linguagem <application>PL/pgSQL</application> pode ser agrupado um
bloco de processamento e uma série de comandos <emphasis>dentro</emphasis>
do servidor de banco de dados, juntando o poder da linguagem procedural
com a facilidade de uso da linguagem SQL, e economizando muito tempo,
porque não há necessidade da sobrecarga de comunicação entre o cliente e o
servidor. Isto pode aumentar o desempenho consideravelmente.
</para>
<para>
Também podem ser utilizados na linguagem <application>PL/pgSQL</application>
todos os tipos de dados, operadores e funções da linguagem SQL.
</para>
</sect2>
<sect2 id="plpgsql-args-results">
<title>Tipos de dado suportados nos argumentos e no resultado</title>
<para>
As funções escritas em <application>PL/pgSQL</application> aceitam como
argumento qualquer tipo de dado escalar ou matriz suportado pelo servidor,
e podem retornar como resultado qualquer um destes tipos.
As funções também aceitam e retornam qualquer tipo composto (tipo linha)
especificado por nome.
Também é possível declarar uma função <application>PL/pgSQL</application>
como retornando <type>record</type>, significando que o resultado
é um tipo linha, cujas colunas são determinadas pela especificação no
comando que faz a chamada, conforme mostrado na
<xref linkend="queries-tablefunctions">.
</para>
<para>
As funções <application>PL/pgSQL</application> também podem ser declaradas
como recebendo ou retornando os tipos polimórficos
<type>anyelement</type> e <type>anyarray</type>. Os tipos de dado
verdadeiros tratados pelas funções polimórficas podem variar entre
chamadas, conforme mostrado na <xref linkend="extend-types-polymorphic">.
Na <xref linkend="plpgsql-declaration-aliases"> é mostrado um exemplo.
</para>
<para>
As funções <application>PL/pgSQL</application> também podem ser declaradas
como retornando <quote>set</quote> (conjunto), ou tabela, de qualquer tipo
de dado para o qual pode ser retornada uma única instância. Este tipo de
função gera sua saída executando <literal>RETURN NEXT</literal> para cada
elemento desejado do conjunto resultado.
</para>
<para>
Por fim, uma função <application>PL/pgSQL</application> pode ser declarada
como retornando <type>void</type> se não produzir nenhum valor de retorno
útil.
</para>
<para>
Atualmente a linguagem <application>PL/pgSQL</> não possui suporte total
para os tipos domínio: trata o domínio da mesma maneira que o tipo escalar
subjacente. Isto significa que não obriga respeitar as restrições
associadas ao domínio, o que não representa problema para os argumentos
da função, mas é perigoso declarar uma função <application>PL/pgSQL</>
como retornando um tipo domínio.
</para>
</sect2>
</sect1>
<sect1 id="plpgsql-development-tips">
<title>Dicas para desenvolvimento em PL/pgSQL</title>
<para>
Uma boa maneira de desenvolver em <application>PL/pgSQL</application> é
utilizar o editor de texto preferido para criar as funções e, em outra
janela, utilizar o <application>psql</application> para carregar e testar
as funções desenvolvidas. Se estiver sendo feito desta maneira, é uma boa
idéia escrever a função utilizando <command>CREATE OR REPLACE FUNCTION</>.
Fazendo assim, basta recarregar o arquivo para atualizar a definição da
função. Por exemplo:
<programlisting>
CREATE OR REPLACE FUNCTION funcao_teste(integer) RETURNS integer AS $$
....
$$ LANGUAGE plpgsql;
</programlisting>
</para>
<para>
Na linha de comando do <application>psql</application> a definição da função
pode ser carregada ou recarregada utilizando
<programlisting>
\i nome_do_arquivo.sql
</programlisting>
e logo em seguida podem ser executados os comandos SQL que testam a função.
</para>
<para>
Outra boa maneira de desenvolver em <application>PL/pgSQL</application>, é
utilizar uma ferramenta de acesso ao banco de dados com interface gráfica
que facilite o desenvolvimento em linguagem procedural.
Um exemplo deste tipo de ferramenta é o <application>PgAccess</application>,
mas existem outras.
Estas ferramentas geralmente disponibilizam funcionalidades úteis como o
escape de apóstrofos, e tornam mais fácil recriar e depurar funções.
</para>
<sect2 id="plpgsql-quote-tips">
<title>Tratamento dos apóstrofos</title>
<para>
O código da função <application>PL/pgSQL</application> é especificado no
comando <command>CREATE FUNCTION</command> como um literal cadeia de
caracteres. Se o literal cadeia de caracteres for escrito da maneira usual,
que é entre apóstrofos (<literal>'</literal>), então os apóstrofos dentro
do corpo da função devem ser duplicados; da mesma maneira, as contrabarras
dentro do corpo da função (<literal>\</literal>) devem ser duplicadas.
Duplicar os apóstrofos é no mínimo entediante, e nos casos mais complicados
pode tornar o código difícil de ser compreendido, porque pode-se chegar
facilmente a uma situação onde são necessários seis ou mais apóstrofos
adjacentes.
Por isso, recomenda-se que o corpo da função seja escrito em um literal
cadeia de caracteres delimitado por <quote>cifrão</>
(consulte a <xref linkend="sql-syntax-dollar-quoting">) em vez de delimitado
por apóstrofos.
Na abordagem delimitada por cifrão os apóstrofos nunca são duplicados e,
em vez disso, toma-se o cuidado de escolher uma marca diferente
para cada nível de aninhamento necessário. Por exemplo, o comando
<command>CREATE FUNCTION</command> pode ser escrito da seguinte maneira:
<programlisting>
CREATE OR REPLACE FUNCTION funcao_teste(integer) RETURNS integer AS $PROC$
....
$PROC$ LANGUAGE plpgsql;
</programlisting>
No corpo da função podem ser utilizados apóstrofos para delimitar cadeias
de caracteres simples nos comandos <acronym>SQL</acronym>, e
<literal>$$</literal> para delimitar fragmentos de comandos
<acronym>SQL</acronym> montados como cadeia de caracteres.
Se for necessário delimitar um texto contendo <literal>$$</literal>,
deve ser utilizado <literal>$Q$</literal>, e assim por diante.
</para>
<para>
O quadro abaixo mostra o que deve ser feito para escrever o corpo da função
entre apóstrofos (sem uso da delimitação por cifrão). Pode ser útil para
tornar códigos anteriores à delimitação por cifrão mais fácil de serem
compreendidos.
</para>
<variablelist>
<varlistentry>
<term>1 apóstrofo</term>
<listitem>
<para>
para começar e terminar o corpo da função como, por exemplo:
<programlisting>
CREATE FUNCTION foo() RETURNS integer AS '
....
' LANGUAGE plpgsql;
</programlisting>
Em todas as ocorrências dentro do corpo da função os apóstrofos
<emphasis>devem</emphasis> aparecer em pares.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>2 apóstrofos</term>
<listitem>
<para>
Para literais cadeia de caracteres dentro do corpo da função como, por exemplo:
<programlisting>
a_output := ''Blah'';
SELECT * FROM users WHERE f_nome=''foobar'';
</programlisting>
Na abordagem delimitada por cifrão seria escrito apenas
<programlisting>
a_output := 'Blah';
SELECT * FROM users WHERE f_nome='foobar';
</programlisting>
que é exatamente o código visto pelo analisador do
<application>PL/pgSQL</application> nos dois casos.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>4 apóstrofos</term>
<listitem>
<para>
Quando é necessário colocar um apóstrofo em uma constante cadeia de
caracteres dentro do corpo da função como, por exemplo:
<programlisting>
a_output := a_output || '' AND nome LIKE ''''foobar'''' AND xyz''
</programlisting>
O verdadeiro valor anexado a <literal>a_output</literal> seria:
<literal> AND nome LIKE 'foobar' AND xyz</literal>.
</para>
<para>
Na abordagem delimitada por cifrão seria escrito
<programlisting>
a_output := a_output || $$ AND nome LIKE 'foobar' AND xyz$$
</programlisting>
tendo-se o cuidado de que todos os delimitadores por cifrão envolvendo
este comando não sejam apenas <literal>$$</>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>6 apóstrofos</term>
<listitem>
<para>
Quando o apóstrofo na cadeia de caracteres dentro do corpo da função está
adjacente ao final da constante cadeia de caracteres como, por exemplo:
<programlisting>
a_output := a_output || '' AND nome LIKE ''''foobar''''''
</programlisting>
O valor anexado à <literal>a_output</literal> seria:
<literal> AND nome LIKE 'foobar'</literal>.
</para>
<para>
Na abordagem delimitada por cifrão se tornaria
<programlisting>
a_output := a_output || $$ AND nome LIKE 'foobar'$$
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>10 apóstrofos</term>
<listitem>
<para>
Quando é necessário colocar dois apóstrofos em uma constante cadeia de
caracteres (que necessita de 8 apóstrofos), e estes dois apóstrofos estão
adjacentes ao final da constante cadeia de caracteres (mais 2 apóstrofos).
Normalmente isto só é necessário quando são escritas funções que geram
outras funções como no <xref linkend="plpgsql-porting-ex2">.
Por exemplo:
<programlisting>
a_output := a_output || '' if v_'' ||
referrer_keys.kind || '' like ''''''''''
|| referrer_keys.key_string || ''''''''''
then return '''''' || referrer_keys.referrer_type
|| ''''''; end if;'';
</programlisting>
O valor de <literal>a_output</literal> seria então:
<programlisting>
if v_... like ''...'' then return ''...''; end if;
</programlisting>
</para>
<para>
Na abordagem delimitada por cifrão se tornaria
<programlisting>
a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$
|| referrer_keys.key_string || $$'
then return '$$ || referrer_keys.referrer_type
|| $$'; end if;$$;
</programlisting>
onde se assume que só é necessário colocar um único apóstrofo em
<literal>a_output</literal>, porque este será delimitado novamente antes
de ser utilizado.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Uma outra abordagem é fazer o escape dos apóstrofos no corpo da função
utilizando a contrabarra em vez de duplicá-los. Desta forma é escrito
<literal>\'\'</literal> no lugar de <literal>''''</literal>. Alguns acham
esta forma mais fácil, porém outros não concordam.
</para>
</sect2>
</sect1>
<sect1 id="plpgsql-structure">
<title>Estrutura da linguagem PL/pgSQL</title>
<para>
A linguagem <application>PL/pgSQL</application> é estruturada em blocos.
O texto completo da definição da função deve ser um
<firstterm>bloco</firstterm>. Um bloco é definido como:
<synopsis>
<optional> <<<replaceable>rótulo</replaceable>>> </optional>
<optional> DECLARE
<replaceable>declarações</replaceable> </optional>
BEGIN
<replaceable>instruções</replaceable>
END;
</synopsis>
</para>
<para>
Todas as declarações e instruções dentro do bloco devem ser terminadas por
ponto-e-vírgula.
Um bloco contido dentro de outro bloco deve conter um ponto-e-vírgula após
o <literal>END</literal>, conforme mostrado acima;
entretanto, o <literal>END</literal> final que conclui o corpo da função
não requer o ponto-e-vírgula.
</para>
<para>
Todas as palavras chave e identificadores podem ser escritos misturando
letras maiúsculas e minúsculas. As letras dos identificadores são
convertidas implicitamente em minúsculas, a menos que estejam entre aspas.
</para>
<para>
Existem dois tipos de comentários no <application>PL/pgSQL</application>.
O hífen duplo (<literal>--</literal>) começa um comentário que se estende
até o final da linha. O <literal>/*</literal> começa um bloco de comentário
que se estende até a próxima ocorrência de <literal>*/</literal>.
Os blocos de comentário não podem ser aninhados, mas comentários de hífen
duplo podem estar contidos em blocos de comentário, e os hífens duplos
escondem os delimitadores de bloco de comentário
<literal>/*</literal> e <literal>*/</literal>.
</para>
<para>
Qualquer instrução na seção de instruções do bloco pode ser um
<firstterm>sub-bloco</firstterm>. Os sub-blocos podem ser utilizados para
agrupamento lógico, ou para limitar o escopo de variáveis a um pequeno
grupo de instruções.
</para>
<para>
As variáveis declaradas na seção de declaração que precede um bloco
são inicializadas com seu valor padrão toda vez que o bloco é executado,
e não somente uma vez a cada chamada da função. Por exemplo:
<programlisting>
<userinput>
CREATE FUNCTION func_escopo() RETURNS integer AS $$
DECLARE
quantidade integer := 30;
BEGIN
RAISE NOTICE 'Aqui a quantidade é %', quantidade; -- A quantidade aqui é 30
quantidade := 50;
--
-- Criar um sub-bloco
--
DECLARE
quantidade integer := 80;
BEGIN
RAISE NOTICE 'Aqui a quantidade é %', quantidade; -- A quantidade aqui é 80
END;
RAISE NOTICE 'Aqui a quantidade é %', quantidade; -- A quantidade aqui é 50
RETURN quantidade;
END;
$$ LANGUAGE plpgsql;
</userinput>
<prompt>=> </prompt><userinput>SELECT func_escopo();</userinput>
<computeroutput>
NOTA: Aqui a quantidade é 30
NOTA: Aqui a quantidade é 80
NOTA: Aqui a quantidade é 50
func_escopo
-------------
50
(1 linha)
</computeroutput>
</programlisting>
</para>
<para>
É importante não confundir a utilização de
<command>BEGIN</command>/<command>END</command> para o agrupamento de
instruções na linguagem <application>PL/pgSQL</application>,
com os comandos de banco de dados para controle de transação.
O <command>BEGIN</command>/<command>END</command> da linguagem
<application>PL/pgSQL</application> é apenas para agrupamento;
não começam nem terminam transações.
Os procedimentos de funções e de gatilhos são sempre executados dentro da
transação estabelecida pelo comando externo — não podem iniciar ou
efetivar transações, porque não haveria contexto para estas serem
executadas.
Entretanto, um bloco contendo a cláusula <command>EXCEPTION</> forma,
efetivamente, uma subtransação que pode ser desfeita sem afetar a
transação externa. Para obter mais detalhes deve ser consultada a
<xref linkend="plpgsql-error-trapping">.
</para>
</sect1>
<sect1 id="plpgsql-declarations">
<title>Declarações</title>
<para>
Todas as variáveis utilizadas em um bloco devem ser declaradas na seção de
declarações do bloco (A única exceção é a variável de laço do
<command>FOR</command> interagindo sobre um intervalo de valores inteiros,
que é automaticamente declarada como sendo do tipo inteiro).
</para>
<para>
As variáveis da linguagem <application>PL/pgSQL</application> podem possuir
qualquer tipo de dado da linguagem SQL, como
<type>integer</type>, <type>varchar</type> e <type>char</type>.
</para>
<para>
Abaixo seguem alguns exemplos de declaração de variáveis:
<programlisting>
id_usuario integer;
quantidade numeric(5);
url varchar;
minha_linha nome_da_tabela%ROWTYPE;
meu_campo nome_da_tabela.nome_da_coluna%TYPE;
uma_linha RECORD;
</programlisting>
</para>
<para>
A sintaxe geral para declaração de variáveis é:
<synopsis>
<replaceable>nome</replaceable> <optional> CONSTANT </optional> <replaceable>tipo</replaceable> <optional> NOT NULL </optional> <optional> { DEFAULT | := } <replaceable>expressão</replaceable> </optional>;
</synopsis>
A cláusula <literal>DEFAULT</literal>, se for fornecida, especifica o
valor inicial atribuído à variável quando o processamento entra no bloco.
Se a cláusula <literal>DEFAULT</literal> não for fornecida, então a
variável é inicializada com o valor nulo do <acronym>SQL</acronym>.
A opção <literal>CONSTANT</literal> impede que seja atribuído valor a
variável e, portanto, seu valor permanece constante pela duração do bloco.
Se for especificado <literal>NOT NULL</literal>, uma atribuição de valor
nulo resulta em um erro em tempo de execução.
Todas as variáveis declaradas como <literal>NOT NULL</literal>
devem ter um valor padrão não nulo especificado.
</para>
<para>
O valor padrão é avaliado toda vez que a execução entra no bloco.
Portanto, por exemplo, atribuir <literal>now()</literal> a uma variável
do tipo <type>timestamp</type> faz com que a variável possua a data e
hora da chamada corrente à função, e não de quando a função foi
pré-compilada.
</para>
<para>
Exemplos:
<programlisting>
quantidade integer DEFAULT 32;
url varchar := ''http://meu-site.com'';
id_usuario CONSTANT integer := 10;
</programlisting>
</para>
<sect2 id="plpgsql-declaration-aliases">
<title>Aliases para parâmetros de função</title>
<para>
Os parâmetros passados para as funções recebem como nome os
identificadores <literal>$1</literal>, <literal>$2</literal>, etc.
Opcionalmente, para melhorar a legibilidade do código, podem ser
declarados aliases para os nomes dos parâmetros
<literal>$<replaceable>n</replaceable></literal>.
Para fazer referência ao valor do parâmetro, pode ser utilizado tanto o
aliás quanto o identificador numérico.
</para>
<para>
Existem duas maneiras de criar um aliás. A forma preferida é fornecer
nome ao parâmetro no comando <command>CREATE FUNCTION</command> como,
por exemplo:
<programlisting>
CREATE FUNCTION taxa_de_venda(subtotal real) RETURNS real AS $$
BEGIN
RETURN subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;
</programlisting>
A outra maneira, que era a única disponível antes da versão 8.0 do
<productname>PostgreSQL</productname>, é declarar explicitamente um aliás
utilizando a sintaxe de declaração
<synopsis>
<replaceable>nome</replaceable> ALIAS FOR $<replaceable>n</replaceable>;
</synopsis>
O exemplo acima escrito utilizando este estilo fica da seguinte maneira:
<programlisting>
CREATE FUNCTION taxa_de_venda(real) RETURNS real AS $$
DECLARE
subtotal ALIAS FOR $1;
BEGIN
RETURN subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;
</programlisting>
Alguns outros exemplos:
<programlisting>
CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$
DECLARE
v_string ALIAS FOR $1;
index ALIAS FOR $2;
BEGIN
-- algum processamento neste ponto
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION concatenar_campos_selecionados(in_t nome_da_tabela) RETURNS text AS $$
BEGIN
RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
$$ LANGUAGE plpgsql;
</programlisting>
</para>
<para>
Quando o tipo retornado por uma função <application>PL/pgSQL</application>
é declarado como sendo de um tipo polimórfico (<type>anyelement</type> ou
<type>anyarray</type>), é criado o parâmetro especial <literal>$0</>.
Seu tipo de dado é o tipo de dado real a ser retornado pela função,
conforme deduzido a partir dos tipos da entrada corrente (consulte a
<xref linkend="extend-types-polymorphic">).
Isto permite à função descobrir o verdadeiro tipo de dado retornado para
a entrada corrente conforme mostrado na
<xref linkend="plpgsql-declaration-type">.
O parâmetro <literal>$0</literal> é inicializado como nulo e pode ser
modificado pela função, portanto pode ser utilizado para armazenar o
valor a ser retornado se for desejado, embora não seja requerido.
Também pode ser criado um aliás para o parâmetro <literal>$0</literal>.
Por exemplo, esta função funciona com qualquer tipo de dado que possua o
operador <literal>+</literal>:
<programlisting>
<userinput>
CREATE FUNCTION somar_tres_valores(v1 anyelement, v2 anyelement, v3 anyelement)
RETURNS anyelement AS $$
DECLARE
resultado ALIAS FOR $0;
BEGIN
resultado := v1 + v2 + v3;
RETURN resultado;
END;
$$ LANGUAGE plpgsql;
SELECT somar_tres_valores(10,20,30);
</userinput>
<computeroutput>
somar_tres_valores
--------------------
60
(1 linha)
</computeroutput>
<userinput>SELECT somar_tres_valores(1.1,2.2,3.3);</userinput>
<computeroutput>
somar_tres_valores
--------------------
6.6
(1 linha)
</computeroutput>
</programlisting>
</para>
</sect2>
<sect2 id="plpgsql-declaration-type">
<title>Cópia de tipo</title>
<synopsis>
<replaceable>variável</replaceable>%TYPE
</synopsis>
<para>
A expressão <literal>%TYPE</literal> fornece o tipo de dado da variável ou
da coluna da tabela. Pode ser utilizada para declarar variáveis que
armazenam valores do banco de dados. Por exemplo, supondo que exista uma
coluna chamada <literal>id_usuario</literal> na tabela
<literal>usuarios</literal>, para declarar uma variável com o mesmo tipo de
dado de <literal>usuarios.id_usuario</literal> deve ser escrito:
<programlisting>
id_usuario usuarios.id_usuario%TYPE;
</programlisting>
</para>
<para>
Utilizando <literal>%TYPE</literal> não é necessário conhecer o tipo
de dado da estrutura sendo referenciada e, ainda mais importante, se o tipo
de dado do item referenciado mudar no futuro (por exemplo: o tipo de dado
de <literal>id_usuario</literal> for mudado de <type>integer</type> para
<type>real</type>), não será necessário mudar a definição na função.
</para>
<para>
A expressão <literal>%TYPE</literal> é particularmente útil em funções
polimórficas, uma vez que os tipos de dado das variáveis internas
podem mudar de uma chamada para outra. Pode-se criar variáveis apropriadas
aplicando <literal>%TYPE</literal> aos argumentos da função ou resultado.
</para>
</sect2>
<sect2 id="plpgsql-declaration-rowtypes">
<title>Tipos linha</title>
<synopsis>
<replaceable>nome</replaceable> <replaceable>nome_da_tabela</replaceable><literal>%ROWTYPE</literal>;
<replaceable>nome</replaceable> <replaceable>nome_do_tipo_composto</replaceable>;
</synopsis>
<para>
Uma variável de tipo composto é chamada de variável <firstterm>linha</>
(ou variável <firstterm>tipo-linha</firstterm>). Este tipo de variável
pode armazenar toda uma linha de resultado de um comando <command>SELECT</>
ou <command>FOR</>, desde que o conjunto de colunas do comando corresponda
ao tipo declarado para a variável.
Os campos individuais do valor linha são acessados utilizando a notação
usual de ponto como, por exemplo, <literal>variavel_linha.campo</literal>.
</para>
<para>
Uma variável-linha pode ser declarada como tendo o mesmo tipo de dado das
linhas de uma tabela ou de uma visão existente, utilizando a notação
<replaceable>nome_da_tabela</replaceable><literal>%ROWTYPE</literal>;
ou pode ser declarada especificando o nome de um tipo composto
(Uma vez que todas as tabelas possuem um tipo composto associado, que possui
o mesmo nome da tabela, na verdade não faz diferença para o
<productname>PostgreSQL</productname> se <literal>%ROWTYPE</literal>
é escrito ou não, mas a forma contendo <literal>%ROWTYPE</literal> é mais
portável).
</para>
<para>
Os parâmetros das funções podem ser de tipo composto (linhas completas da
tabela). Neste caso, o identificador correspondente
<literal>$<replaceable>n</replaceable></literal> será uma variável linha,
e os campos poderão ser selecionados a partir deste identificador
como, por exemplo, <literal>$1.id_usuario</literal>.
</para>
<para>
Somente podem ser acessadas na variável tipo-linha as colunas definidas pelo
usuário presentes na linha da tabela, a coluna OID e as outras colunas do
sistema não podem ser acessadas por esta variável (porque a linha pode ser
de uma visão). Os campos do tipo-linha herdam o tamanho do campo da tabela,
ou a precisão no caso de tipos de dado como
<type>char(<replaceable>n</replaceable>)</type>.
</para>
<para>
Abaixo está mostrado um exemplo de utilização de tipo composto:
<programlisting>
CREATE FUNCTION mesclar_campos(t_linha nome_da_tabela) RETURNS text AS $$
DECLARE
t2_linha nome_tabela2%ROWTYPE;
BEGIN
SELECT * INTO t2_linha FROM nome_tabela2 WHERE ... ;
RETURN t_linha.f1 || t2_linha.f3 || t_linha.f5 || t2_linha.f7;
END;
$$ LANGUAGE plpgsql;
SELECT mesclar_campos(t.*) FROM nome_da_tabela t WHERE ... ;
</programlisting>
</para>
</sect2>
<sect2 id="plpgsql-declaration-records">
<title>Tipos registro</title>
<synopsis>
<replaceable>nome</replaceable> RECORD;
</synopsis>
<para>
As variáveis registro são semelhantes às variáveis tipo-linha, mas não
possuem uma estrutura pré-definida. Assumem a estrutura da linha para a qual
são atribuídas pelo comando <command>SELECT</command> ou <command>FOR</>.
A subestrutura da variável registro pode mudar toda vez que é usada em uma
atribuição. Como conseqüência, antes de ser utilizada em uma atribuição a
variável registro não possui subestrutura, e qualquer tentativa de acessar
um de seus campos produz um erro em tempo de execução.
</para>
<para>
Deve ser observado que <literal>RECORD</literal> não é um tipo de dado real,
mas somente uma indicação. Deve-se ter em mente, também, que declarar uma
função do <application>PL/pgSQL</application> como retornando o tipo
<type>record</type> não é exatamente o mesmo conceito de variável registro,
embora a função possa utilizar uma variável registro para armazenar seu
resultado. Nos dois casos a verdadeira estrutura da linha é desconhecida
quando a função é escrita, mas na função que retorna o tipo
<type>record</type> a estrutura verdadeira é determinada quando o comando
que faz a chamada é analisado, enquanto uma variável registro pode mudar a
sua estrutura de linha em tempo de execução.
</para>
</sect2>
<sect2 id="plpgsql-declaration-renaming-vars">
<title>RENAME</title>
<synopsis>
RENAME <replaceable>nome_antigo</replaceable> TO <replaceable>novo_nome</replaceable>;
</synopsis>
<para>
O nome de uma variável, registro ou linha pode ser mudado através da
instrução <literal>RENAME</literal>. A utilidade principal é quando
<literal>NEW</literal> ou <literal>OLD</literal> devem ser referenciados por
outro nome dentro da função de gatilho.
Consulte também <literal>ALIAS</literal>.
</para>
<para>
Exemplos:
<programlisting>
RENAME id TO id_usuario;
RENAME esta_variavel TO aquela_variavel;
</programlisting>
</para>
<note>
<para>
<literal>RENAME</literal> parece estar com problemas desde o
<productname>PostgreSQL</productname> 7.3. A correção possui baixa
prioridade, porque o <literal>ALIAS</literal> cobre a maior parte dos
usos práticos do <literal>RENAME</literal>.
</para>
</note>
</sect2>
</sect1>
<sect1 id="plpgsql-expressions">
<title>Expressões</title>
<para>
Todas as expressões utilizadas nas instruções do
<application>PL/pgSQL</application> são processadas utilizando o executor
de <acronym>SQL</acronym> regular do servidor. Na verdade, um comando como
<synopsis>
SELECT <replaceable>expressão</replaceable>
</synopsis>
é executado utilizando o gerenciador da Interface de Programação do
Servidor (<acronym>SPI</acronym>).
Antes da avaliação, as ocorrências de identificadores variáveis do
<application>PL/pgSQL</application> são substituídas por parâmetros, e os
valores verdadeiros das variáveis são passados para o executor na
matriz de parâmetros.
Isto permite que o plano de comando para o <command>SELECT</command> seja
preparado uma única vez, e depois reutilizado nas avaliações seguintes.
</para>
<para>
A avaliação feita pelo analisador principal do
<productname>PostgreSQL</productname> produz alguns efeitos colaterais na
interpretação de valores constantes. Visto em detalhes existe diferença
entre o que estas duas funções fazem:
<programlisting>
CREATE FUNCTION logfunc1(logtxt text) RETURNS timestamp AS $$
BEGIN
INSERT INTO logtable VALUES (logtxt, 'now');
RETURN 'now';
END;
$$ LANGUAGE plpgsql;
</programlisting>
e
<programlisting>
CREATE FUNCTION logfunc2(logtxt text) RETURNS timestamp AS $$
DECLARE
curtime timestamp;
BEGIN
curtime := 'now';
INSERT INTO logtable VALUES (logtxt, curtime);
RETURN curtime;
END;
$$ LANGUAGE plpgsql;
</programlisting>
</para>
<para>
No caso da função <function>logfunc1</function>, o analisador principal do
<productname>PostgreSQL</productname> sabe, ao preparar o plano
para o comando <command>INSERT</command>, que a cadeia de caracteres
<literal>'now'</literal> deve ser interpretada como <type>timestamp</type>,
porque a coluna de destino na tabela <classname>logtable</classname>
é deste tipo, e por isso cria uma constante a partir de
<literal>'now'</literal> contendo a data e hora da análise. Depois, esta
constante é utilizada em todas as chamadas à função
<function>logfunc1</function> durante toda a sessão. É desnecessário dizer
que não é este o comportamento o desejado pelo programador.
</para>
<para>
No caso da função <function>logfunc2</function>, o analisador principal do
<productname>PostgreSQL</productname> não sabe o tipo que
<literal>'now'</literal> deve se tornar e, portanto, retorna um valor de
dado do tipo <type>text</type> contendo a cadeia de caracteres
<literal>now</literal>. Durante as atribuições seguintes à
variável local <varname>curtime</varname>, o interpretador do
<application>PL/pgSQL</application> irá converter a cadeia de caracteres
para o tipo <type>timestamp</type>, chamando as funções
<function>text_out</function> e <function>timestamp_in</function>
para fazer a conversão. Portanto, a data e hora computada é atualizada
a cada execução, como esperado pelo programador.
</para>
<para>
A natureza mutável das variáveis registro também apresenta um problema
semelhante. Quando campos de uma variável registro são utilizados em
expressões ou instruções, os tipos de dado dos campos não devem mudar
entre chamadas à mesma expressão, uma vez que a expressão é planejada
utilizando o tipo de dado presente quando a expressão é encontrada pela
primeira vez. Deve-se ter isto em mente ao escrever procedimentos de
gatilhos que tratam eventos para mais de uma tabela; quando for necessário,
pode ser utilizado <command>EXECUTE</command> para evitar este problema.
</para>
</sect1>
<sect1 id="plpgsql-statements">
<title>Instruções básicas</title>
<para>
Esta seção e as seguintes descrevem todos os tipos de instruções
compreendidas explicitamente pelo <application>PL/pgSQL</application>.
Tudo que não é reconhecido como um destes tipos de instrução é assumido
como sendo um comando SQL, e enviado para ser executado pela máquina de
banco de dados principal (após a substituição das variáveis do
<application>PL/pgSQL</application> na instrução).
Desta maneira, por exemplo, os comandos SQL <command>INSERT</command>,
<command>UPDATE</command> e <command>DELETE</command> podem ser considerados
como sendo instruções da linguagem <application>PL/pgSQL</application>, mas
não são listados aqui.
</para>