Escolar Documentos
Profissional Documentos
Cultura Documentos
INTRODUÇÃO
O método conhecido como Embedded SQL (ou SQL embutido) é definido pelo ANSI (American
National Standards Institute) e define um conjunto de padrões para que código SQL possa ser
usado a partir de programas feitos em outras linguagens de programação, que no nosso caso
será o C.
A implementação do PostgreSQL para este conceito é chamado de ECPG. Todo o código SQL
contido no programa em C é pré-processado antes por um pré-processador do PostgreSQL, que
irá fazer a tradução para código C comum, para então ser compilado por um compilador C.
Este método tem algumas vantagens com relação a outros métodos, comparando aqui com a
libpq, entre elas:
O gerenciamento de variáveis que irão receber valores retornados por queries é muito
mais fácil do que na libpq.
Toda sintaxe do SQL é verificada, o que permite que erros desse tipo sejam corrigidos
antes de o programa ser de fato compilado.
O embedded SQL é definido pelo padrão ANSI, e como o PostgreSQL segue o mais
próximo o possível estes padrões, é muito mais fácil portar estes programas para outros
bancos de dados.
E claro, nem tudo é vantagem. Entre as desvantagens deste método podemos citar:
Claro, nada é perfeito, e em todas as situações deve ser analisado qual a melhor solução a ser
usada.
1 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
No nosso caso, estamos usando um banco chamado 'TESTE'. Não entraremos em detalhes
sobre esses assuntos pois isto é material suficiente para um outro artigo.
Vamos criar o nosso ambiente de testes usando o psql, que é a ferramenta de linha de comando
do PostgreSQL. Caso não saiba usá-la, é bem simples, basta digitar o comando psql na linha de
comando e, após o login, digitar os comandos SQL finalizando com um ponto-e-vírgula (;).
Para o nosso ambiente de testes, iremos precisar apenas de uma tabela. Iremos criá-la com o
comando abaixo:
Digitando no psql, teremos o seguinte (a palavra 'TESTE' que aparece é o nome do nosso banco
de dados):
(note que o comando só é executado quando temos um ';'). Ao pressionar enter no final do
comando acima, teremos o seguinte resultado:
2 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
Começar a escrever código usando ECPG é relativamente fácil. Basta adicionar os comandos
SQL no meio do seu código C. Parece estranho? Mas não é. De fato, temos apenas que seguir
alguns padrões, que veremos no decorrer deste artigo.
A primeira regra é incluir o arquivo de cabeçalho que vai nos dar informações sobre os erros e
outras coisas. Como precisamos que este arquivo também seja processado pelo pré-processador
do PostgreSQL, não faz sentido incluir ele com a diretiva #include. Para incluir este arquivo,
usamos o comando:
A segunda regra é que todo comando que deve ser interpretado pelo pré-processador deve iniciar
com o comando exec sql, por exemplo:
3 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
nome do banco[@host][:porta]
tcp:postgresql://host[:porta][/nome_do_banco]
unix:postgresql://host[:porta][/nome_do_banco]
username
username/senha
username IDENTIFIED BY senha
username USING senha
Para o nosso artigo, iremos passar os parâmetros através de variáveis, que é o penúltimo modo
listado lá em cima. Vamos então, ao código fonte:
4 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
/* INCLUDE */
#include <stdio.h>
/* MAIN */
int main(int argc, char **argv)
{
EXEC SQL BEGIN DECLARE SECTION;
const char *nome_database = "teste@localhost";
const char *szUser = "teste";
EXEC SQL END DECLARE SECTION;
if(sqlca.sqlcode != 0) {
printf("Conexão com %s falhou. ", nome_database);
return 0;
} else {
printf("Connection ok com %s. ", nome_database);
}
return 0;
}
5 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
Este bloco serve para declarar variáveis que serão usadas para passar ou receber valores para o
banco de dados. Elas precisam ser declaradas nesta seção em especial para que o pré-
processador do PostgreSQL tenha conhecimento delas.
O comando:
realiza a conexão com o banco de dados. Para indicar ao pré-processador que queremos usar
variáveis, devemos usar o símbolo dois-pontos (:) seguido pelo nome da variável. Note que estas
variáveis devem ter sido declaradas na seção DECLARE SECTION.
struct {
char sqlcaid[8];
long sqlabc;
long sqlcode;
struct {
int sqlerrml;
char sqlerrmc[70];
} sqlerrm;
char sqlerrp[8];
long sqlerrd[6];
char sqlwarn[8];
char sqlstate[5];
} sqlca;
6 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
Esta estrutura permite uma verificação de erros e warnings (aviso, traduzido literalmente) mais
detalhada sobre os comandos executados. A variável sqlcode pode assumir os seguintes valores:
O programa acima simplesmente abre uma conexão com o banco de dados especificado e exibe
uma mensagem dizendo se a conexão foi efetuada com sucesso ou não. Como padrão eu
costumo salvar os arquivos com SQL embutido com a extensão pgc, mas qualquer outra
extensão pode ser usada.
COMPILANDO OS PROGRAMAS
7 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
A única diferença da compilação de um programa que tenha código SQL embutido para outros
programas escritos em C é que o pré-processador do PostgreSQL deve ser chamado antes do
gcc.
$ ecpg exemplo.pgc
Mais simples que isso, impossível. O ECPG vai gerar um arquivo de mesmo nome, porém com a
extensão ".c". Iremos compilar este arquivo com o gcc da seguinte forma:
A opção -o especifica o nome do arquivo executável que será gerado, no nosso caso, exemplo.
O parâmetro exemplo.c é o arquivo contendo o código-fonte, que foi gerado previamente pelo
ECPG.
A opção -lecpg diz ao compilador para usar a biblioteca do ECPG. Esta opção não pode ser
esquecida, do contrário, você vai ver muitos erros de compilação e pode perder horas até
conseguir se dar conta de que esqueceu esta opção.
Após este passo, temos um arquivo executável pronto para ser rodado.
Agora que já sabemos como abrir uma conexão, vamos começar a trabalhar com as nossas
tabelas.
O primeiro passo será inserir alguns dados na tabela. Como não há muito a ser dito, visto que
basicamente trata-se de comandos SQL normais, vamos ao código (iremos omitir o código que
realiza a conexão, uma vez que já o listamos lá em cima):
8 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
EXEC SQL INSERT INTO contatos (id_contato, nome) VALUES(:i, 'Nome ' || :i );
if(sqlca.sqlcode != 0) {
printf(" Erro executando a query. ");
printf("Descrição: %s ", sqlca.sqlerrm.sqlerrmc);
}
}
9 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
Com estes comandos, iniciamos e terminamos uma transação, respectivamente, o que torna o
nosso INSERT muito mais rápido, pois o PostgreSQL só vai gravar os dados fisicamente na
tabela quando ele encontrar o comando COMMIT WORK. Estes comandos sempre devem ser
usados, a não ser que se use o comando EXEC SQL SET AUTOCOMMIT TO ON, o que faz com
que a cada comando SQL executado o PostgreSQL execute o commit.
EXEC SQL INSERT INTO contatos (id_contato, nome) VALUES(:i, 'Nome ' || :i );
Este é o nosso INSERT, que vai gravar os dados na tabela contatos. O que deve ser observado
aqui são os valores passados dentro de VALUES: :i - esta é a nossa variável declarada na seção
de declaração. Esta é uma variável do C que está disponível para o PostgreSQL.
'Nome ' || :i - isso vai inserir um nome do tipo "Nome 1", "Nome 2", etc, de acordo com a nossa
variável "i". Os dois "pipes" ( || ) é o caracter para concatenar strings no PostgreSQL.
Por fim, sqlca.sqlerrm.sqlerrmc irá mostrar a mensagem de erro, caso algum erro aconteça.
Executar comandos SELECT usando o ECPG tem uma pequena diferença com relação a outros
comandos. Ao executar um SELECT, precisamos de uma maneira de armazenar o que foi
retornado pelo SELECT em algum lugar. Uma variável para ser mais exato.
Vamos executar um SELECT que retorna apenas uma linha (e temos certeza de que ele
vai retornar apenas uma linha);
Vamos executar um SELECT que retorna mais de uma linha.
10 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
if(sqlca.sqlcode != 0) {
printf(" Erro executando a query. ");
printf("Descrição: %s ", sqlca.sqlerrm.sqlerrmc);
return -1;
} else {
printf("O id do contato é: %d ", var_id_contato);
printf("O nome do contato é: %s ", var_nome_contato.arr);
}
O que temos de diferente no comando acima basicamente é a palavra INTO, que faz parte da
especificação SQL do PostgresQL. Isso fará com que as variáveis var_id_contato e
var_nome_contato sejam preenchidas com os campos id_contato e nome, respectivamente.
Outra novidade é que declaramos a variável var_nome_contato sendo do tipo VARCHAR. Mas
espera aí, existe o tipo VARCHAR em C? A resposta é não! Mas felizmente, o pré-processador
do ECPG nos permite essa declaração, pois o tipo VARCHAR do PostgreSQL não tem nenhum
correlato em C (nem mesmo o tipo char!). O que acontece quando o código em C é gerado após
ser processado pelo ECPG é que esta declaração será transformada em uma estrutura, na
seguinte forma:
struct varchar_var_nome_contato {
int len;
char arr[255];
} var_nome_contato;
O segundo caso é um pouco mais trabalhoso, mas nada de outro mundo. Ocorre quando não
sabemos quantas linhas o SELECT irá retornar. Para isso vamos usar um cursor para retornar os
dados e ter acesso a eles. Vamos ao código:
11 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
EXEC SQL DECLARE curr_contatos CURSOR FOR SELECT id_contato, nome FROM
contatos;
if(sqlca.sqlcode != 0) {
printf(" Erro executando a query. ");
printf("Descrição: %s ", sqlca.sqlerrm.sqlerrmc);
return -1;
}
while( sqlca.sqlcode == 0) {
printf("O id do contato é: %d ", var_id_contato);
printf("O nome do contato é: %s ", var_nome_contato.arr);
12 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
No código acima omitimos algumas verificações de erro para tornar o código mais simples.
Vamos analisar os comandos do código acima:
EXEC SQL DECLARE curr_contatos CURSOR FOR SELECT id_contato, nome FROM contatos;
Este comando vai declarar um cursor (escrevi um artigo aqui no Viva o Linux
(//www.vivaolinux.com.br/linux/) que detalha melhor os cursores no PostgreSQL) chamado
curr_contatos para o SELECT que acompanha o comando.
O comando acima vai realizar o primeiro fetch, caso haja algum dado na tabela, e vai armazenar
os valores dentro das variáveis var_id_contato e var_nome_contato.
Após o FETCH, vamos entrar em um loop while, que vai ser executado enquanto não tivermos
um erro ou um warning. Antes que você pense que ficaremos em um loop infinito, vamos lembrar
que quando uma query não retorna resultados o valor de sqlca.sqlcode é maior do que zero.
Dentro do loop, precisamos executar outro FETCH, pois se não o fizermos aí sim entraremos em
um loop infinito.
Por fim, fechamos o cursor com o comando CLOSE curr_contatos e executamos o COMMIT.
Um ponto que omitimos foi a verificação no caso do PostgreSQL retornar valores nulos (NULL do
banco de dados, não NULL do C) para algum dos campos. Esta verificação deve ser feita, pois do
contrário podemos receber erros do tipo:
Para contornar este problema, precisamos usar um "indicator" (ou indicador, traduzindo
literalmente) para verificar se uma coluna é NULL ou não. Para isso, declaramos uma variável
extra na seção DECLARE do tipo int. Vejamos como vai ficar o código acima, supondo que temos
algum valor NULL no campos nome:
13 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
EXEC SQL DECLARE curr_contatos CURSOR FOR SELECT id_contato, nome FROM
contatos;
if(sqlca.sqlcode != 0) {
printf(" Erro executando a query. ");
printf("Descrição: %s ", sqlca.sqlerrm.sqlerrmc);
return -1;
}
while( sqlca.sqlcode == 0) {
printf("O id do contato é: %d ", var_id_contato);
printf("O nome do contato é: %s ", var_nome_contato.arr);
Se a variável verifica_nome_null for igual a zero, então o campo não é NULL e podemos acessar
este valor, do contrário, se tentarmos acessar este valor teremos um erro. A verificação pode ser
feita assim:
14 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...
while( sqlca.sqlcode == 0) {
if(verifica_nome_null == 0) {
printf("O id do contato é: %d ", var_id_contato);
printf("O nome do contato é: %s ", var_nome_contato.arr);
}
Para fazer a verificação em mais de uma coluna, basta criar mais variáveis do tipo int e fazer a
associação conforme mostrado aqui.
CONSIDERAÇÕES FINAIS
Neste artigo vimos uma alternativa a libpq para acessar o PostgreSQL usando C com o uso do
ECPG. Como tudo na vida, o ECPG tem as suas vantagens e desvantagens. Lembrando que é
possível também combinar os dois métodos, usando tanto a libpq quanto o ECPG no mesmo
código.
Espero ter dado mais uma opção com relação ao interfaceamento com o PostgreSQL.
Um grande abraço!!!
Voltar (verArtigo.php?codigo=4652)
15 of 15 10/05/2018 22:44