Você está na página 1de 15

PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...

POSTGRESQL - EMBUTINDO COMANDOS SQL NO SEU CÓDIGO C

Autor: Poleto <luiz.poleto at gmail.com>


Data: 01/06/2006

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:

A depuração do programa pode ser mais complicada, pois o arquivo é pré-processado


antes de o compilador C entrar em ação, ou seja, erros do compilador podem ser mais
difíceis de encontrar.
Deve-se saber antecipadamente a estrutura das tabelas quando for usar comandos
SELECT.

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...

CRIANDO O AMBIENTE DE TESTES

Antes de começarmos, vamos partir do princípio que o PostgreSQL já funciona em seu


computador (e usei de base para este artigo a versão 8.0, mas deve funcionar em versões mais
antigas), e que você tem um banco de dados pronto para ser usado. Também iremos considerar
que você já tem um leve conhecimento sobre comandos SQL e C.

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:

CREATE TABLE contatos(


id_contato INTEGER,
nome VARCHAR(255)
);

Digitando no psql, teremos o seguinte (a palavra 'TESTE' que aparece é o nome do nosso banco
de dados):

TESTE=> CREATE TABLE contatos (


TESTE=> id_contato INTEGER,
TESTE=> nome VARCHAR(255)
TESTE=> );

(note que o comando só é executado quando temos um ';'). Ao pressionar enter no final do
comando acima, teremos o seguinte resultado:

TESTE=> CREATE TABLE

Pronto, nossa tabela está criada e pronta para ser usada.

2 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...

INICIANDO COM O ECPG

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:

exec sql include sqlca;

A segunda regra é que todo comando que deve ser interpretado pelo pré-processador deve iniciar
com o comando exec sql, por exemplo:

exec sql SELECT * FROM FOO;

Simples, não? Então, já está na hora de colocar a mão na massa.

CONECTANDO COM O SERVIDOR DE BANCO DE DADOS

Para conectar-se com o banco de dados, usamos o seguinte comando:

EXEC SQL CONNECT TO destino [AS nome_da_conexão] [USER nome_do_usuário];

3 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...

Onde destino pode ser definido da seguinte forma:

nome do banco[@host][:porta]
tcp:postgresql://host[:porta][/nome_do_banco]
unix:postgresql://host[:porta][/nome_do_banco]

uma string contendo qualquer uma das formas mencionadas acima


uma variável do tipo char contendo qualquer uma das formas mencionadas acima
DEFAULT

E nome_do_usuário pode ser definido como:

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>

EXEC SQL include sqlca;

/* 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;

EXEC SQL CONNECT TO :szDBName USER :szUser;

if(sqlca.sqlcode != 0) {
printf("Conexão com %s falhou. ", nome_database);
return 0;
} else {
printf("Connection ok com %s. ", nome_database);
}

EXEC SQL DISCONNECT ALL;

return 0;
}

Os pontos que devem ser observados aqui são:

EXEC SQL BEGIN DECLARE SECTION;


const char *nome_database = "teste@localhost";
const char *szUser = "teste";
EXEC SQL END DECLARE SECTION;

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:

EXEC SQL CONNECT TO :szDBName USER :szUser;

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.

Outro ponto a ser observado é a verificação da variável sqlca.sqlcode. O pré-processador declara


uma variável global chamada sqlca, que tem a seguinte estrutura:

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:

0 se nenhum erro ocorreu durante a execução;


negativo, se um warning foi gerado;
positivo, se uma condição não-fatal ocorreu, como por exemplo uma query que não
retorna valores.

Por fim, o comando:

EXEC SQL DISCONNECT ALL;

Finaliza todas as conexões abertas pelo programa.

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.

Para compilar nosso programa acima, usamos o comando:

$ 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:

$ gcc -o exemplo exemplo.c -lecpg

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.

INSERINDO, ATUALIZANDO E APAGANDO DADOS DE TABELAS

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 BEGIN DECLARE SECTION;


int i;
EXEC SQL END DECLARE SECTION;

EXEC SQL BEGIN WORK;

for(i = 0; i < 10; i++) {

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);
}
}

EXEC SQL COMMIT WORK;

9 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...

As novidades no fragmento de código acima são:

EXEC SQL BEGIN WORK e EXEC SQL COMMIT WORK

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.

Os comandos de UPDATE e DELETE podem ser executados usando a mesma estrutura de


código acima, uma vez que eles são semelhantes.

RETORNANDO DADOS DE TABELAS

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.

Quando executamos um SELECT, existem duas situações que podem ocorrer:

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.

No primeiro caso, a solução é (relativamente) simples. Vamos ver um exemplo de código:

10 of 15 10/05/2018 22:44
PostgreSQL - Embutindo comandos SQL no seu... https://www.vivaolinux.com.br/artigos/impresso...

EXEC SQL BEGIN DECLARE SECTION;


int var_id_contato;
VARCHAR var_nome_contato[255];
EXEC SQL END DECLARE SECTION;

EXEC SQL SELECT id_contato, nome INTO :var_id_contato, :var_nome_contato FROM


contatos WHERE id_contato = 1;

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;

Portanto, podemos acessar o valor retornado usando var_nome_contato.arr.

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 BEGIN DECLARE SECTION;


int var_id_contato;
VARCHAR var_nome_contato[255];
EXEC SQL END DECLARE SECTION;

EXEC SQL BEGIN WORK;

EXEC SQL DECLARE curr_contatos CURSOR FOR SELECT id_contato, nome FROM
contatos;

EXEC SQL OPEN curr_contatos;

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato, :var_nome_contato;

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);

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato, :var_nome_contato;


}

EXEC SQL CLOSE curr_contatos;


EXEC SQL COMMIT WORK;

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.

EXEC SQL OPEN curr_contatos;

Este comando simplesmente abre o cursor.

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato, :var_nome_contato;

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:

NULL value without indicator in line xx.

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 BEGIN DECLARE SECTION;


int var_id_contato;
VARCHAR var_nome_contato[255];
int verifica_nome_null;
EXEC SQL END DECLARE SECTION;

EXEC SQL BEGIN WORK;

EXEC SQL DECLARE curr_contatos CURSOR FOR SELECT id_contato, nome FROM
contatos;

EXEC SQL OPEN curr_contatos;

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato,


:var_nome_contato:verifica_nome_null;

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);

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato,


:var_nome_contato:verifica_nome_null;
}

EXEC SQL CLOSE curr_contatos;


EXEC SQL COMMIT WORK;

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);
}

EXEC SQL FETCH NEXT IN curr_contatos INTO :var_id_contato, :var_nome_contato;


}

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

Você também pode gostar