Acessando PostgreSQL com C

O PostgreSQL é um dos principais bancos de dados open source do momento. Veremos neste artigo como acessá-lo utilizando a linguagem C.

[ Hits: 119.783 ]

Por: Poleto em 08/12/2005


Recuperando dados



Chegamos na parte mais usada, e também a mais complexa da libpq, que é a recuperação de dados.

O que torna essa parte da API mais complexa é o fato de não sabermos sempre quantas linhas o nosso comando irá retornar, ou mesmo a quantidade de campos. Porém, podemos fazer chamadas adicionais a funções da API que ajudam a contornar este problema. Para executar um comando SELECT continuamos a usar a função PQexec exatamente como antes.

Primeiro, vamos descobrir quantas linhas o nosso comando retorna. Para isso, usamos a função PQntuples, que tem o seguinte protótipo:

int PQntuples(PGresult *result);

Onde result é o retorno da chamada a função PQexec.

Tudo bem, isso na verdade não ajuda muito, pois o que queremos é ver o que temos dentro da tabela. Para isso, vamos usar uma maneira rápida e simples da libpq que gera a saída em um arquivo. Esta função é a PQprint, que tem o protótipo:

void PQprint(FILE *stream, PGresult *result, PQprintOpt *options);

Esta função vai receber como parâmetros um ponteiro para o nosso arquivo, um ponteiro de resultado retornado pela função PQexec e uma estrutura de opções. Esta estrutura vai definir algumas opções para gerar o arquivo, como por exemplo o caractere que vai delimitar os dados.

typedef struct PQprintOpt
{
    pqbool header;    /*imprime o cabeçalho*/
    pqbool align;     /*alinha e preenche os campos*/
    pqbool standard;  /*formato antigo não mais utilizado*/
    pqbool html3;     /*gera saída das tabelas em HTML*/
    pqbool expanded;  /*expande tabelas*/
    pqbool pager;     /*usa o paginador para saída caso necessário*/
    char *fieldSep;   /*caractere que será o separador de campos*/
    char *tableOpt;   /*inserção na <table ...> HTML*/
    char *legenda;    /*legenda HTML*/
    char **fieldname; /*array terminado com null contendo o nome de campos para substituição*/
}

Vamos agora alterar o nosso programa anterior para recuperar os dados da nossa tabela de testes.

#include <stdio.h>
#include <stdlib.h>
#include <libpq-fe.h>

/*Objeto de conexão*/
PGconn *conn = NULL;

/*Ponteiro de resultado*/
PGresult *result;

/*Arquivo que irá conter o fluxo de saída*/
FILE *output_stream;

/*Estrutura de opções*/
PQprintOpt print_options;

int main()
{
    /*realiza a conexão*/
    conn = PQconnectdb("host=localhost dbname=TESTE");
    
    if(PQstatus(conn) == CONNECTION_OK)
    {
        printf("Conexão com efetuada com sucesso. ");
    }
    else
    {
        printf("Falha na conexão. Erro: %s", PQerrorMessage(conn));
        PQfinish(conn);
        return -1;
    }

    /*Executa o comando*/
    result = PQexec(conn, "SELECT * FROM contatos");
    
    if(!result)
    {
        printf("Erro executando comando. ");
    }
    else
    {
        switch(PQresultStatus(result))
        {
            case PGRES_EMPTY_QUERY:
                printf("Nada aconteceu. ");
                break;
            case PGRES_TUPLES_OK:
                printf("A query retornou %d linhas. ", PQntuples(result));
                break;
            case PGRES_FATAL_ERROR:
                printf("Error in query: %s ", PQresultErrorMessage(result));
                break;
            case PGRES_COMMAND_OK:
                printf("%s linhas afetadas. ", PQcmdTuples(result));
                break;
            default:
                printf("Algum outro resultado ocorreu. ");
                break;
        }
        
        /*Define o nosso arquivo de saída*/
        output_stream = fopen("/dev/tty", "w");

        if(output_stream == NULL)
            printf("Erro abrindo o arquivo. ");
        else
        {
            
            memset(&print_options, '\0', sizeof(print_options));
            
            print_options.header = 1;
            print_options.align = 1;
            print_options.html3 = 0;
            print_options.fieldSep = "|";
            print_options.fieldName = NULL;
            
            PQprint(output_stream, result, &print_options);
        }
                
        /*Libera o nosso objeto*/
        PQclear(result);
    }

  
    /*Verifica se a conexão está aberta e a encerra*/
    if(conn != NULL)
        PQfinish(conn);
}

Percebam que apesar de ser relativamente simples de usar, esta solução está longe de ser a melhor solução para recuperar dados. Quando temos um volume pequeno de dados esta solução é aceitável, mas que torna-se inutilizável quando temos tabelas maiores. Para piorar, é muito complicado se quisermos manipular os valores retornados.

Existe uma outra alternativa muito mais eficiente para retornarmos dados que é o uso de cursores. Este assunto porém é material suficiente para um novo artigo, devido ao tamanho e complexidade envolvida.

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Criando o ambiente de testes
   3. Libpq
   4. Rotinas para conexão
   5. Inserindo, atualizando e removendo dados
   6. Recuperando dados
   7. Considerações finais
Outros artigos deste autor

Instalando o CMS Drupal 4.7

Acessando PostgreSQL com C - Cursores

PostgreSQL - Embutindo comandos SQL no seu código C

Leitura recomendada

Acessando PostgreSQL com C - Cursores

Usando MySQL na linguagem C

Ensaio acerca de bibliotecas de código aberto para abstração de acesso a banco de dados em linguagem C++

Embutindo um banco de dados SQLite em sua aplicação C++

PostgreSQL - Embutindo comandos SQL no seu código C

  
Comentários
[1] Comentário enviado por cbov em 08/12/2005 - 04:16h

muito bom artigo.
eu imaginava ser mais complicado, pelo fato do unico banco que acessei usando C foi o oracle, qual tinha que dar algumas voltas ate gerar o binario

[2] Comentário enviado por teovictor em 08/12/2005 - 12:00h

Se a intenção era ser um pontapé inicial, saiba que foi um pontapé certeiro. :) Muito bom para começar a usar o PostgreSQL em C e muito bem explicado.

[3] Comentário enviado por bestlinux em 08/12/2005 - 13:12h

Parabéns pelo artigo...

Não sabia que o PostgreSQL "conversava" com C :-)

Muito interessante...

Falow !

[4] Comentário enviado por Serafim em 08/12/2005 - 14:35h

Muito interessante o seu artigo. Não sabia que o PostgreSQL podia ser usado no C.

[5] Comentário enviado por lennon.jesus em 09/12/2005 - 13:52h

Show de bola!
Gostei muito.
Quando tiver tempo vou testar!

Abraços,
Lennon Jesus

[6] Comentário enviado por rjesus em 13/03/2007 - 11:19h

Olá, sou novo no linux, utilizoo o SUSE versão 10.1, tentei executar o exemplo que foi passado acima e obtive o seguinte resultado :
suse:/usr/include/pgsql # gcc $(pkg-config --libs --cflags gtk+-2.0) -g teste1.c
/tmp/ccc0dzwL.o: In function `main':
/usr/include/pgsql/teste1.c:13: undefined reference to `PQconnectdb'
/usr/include/pgsql/teste1.c:15: undefined reference to `PQstatus'
/usr/include/pgsql/teste1.c:28: undefined reference to `PQexec'
/usr/include/pgsql/teste1.c:21: undefined reference to `PQerrorMessage'
/usr/include/pgsql/teste1.c:22: undefined reference to `PQfinish'
/usr/include/pgsql/teste1.c:36: undefined reference to `PQresultStatus'
/usr/include/pgsql/teste1.c:42: undefined reference to `PQresultErrorMessage'
/usr/include/pgsql/teste1.c:45: undefined reference to `PQcmdTuples'
/usr/include/pgsql/teste1.c:53: undefined reference to `PQclear'
/usr/include/pgsql/teste1.c:59: undefined reference to `PQfinish'
collect2: ld returned 1 exit status
Alguêm poderia me ajudar ???
Obigado!

[7] Comentário enviado por seferzohar em 06/11/2007 - 16:13h

rjesus
Vc esta compilando o exemplo com as flags erradas para o linker (ld)
pkg-config --libs --cflags gtk+-2.0 gera as flags necessarias para compilacao de programas gráficos utilizando a biblioteca gtk, desnecessária neste exemplo. Para compilar-lo vc precisa que o linker ligue o seu programa a biblioteca libpq, que implementa as funcoes acima.
O seu teste provavelmente irá compilar com o seguinte comando:

gcc -lpq -o teste1 teste1.c

[8] Comentário enviado por albertguedes em 19/02/2008 - 19:41h

Quem estiver comproblemas de erro de compilação, criem um arquivo
'Makefile' e coloquem nele estas linhas

----
<programa>: <programa>.o
gcc -O -o <programa> <programa>.o -lpq

<programa>.o: <programa>.c
gcc -c -O -o <programa>.o <programa>.c -I/usr/include/postgresql/
-----

Eu testei e compila todos os código feito no artigo do Poleto, e ainda otimiza com a opção "-O".

Depois para compilar é só dar

$ make

no mesmo diretorio onde tenha o 'Makefile' e terá o programa compiladinho.

[9] Comentário enviado por netmorais em 30/06/2008 - 16:04h

Poleto
Voce sabe se existe a biblioteca estática libpq para windows (libpq.a ...).
Instalei o Postgres 8.3 num xp e na pasta .../lib só encontro .dll.
Grato
Sergio.
netmorais@bol.com.br

[10] Comentário enviado por poleto em 30/06/2008 - 18:13h

netmorais,

Nunca tentei utilizar a libpq a partir do windows.
Mas, acredito que não seja muito diferente, só que, ao invés de usar uma biblioteca com extensão .so, você vai usar uma dll. Se o nome não for o mesmo (libpq.dll, tente pq.dll). De resto, use o procedimento normal do desenvolvimento sobre windows para carregar a dll.

Abraços,
Luiz Poleto

[11] Comentário enviado por fabiomattes2011 em 01/09/2008 - 17:52h

Esta biblioteca também funciona no c++, ou tem alguma outra?

[12] Comentário enviado por poleto em 01/09/2008 - 17:54h

gelheadbanger,

Teoricamente, não existe motivos para não funcionar.
Qualquer coisa, só perguntar.

Abraços,
Luiz Poleto

[13] Comentário enviado por fabiomattes2011 em 03/09/2008 - 16:20h

vo testar aqui com c++... qualquer posto aqui se funcionou... valeu poleto.

[14] Comentário enviado por fabiomattes2011 em 03/09/2008 - 17:22h

Kra consegui conectar no c++ mais teve algumas alterações, segue abaxo o código que usei:

#include <iostream>
#include "libpq-fe.h"

using namespace std;

/* Conexão com o banco */
PGconn *conn = NULL;

int main()
{
/* realiza a conexão */
conn = PQconnectdb("host=localhost dbname=TESTE user=admin password=mnpinfo459");

if(PQstatus(conn) == CONNECTION_OK)
{
cout << "Conexão efetuada com sucesso!";
}
else
{
cout << "Falha na conexão. Erro " << PQerrorMessage(conn);
PQfinish(conn);
return -1;
}

/* Verifica se a conexão está aberta e a encerra */
if(conn != NULL)
PQfinish(conn);

depois é só compilar com:
g++ -o programa -I/usr/include/postgresql/ programa.cpp -lpq

[15] Comentário enviado por Azraelm em 19/08/2015 - 04:30h

Boa, valeu pela contribuição.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts