-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathecpg.sgml
More file actions
2572 lines (2234 loc) · 80.8 KB
/
ecpg.sgml
File metadata and controls
2572 lines (2234 loc) · 80.8 KB
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/ecpg.sgml,v 1.62 2005/01/08 22:13:25 tgl Exp $
-->
<chapter id="ecpg">
<title>ECPG - SQL incorporado à linguagem C</title>
<indexterm zone="ecpg"><primary>SQL incorporado</primary><secondary>linguagem C</secondary></indexterm>
<indexterm zone="ecpg"><primary>C</primary></indexterm>
<indexterm zone="ecpg"><primary>ECPG</primary></indexterm>
<para>
Este capítulo descreve o pacote de <acronym>SQL</acronym> incorporado para o
<productname>PostgreSQL</productname>.
Foi escrito por Linus Tolke (<email>linus@epact.se</email>) e
Michael Meskes (<email>meskes@postgresql.org</email>).
Originalmente escrito para trabalhar com a linguagem <acronym>C</acronym>,
também trabalha com a linguagem <acronym>C++</acronym>, mas ainda não
reconhece todas as construções de <acronym>C++</acronym>.
</para>
<para>
Esta documentação é bastante incompleta, mas uma vez que a interface é
padronizada, podem ser encontradas informações adicionais em várias fontes
sobre <acronym>SQL</acronym>.
</para>
<sect1 id="ecpg-concept">
<title>O conceito</title>
<para>
Um programa com <acronym>SQL</acronym> incorporado consiste de código escrito
em uma linguagem de programação comum, neste caso a linguagem <acronym>C</>,
misturado com comandos <acronym>SQL</acronym> em seções com marcas especiais.
Para construir o programa, primeiro o código fonte é passado através de um
pré-processador de <acronym>SQL</acronym> incorporado, que converte este
código em um programa <acronym>C</acronym> comum. Após isto ser feito, o
código pode ser processado pelo compilador <acronym>C</acronym>.
</para>
<para>
O <acronym>SQL</acronym> incorporado possui vantagens sobre outros métodos
que tratam comandos <acronym>SQL</acronym> a partir do código <acronym>C</>:
Em primeiro lugar, toma conta da entediante passagem de informação de e para
as variáveis do programa escrito em <acronym>C</acronym>;
Em segundo lugar, o código <acronym>SQL</acronym> incorporado ao programa é
verificado quanto à correção sintática em tempo de construção;
Em terceiro lugar, o <acronym>SQL</acronym> incorporado à linguagem
<acronym>C</acronym> é especificado pelo padrão <acronym>SQL</acronym>, e
suportado por muitos outros sistemas gerenciadores de banco de dados
<acronym>SQL</acronym>.
</para>
<para>
A implementação do <productname>PostgreSQL</> foi projetada para corresponder
ao padrão tanto quanto o possível. Geralmente é possível portar para o
<productname>PostgreSQL</>, com relativa facilidade, programas com
<acronym>SQL</acronym> incorporado escritos para outros gerenciadores de
banco de dados <acronym>SQL</acronym>.
</para>
<para>
Como já foi dito, os programas escritos para a interface de <acronym>SQL</>
incorporado são programas <acronym>C</acronym> normais, com código especial
inserido para realizar ações relacionadas com o banco de dados. Este código
especial sempre possui a forma:
<programlisting>
EXEC SQL ...;
</programlisting>
Sintaticamente estas declarações tomam o lugar da declaração <acronym>C</>.
Dependendo da declaração em particular, pode aparecer no nível global ou
dentro de uma função.
As declarações <acronym>SQL</acronym> incorporadas seguem as regras de
tratamento de letras maiúsculas e minúsculas do código <acronym>SQL</>
normal, e não as regras da linguagem <acronym>C</acronym>.
</para>
<para>
As seções que se seguem explicam todas as declarações <acronym>SQL</acronym>
incorporadas.
</para>
</sect1>
<sect1 id="ecpg-connect">
<title>Conexão com o servidor de banco de dados</title>
<para>
A conexão com o servidor de banco de dados é feita utilizando a seguinte
declaração:
<programlisting>
EXEC SQL CONNECT TO <replaceable>destino</replaceable> <optional>AS <replaceable>nome_da_conexão</replaceable></optional> <optional>USER <replaceable>nome_do_usuário</replaceable></optional>;
</programlisting>
O <replaceable>destino</replaceable> pode ser especificado das seguintes
formas:
<itemizedlist>
<listitem>
<simpara>
<literal><replaceable>nome_do_banco_de_dados</replaceable><optional>@<replaceable>nome_do_hospedeiro</replaceable></optional><optional>:<replaceable>porta</replaceable></optional></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>tcp:postgresql://<replaceable>nome_do_hospedeiro</replaceable><optional>:<replaceable>porta</replaceable></optional><optional>/<replaceable>nome_do_banco_de_dados</replaceable></optional><optional>?<replaceable>opções</replaceable></optional></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>unix:postgresql://<replaceable>nome_do_hospedeiro</replaceable><optional>:<replaceable>porta</replaceable></optional><optional>/<replaceable>nome_do_banco_de_dados</replaceable></optional><optional>?<replaceable>opções</replaceable></optional></literal>
</simpara>
</listitem>
<listitem>
<simpara>
literal cadeia de caracteres <acronym>SQL</acronym> contendo uma das
formas acima
</simpara>
</listitem>
<listitem>
<simpara>
referência a uma variável do tipo caractere contendo uma das formas acima
(veja os exemplos)
</simpara>
</listitem>
<listitem>
<simpara>
<literal>DEFAULT</literal>
</simpara>
</listitem>
</itemizedlist>
Se o destino da conexão for especificado literalmente (ou seja, não for
especificado através de referência a uma variável), e o valor não estiver
entre aspas, então são aplicadas as regras normais do <acronym>SQL</acronym>
para tratamento de letras maiúsculas e minúsculas.
Neste caso, os parâmetros podem ser colocados individualmente entre aspas
conforme seja necessário.
Na prática, provavelmente há menos chance de errar quando se usa literais
cadeia de caracteres (entre apóstrofos), ou referência a uma variável.
O destino de conexão <literal>DEFAULT</literal> inicia uma conexão com o
banco de dados padrão sob o nome de usuário padrão.
Neste caso, não é necessário especificar o nome do usuário ou da
conexão em separado.
</para>
<para>
Também existem maneiras diferentes de especificar o nome do usuário:
<itemizedlist>
<listitem>
<simpara>
<literal><replaceable>nome_do_usuário</replaceable></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal><replaceable>nome_do_usuário</replaceable>/<replaceable>senha</replaceable></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal><replaceable>nome_do_usuário</replaceable> IDENTIFIED BY <replaceable>senha</replaceable></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal><replaceable>nome_do_usuário</replaceable> USING <replaceable>senha</replaceable></literal>
</simpara>
</listitem>
</itemizedlist>
Como acima, os parâmetros <replaceable>nome_do_usuário</replaceable> e
<replaceable>senha</replaceable> podem ser um identificador <acronym>SQL</>,
um literal cadeia de caracteres <acronym>SQL</acronym>, ou referência a
uma variável do tipo caractere.
</para>
<para>
O <replaceable>nome_da_conexão</replaceable> é utilizado para tratar várias
conexões em um mesmo programa. Pode ser omitido se o programa utilizar apenas
uma conexão. A conexão aberta mais recentemente se torna a conexão corrente,
que é utilizada por padrão quando uma declaração <acronym>SQL</acronym> é
executada (veja mais adiante neste capítulo).
</para>
<para>
Abaixo estão mostrados alguns exemplos de declaração <command>CONNECT</>:
<programlisting>
EXEC SQL CONNECT TO meubanco@sql.meudominio.com;
EXEC SQL CONNECT TO 'unix:postgresql://sql.meudominio.com/meubanco' AS minhaconexao USER joao;
EXEC SQL BEGIN DECLARE SECTION;
const char *destino = "meubanco@sql.meudominio.com";
const char *usuario = "joao";
EXEC SQL END DECLARE SECTION;
...
EXEC SQL CONNECT TO :destino USER :usuario;
</programlisting>
A última forma faz uso da variante que foi referida acima como referência a
uma variável do tipo caractere. Na <xref linkend="ecpg-variables"> é mostrado
como as variáveis da linguagem <acronym>C</> podem ser utilizadas nas
declarações <acronym>SQL</acronym> quando são prefixadas por dois-pontos
(<literal>:</literal>).
</para>
<para>
Como o formato do destino da conexão não é especificado pelo padrão
<acronym>SQL</acronym>, se for desejado desenvolver aplicativos portáveis
deve-se dar preferência à utilização de algo baseado no último exemplo acima,
para encapsular a cadeia de caracteres de destino da conexão fora da
declaração.
</para>
</sect1>
<sect1 id="ecpg-disconnect">
<title>Fechamento de conexão</title>
<para>
Para fechar a conexão deve ser utilizada a seguinte declaração:
<programlisting>
EXEC SQL DISCONNECT <optional><replaceable>conexão</replaceable></optional>;
</programlisting>
Onde <replaceable>conexão</replaceable> pode ser especificada das seguintes
maneiras:
<itemizedlist>
<listitem>
<simpara>
<literal><replaceable>nome_da_conexão</replaceable></literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>DEFAULT</literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>CURRENT</literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>ALL</literal>
</simpara>
</listitem>
</itemizedlist>
Se não for especificado o nome da conexão, a conexão corrente é fechada.
</para>
<para>
É bom estilo o aplicativo sempre fechar todas as conexões abertas.
</para>
</sect1>
<sect1 id="ecpg-commands">
<title>Execução de comandos SQL</title>
<para>
Pode ser executado qualquer comando <acronym>SQL</acronym> de dentro de um
aplicativo com <acronym>SQL</acronym> incorporado. Abaixo estão mostrados
alguns exemplos de como se faz isto.
</para>
<para>
Criação de tabela:
<programlisting>
EXEC SQL CREATE TABLE foo (numero integer, ascii char(16));
EXEC SQL CREATE UNIQUE INDEX num1 ON foo(numero);
EXEC SQL COMMIT;
</programlisting>
</para>
<para>
Inserção de linhas:
<programlisting>
EXEC SQL INSERT INTO foo (numero, ascii) VALUES (9999, 'doodad');
EXEC SQL COMMIT;
</programlisting>
</para>
<para>
Exclusão de linhas:
<programlisting>
EXEC SQL DELETE FROM foo WHERE numero = 9999;
EXEC SQL COMMIT;
</programlisting>
</para>
<para>
Seleção de uma única linha:
<programlisting>
EXEC SQL SELECT numero INTO :numero FROM foo WHERE ascii = 'doodad';
</programlisting>
</para>
<para>
Seleção usando cursores:
<programlisting>
EXEC SQL DECLARE foo_bar CURSOR FOR
SELECT numero, ascii FROM foo
ORDER BY ascii;
EXEC SQL OPEN foo_bar;
EXEC SQL FETCH foo_bar INTO :numero, :ascii;
...
EXEC SQL CLOSE foo_bar;
EXEC SQL COMMIT;
</programlisting>
</para>
<para>
Atualizações:
<programlisting>
EXEC SQL UPDATE foo
SET ascii = 'foobar'
WHERE numero = 9999;
EXEC SQL COMMIT;
</programlisting>
</para>
<para>
Os termos (<literal>tokens</literal>) com a forma
<literal>:<replaceable>alguma_coisa</replaceable></literal>
são <firstterm>variáveis hospedeiras</firstterm>, ou seja, se referem a
variáveis do programa <acronym>C</acronym>, e são explicadas na
<xref linkend="ecpg-variables">.
</para>
<para>
No modo padrão, as declarações são efetivadas apenas quando é executado
<command>EXEC SQL COMMIT</command>. A interface de <acronym>SQL</acronym>
incorporado também suporta a auto-efetivação das transações (semelhante ao
comportamento da biblioteca <application>libpq</>), através da opção de linha
de comando <option>-t</option> do <command>ecpg</command> (veja abaixo),
ou através da declaração <literal>EXEC SQL SET AUTOCOMMIT TO ON</literal>.
No modo de auto-efetivação todo comando é efetivado automaticamente, a menos
que esteja dentro de um bloco de transação explícito. Este modo pode ser
desabilitado explicitamente através da declaração
<literal>EXEC SQL SET AUTOCOMMIT TO OFF</literal>.
</para>
</sect1>
<sect1 id="ecpg-set-connection">
<title>Escolha da conexão</title>
<para>
As declarações <acronym>SQL</acronym> mostradas na seção anterior são
executadas na conexão corrente, ou seja, a conexão aberta mais recentemente.
Se o aplicativo precisar gerenciar várias conexões, então existem duas
maneiras de tratar este problema.
</para>
<para>
A primeira opção é escolher explicitamente a conexão para cada declaração
<acronym>SQL</acronym> como, por exemplo:
<programlisting>
EXEC SQL AT <replaceable>nome_da_conexão</replaceable> SELECT ...;
</programlisting>
Esta opção é particularmente apropriada quando o aplicativo necessita
utilizar várias conexões sem uma ordem definida.
</para>
<para>
Se o aplicativo utilizar vários fluxos de execução (<literal>threads</>),
estes não podem compartilhar simultaneamente uma conexão.
Deve ser controlado explicitamente o acesso às conexões (utilizando
mutexes), ou utilizada uma conexão para cada fluxo de execução.
Se cada fluxo de execução utilizar sua própria conexão, será necessário
usar a cláusula <literal>AT</literal> para especificar a conexão que o
fluxo de execução vai utilizar.
</para>
<para>
A segunda opção é executar uma declaração para alternar a conexão corrente.
A declaração é:
<programlisting>
EXEC SQL SET CONNECTION <replaceable>nome_da_conexão</replaceable>;
</programlisting>
Esta opção é particularmente apropriada quando são executadas muitas
declarações utilizando a mesma conexão, mas não considera os fluxos de
execução.
</para>
</sect1>
<sect1 id="ecpg-variables">
<title>Utilização de variáveis hospedeiras</title>
<para>
Na <xref linkend="ecpg-commands"> foi visto como executar declarações
<acronym>SQL</acronym> a partir de um programa com <acronym>SQL</acronym>
incorporado. Algumas destas declarações utilizam apenas valores fixos,
não possuindo uma maneira de inserir valores fornecidos pelo usuário na
declaração, nem os programas processam os valores retornados pelas
consultas. Este tipo de declaração, na verdade, não é útil em aplicativos
reais. Esta seção explica em detalhe como passar dados entre o programa
<acronym>C</acronym> e os comandos <acronym>SQL</acronym> incorporados,
utilizando um mecanismo simples chamado
<firstterm>variáveis hospedeiras</firstterm>.
</para>
<sect2>
<title>Visão geral</title>
<para>
A passagem de dados entre o programa <acronym>C</acronym> e as declarações
<acronym>SQL</acronym> é particularmente simples no <acronym>SQL</acronym>
incorporado. Em vez do programa colar os dados na declaração, que envolve
várias dificuldades, como colocar o valor entre apóstrofos de forma
apropriada, pode-se simplesmente escrever o nome da variável
<acronym>C</acronym>, prefixada por dois-pontos, na declaração
<acronym>SQL</acronym>. Por exemplo:
<programlisting>
EXEC SQL INSERT INTO alguma_tabela VALUES (:v1, 'foo', :v2);
</programlisting>
Esta declaração faz referência a duas variáveis <acronym>C</acronym>,
chamadas <varname>v1</varname> e <varname>v2</varname>, e também usa um
literal cadeia de caracteres <acronym>SQL</acronym> regular, para mostrar
que não fica restrito ao uso de um tipo de dado ou outro.
</para>
<para>
Esta forma de inserir variáveis <acronym>C</acronym> em declarações
<acronym>SQL</acronym> funciona em qualquer lugar onde é esperada uma
expressão de valor na declaração <acronym>SQL</acronym>. No ambiente
<acronym>SQL</acronym>, as variáveis <acronym>C</acronym> referenciadas
são chamadas de <firstterm>variáveis hospedeiras</firstterm>.
</para>
</sect2>
<sect2>
<title>Seções de declaração</title>
<para>
Para passar os dados do programa para o banco de dados, por exemplo como
parâmetros de uma consulta, ou para passar os dados do banco de dados
de volta para o programa <acronym>C</acronym>, as variáveis
<acronym>C</acronym> utilizadas para armazenar estes dados precisam ser
declaradas em seções marcadas de forma especial, para que o pré-processador
de <acronym>SQL</acronym> incorporado tenha conhecimento destas variáveis.
</para>
<para>
Estas seções começam por
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
</programlisting>
e terminam por
<programlisting>
EXEC SQL END DECLARE SECTION;
</programlisting>
Entre estas duas linhas devem haver declarações normais de variáveis
<acronym>C</acronym>, como:
<programlisting>
int x;
char foo[16], bar[16];
</programlisting>
Podem existir tantas seções de declaração no programas quantas forem
desejadas.
</para>
<para>
As declarações também são reproduzidas no arquivo de saída como variáveis
<acronym>C</acronym> normais, para que não seja necessário declará-las
novamente. As variáveis que não são utilizadas nos comandos
<acronym>SQL</acronym> podem ser declaradas normalmente fora destas seções
especiais.
</para>
<para>
A definição das estruturas e das uniões também devem ser colocadas dentro
da seção <literal>DECLARE</>, senão o pré-processador não pode tratar
estes tipos, uma vez que não conhece as definições.
</para>
<para>
O tipo especial <type>VARCHAR</type> é convertido em uma
<type>struct</> com nome para todas as variáveis. Uma declaração como
<programlisting>
VARCHAR var[180];
</programlisting>
é convertida em
<programlisting>
struct varchar_var { int len; char arr[180]; } var;
</programlisting>
Esta estrutura é adequada para servir de interface para os dados do tipo
<type>varchar</type> do <acronym>SQL</acronym>.
<footnote>
<para>
<productname>DB2</productname> —
declaração válida da variável hospedeira <varname>vstring</varname>:
<literal>struct VARCHAR { short len; char s[10] } vstring;</literal>
<ulink url="http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/rzajp/rzajpmst02.htm">
Declaring host variables in C and C++ applications that use SQL</ulink>
(N. do T.)
</para>
</footnote>
</para>
</sect2>
<sect2>
<title>Declarações SELECT INTO e FETCH INTO</title>
<para>
Agora já se sabe como passar dados gerados pelo programa para o comando
<acronym>SQL</acronym>, mas como fazer para trazer os resultados da
consulta? Para esta finalidade o <acronym>SQL</acronym> incorporado
disponibiliza duas variantes dos comandos usuais <command>SELECT</command>
e <command>FETCH</command>. Estes comandos possuem uma cláusula especial
<literal>INTO</literal>, que especifica em quais variáveis hospedeiras
os valores trazidos são armazenados.
</para>
<para>
Abaixo segue um exemplo:
<programlisting>
/*
* assumindo a existência desta tabela:
* CREATE TABLE test1 (a int, b varchar(50));
*/
EXEC SQL BEGIN DECLARE SECTION;
int v1;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL SELECT a, b INTO :v1, :v2 FROM test1;
</programlisting>
Portanto, a cláusula <literal>INTO</> aparece entre a lista de seleção
e a cláusula <literal>FROM</literal>. O número de elementos da lista de
seleção e da lista após a cláusula <literal>INTO</literal>, também chamada
de lista de destino, devem ser iguais.
</para>
<para>
Abaixo segue um exemplo mostrando o comando <command>FETCH</command>:
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
int v1;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL DECLARE foo CURSOR FOR SELECT a, b FROM test1;
...
do {
...
EXEC SQL FETCH NEXT FROM foo INTO :v1, :v2;
...
} while (...);
</programlisting>
Aqui a cláusula <literal>INTO</literal> aparece após todas as cláusulas
normais.
</para>
<para>
Este dois métodos só permitem trazer uma linha de cada vez. Se for
necessário processar conjunto de resultados contendo potencialmente mais
de uma linha, é necessário utilizar um cursor, conforme mostrado no segundo
exemplo.
</para>
</sect2>
<sect2>
<title>Indicadores</title>
<para>
Os exemplos acima não tratam valores nulos. Na verdade, os exemplos de
recuperação vão lançar um erro se trouxerem um valor nulo do banco de dados.
Para ser possível passar valores nulos para o banco de dados, ou trazer
valores nulos do banco de dados, é necessário anexar uma segunda variável
hospedeira na especificação de cada variável hospedeira que contém dado.
Esta segunda variável é chamada de <firstterm>indicador</firstterm>, e
contém um sinalizador para informar se o dado é nulo. Neste caso o valor da
variável hospedeira real é ignorado. Abaixo está mostrado um exemplo que
trata a recuperação de valores nulos de forma correta:
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
int v1, ind1, ind2;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL SELECT a, b INTO :v1 :ind1, :v2 :ind2 FROM test1;
</programlisting>
A variável indicadora (<varname>ind1</varname> ou <varname>ind2</varname>)
será igual a zero quando o valor da coluna não for nulo, ou será negativa
quando o valor da coluna for nulo. Deve ser observado que não há vírgula
separando a variável hospedeira da variável indicadora. Não há necessidade
de espaço entre a variável hospedeira e a variável indicadora.
</para>
<para>
O indicador possui outra função: se o valor do indicador for positivo,
significa que o valor não é nulo, mas que foi truncado ao ser armazenado na
variável hospedeira.
<footnote>
<para>
<productname>DB2</productname> —
se o valor da coluna de resultado for nulo, o <acronym>SQL</acronym>
coloca -1 na variável indicadora; se não for utilizada uma variável
indicadora, e a coluna de resultado tiver um valor nulo, retorna um
SQLCODE negativo. Se o valor da coluna de resultado causar um erro de
mapeamento, o <acronym>SQL</acronym> define a variável indicadora como -2.
A variável indicadora também pode ser utilizada para verificar se o valor
da cadeia de caracteres foi truncado. Quando há truncamento, a variável
indicadora contém um inteiro positivo que especifica o comprimento
original da cadeia de caracteres. (N. do T.)
</para>
</footnote>
<footnote>
<para>
<productname>DB2</productname> —
A variável indicadora vem imediatamente após a variável hospedeira.
(N. do T.)
</para>
</footnote>
</para>
</sect2>
</sect1>
<sect1 id="ecpg-dynamic">
<title>SQL dinâmico</title>
<para>
Em muitos casos, a declaração <acronym>SQL</acronym> a ser utilizada pelo
aplicativo já é conhecida na hora em que o aplicativo é escrito. Em alguns
casos, entretanto, as declarações <acronym>SQL</acronym> são formadas em
tempo de execução, ou fornecidas por uma fonte externa. Nestes casos, a
declaração <acronym>SQL</acronym> não pode ser incorporada diretamente ao
código fonte <acronym>C</acronym>, mas existe um mecanismo que permite
executar declarações <acronym>SQL</acronym> arbitrárias especificadas através
de variáveis do tipo cadeia de caractere.
</para>
<para>
A forma mais simples de executar uma declaração <acronym>SQL</acronym>
arbitrária é utilizando o comando <command>EXECUTE IMMEDIATE</command>.
Por exemplo:
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
const char *declaracao = "CREATE TABLE test1 (...);";
EXEC SQL END DECLARE SECTION;
EXEC SQL EXECUTE IMMEDIATE :declaracao;
</programlisting>
As declarações que trazem dados (por exemplo, <command>SELECT</command>),
não podem ser executadas desta forma.
</para>
<para>
Uma forma mais poderosa de executar declarações <acronym>SQL</acronym>
arbitrárias é preparar uma vez, e executar a declaração preparada tantas
vezes quanto se desejar. Também é possível preparar uma versão generalizada
da declaração, e executar versões específicas desta fazendo a substituição
de parâmetros. Ao preparar a declaração são colocados pontos de interrogação
nos locais a serem substituídos posteriormente por parâmetros. Por exemplo:
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
const char *declaracao = "INSERT INTO test1 VALUES(?, ?);";
EXEC SQL END DECLARE SECTION;
EXEC SQL PREPARE minha_declaracao FROM :declaracao;
...
EXEC SQL EXECUTE minha_declaracao USING 42, 'foobar';
</programlisting>
Quando a declaração utilizada retorna valores é adicionada a cláusula
<literal>INTO</literal>:
<programlisting>
EXEC SQL BEGIN DECLARE SECTION;
const char *declaracao = "SELECT a, b, c FROM test1 WHERE a > ?";
int v1, v2;
VARCHAR v3;
EXEC SQL END DECLARE SECTION;
EXEC SQL PREPARE minha_declaracao FROM :declaracao;
...
EXEC SQL EXECUTE minha_declaracao INTO v1, v2, v3 USING 37;
</programlisting>
O comando <command>EXECUTE</command> pode possuir uma cláusula
<literal>INTO</literal>, uma cláusula <literal>USING</literal>,
as duas, ou nenhuma delas.
</para>
<para>
Quando a declaração preparada não é mais necessária deve-se liberá-la:
<programlisting>
EXEC SQL DEALLOCATE PREPARE <replaceable>nome</replaceable>;
</programlisting>
</para>
</sect1>
<sect1 id="ecpg-descriptors">
<title>Utilização das áreas descritoras de SQL</title>
<para>
A área descritora de <acronym>SQL</acronym> é um método mais sofisticado
para processar os resultados das declarações <command>SELECT</command> e
<command>FETCH</command>. A área descritora de <acronym>SQL</acronym> agrupa
os dados de uma linha de dados junto com os itens de metadado, em uma
estrutura de dados. Os metadados são particularmente úteis ao executar
declarações <acronym>SQL</acronym> dinâmicas, quando a natureza das colunas
do resultado não podem ser conhecidas a priori.
</para>
<para>
Uma área descritora de <acronym>SQL</acronym> consiste em um cabeçalho, que
contém informações a respeito de todo o descritor, e uma ou mais áreas
descritoras de item, onde cada área basicamente descreve uma coluna da linha
de resultado.
</para>
<para>
É necessário alocar a área descritora de <acronym>SQL</acronym> para que
possa ser utilizada:
<programlisting>
EXEC SQL ALLOCATE DESCRIPTOR <replaceable>identificador</replaceable>;
</programlisting>
O identificador serve como o <quote>nome de variável</quote> da área
descritora. <remark>The scope of the allocated descriptor is WHAT?.</remark>
Quando não há mais necessidade do descritor, este deve ser liberado:
<programlisting>
EXEC SQL DEALLOCATE DESCRIPTOR <replaceable>identificador</replaceable>;
</programlisting>
</para>
<para>
Para usar a área descritora deve-se especificá-la como destino do
armazenamento na cláusula <literal>INTO</literal>, em vez de especificar as
variáveis hospedeiras:
<programlisting>
EXEC SQL FETCH NEXT FROM meu_cursor INTO DESCRIPTOR meu_descritor;
</programlisting>
</para>
<para>
Como fazer para extrair os dados da área descritora? Pode-se pensar na área
descritora como sendo uma estrutura com campos nomeados. Para extrair o valor
de um campo do cabeçalho e armazená-lo em uma variável hospedeira deve ser
utilizada a seguinte declaração:
<programlisting>
EXEC SQL GET DESCRIPTOR <replaceable>nome</replaceable> :<replaceable>variável_hospedeira</replaceable> = <replaceable>campo</replaceable>;
</programlisting>
Atualmente existe apenas um campo de cabeçalho definido, chamado
<replaceable>COUNT</replaceable>, que informa quantas áreas descritoras de
item existem (ou seja, quantas colunas o resultado contém). A variável
hospedeira precisa ser do tipo inteiro. Para extrair um campo da área
descritora de item deve ser utilizada a seguinte declaração:
<programlisting>
EXEC SQL GET DESCRIPTOR <replaceable>nome</replaceable> VALUE <replaceable>num</replaceable> :<replaceable>variável_hospedeira</replaceable> = <replaceable>campo</replaceable>;
</programlisting>
onde <replaceable>num</replaceable> pode ser um literal inteiro, ou uma
variável hospedeira contendo um inteiro. Os campos possíveis são:
<variablelist>
<varlistentry>
<term><literal>CARDINALITY</literal> (integer)</term>
<listitem>
<para>
número de linhas no conjunto de resultados
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DATA</literal></term>
<listitem>
<para>
item de dado verdadeiro (portanto, o tipo de dado deste campo depende da
consulta)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DATETIME_INTERVAL_CODE</literal> (integer)</term>
<listitem>
<para>
?
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DATETIME_INTERVAL_PRECISION</literal> (integer)</term>
<listitem>
<para>
não implementado
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>INDICATOR</literal> (integer)</term>
<listitem>
<para>
o indicador (indica um valor nulo ou o truncamento do valor)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>KEY_MEMBER</literal> (integer)</term>
<listitem>
<para>
não implementado
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>LENGTH</literal> (integer)</term>
<listitem>
<para>
comprimento do dado em caracteres
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NAME</literal> (string)</term>
<listitem>
<para>
nome da coluna
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NULLABLE</literal> (integer)</term>
<listitem>
<para>
não implementado
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>OCTET_LENGTH</literal> (integer)</term>
<listitem>
<para>
comprimento da representação do caractere do dado em bytes
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>PRECISION</literal> (integer)</term>
<listitem>
<para>
precisão (para o tipo <type>numeric</type>)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RETURNED_LENGTH</literal> (integer)</term>
<listitem>
<para>
comprimento do dado em caracteres
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RETURNED_OCTET_LENGTH</literal> (integer)</term>
<listitem>
<para>
comprimento da representação do caractere do dado em bytes
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SCALE</literal> (integer)</term>
<listitem>
<para>
escala (para o tipo <type>numeric</type>)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TYPE</literal> (integer)</term>
<listitem>
<para>
código numérico do tipo de dado da coluna
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
<sect1 id="ecpg-errors">
<title>Tratamento de erro</title>
<para>
Esta seção descreve como tratar condições excepcionais e advertências em
programas com <acronym>SQL</acronym> incorporado. Existem várias maneiras
não exclusivas para isto.
</para>
<sect2>
<title>Definição de chamada</title>
<para>
Um método simples para capturar os erros e advertências é definir uma ação
específica a ser executada sempre que uma determinada condição ocorrer.
Em geral:
<programlisting>
EXEC SQL WHENEVER <replaceable>condição</replaceable> <replaceable>ação</replaceable>;
</programlisting>
</para>
<para>
a <replaceable>condição</replaceable> pode ser uma das seguintes:
<variablelist>
<varlistentry>
<term><literal>SQLERROR</literal></term>
<listitem>
<para>
A ação especificada é chamada sempre que ocorre um erro durante a
execução da declaração <acronym>SQL</acronym>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SQLWARNING</literal></term>
<listitem>
<para>
A ação especificada é chamada sempre que ocorre uma advertência durante
a execução da declaração <acronym>SQL</acronym>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NOT FOUND</literal></term>
<listitem>
<para>
A ação especificada é chamada sempre que a declaração <acronym>SQL</>
traz ou afeta zero linhas (Esta condição não é um erro, mas pode-se
estar interessado em tratá-la de forma especial).
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
a <replaceable>ação</replaceable> pode ser uma das seguintes:
<variablelist>
<varlistentry>
<term><literal>CONTINUE</literal></term>
<listitem>
<para>
Significa efetivamente que a condição é ignorada. É o padrão.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>GOTO <replaceable>rótulo</replaceable></literal></term>
<term><literal>GO TO <replaceable>rótulo</replaceable></literal></term>
<listitem>
<para>
Desvia para o rótulo especificado (utilizando a declaração
<literal>goto</literal> da linguagem <acronym>C</acronym>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SQLPRINT</literal></term>
<listitem>
<para>
Envia uma mensagem para a saída de erro padrão. É útil em programas
simples ou durante a prototipação. Não é possível configurar os detalhes
da mensagem.