Acessando PostgreSQL com C - Cursores

Veremos neste artigo como trabalhar com cursores através da libpq, utilizando a linguagem C.

[ Hits: 42.327 ]

Por: Poleto em 27/04/2006


Acessando os dados recuperados



A última parte da manipulação de cursores é a forma de acessar os dados que foram retornados no nosso cursor. Uma coisa que não temos que nos preocupar é como os dados serão retornados, pois a libpq sempre retorna os dados em forma de string e cabe a quem estiver escrevendo o programa converter os dados, caso seja necessário.

Somente no caso de cursores binários (BINARY CURSORS) esta afirmação não é verdade, mas este assunto está fora de nosso escopo.

Vamos conhecer as funções que irão nos auxiliar com a tarefa de acessar os dados retornados:

PQgetvalue


Esta função retorna uma string terminada em NULL, e tem o seguinte protótipo:

char *PQgetvalue(const PGresult *res, int tup_num, int field_num);

Onde *res é um ponteiro para uma estrutura PGresult, tup_num é o número da linha que queremos acessar e field_num é o número do campo. Lembrando que número de linhas e colunas sempre começam em zero.

Um ponto importante sobre esta função: a string retornada encontra-se dentro de uma estrutura PGresult, logo, é preciso copiar os dados caso seja necessário manter os dados para fazer qualquer coisa com eles.

PQgetisnull


Esta função nos permite verificar se o valor a ser retornado pelo banco é uma string de comprimento nulo ou uma string em branco cujo campo contém o valor NULL (lembrando que NULL dentro de uma coluna no banco não significa vazio, e sim desconhecido).

int PQgetisnull(const PGresult *res, int tup_num, int field_num);

Onde *res é um ponteiro para uma estrutura PGresult, tup_num é o número da linha que queremos acessar e field_num é o número do campo. Lembrando que número de linhas e colunas sempre começam em zero. A função irá retornar 1 se o campo for nulo e 0 se tiver um valor não-nulo.

Vamos ao nosso código agora. Vamos criar uma função para poder ver os dados retornados:

void Exibe_Dados(PGresult *result)
{
   int coluna;
  
   for(coluna = 0; coluna < PQnfields(result); coluna++)
   {
      /*Verifica se o valor da coluna é nulo*/
      if(PQgetisnull(result, 0, coluna))
      {
         printf("DATA: <NULL> ");
      }
      else
      {
         printf("DATA: %s ", PQgetvalue(result, 0, coluna));
      }
   }
}

A listagem completa do programa, incluindo a rotina de conexão fica assim:

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

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

/*Protótipo de funções*/
int ExecutaComando(const char *, PGresult **);
void Mostra_Info_Colunas(PGresult *);
void Exibe_Dados(PGresult *);

int main()
{
   int comando_ok;
   PGresult *result;

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

    comando_ok = ExecutaComando("BEGIN WORK", &result);
    
    if(comando_ok)
    {
       PQclear(result);
      
       /*Executa o comando*/
       comando_ok = ExecutaComando("DECLARE curr CURSOR FOR SELECT * FROM contatos", &result);
      
       if(comando_ok)
       {
          PQclear(result);
          comando_ok = ExecutaComando("FETCH 1 IN curr", &result);
          
          if(comando_ok)
             Mostra_Info_Colunas(result);
          
          while(comando_ok && PQntuples(result) > 0)
          {
             Exibe_Dados(result);
             PQclear(result);
             ExecutaComando("FETCH NEXT IN curr", &result);
          }
       }
      comando_ok = ExecutaComando("COMMIT WORK", &result);
    }

    if(comando_ok)
       PQclear(result);

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


int ExecutaComando(const char *comando, PGresult **ptr_resultado)
{
   int codigo_retorno = 1;
   const char *str_resultado;
  
   PGresult *resultado_local;
  
   printf(" Executando comando: %s ", comando);
      
   /*executa o comando e armazena localmente*/
   resultado_local = PQexec(conn, comando);
  
   /*passa o resultado local para o segundo parâmetro da função, para que seja
   acessível dentro de MAIN*/
   *ptr_resultado = resultado_local;
  
   /*Verifica se o comando foi bem sucedido*/
   if(!resultado_local)
   {
      /*Se falhou, imprime mensagem na tela e seta o código de retorno da função como 0 (erro)*/
      printf("O comando falhou. ");
      codigo_retorno = 0;
   }
   else
   {
      /*Se foi sucedido, chamamos PQresultStatus para verificar qual o código de retorno*/
      switch(PQresultStatus(resultado_local))
      {
         case PGRES_COMMAND_OK:
            printf("Comando ok, %s linhas afetadas. ", PQcmdTuples(resultado_local));
            break;
         case PGRES_TUPLES_OK:
            printf("A query retornou %d linhas. ", PQntuples(resultado_local));
            break;
         default:
            printf("Error in query: %s ", PQresultErrorMessage(resultado_local));
            PQclear(resultado_local);
            codigo_retorno = 0;
            break;
      }
   }
  
   /*retorna código de retorno*/
   return codigo_retorno;
}

void Mostra_Info_Colunas(PGresult *result)
{
   int numero_colunas;
   int i;
  
   if(!result)
      return;
  
   /*Obtém o número de colunas*/
   numero_colunas = PQnfields(result);
   printf("O conjunto de dados tem %d colunas ", numero_colunas);
  
   for(i = 0; i <numero_colunas; i++)
   {
      printf("Campo: %d. Nome: %s Tamanho Interno: %d ", i, PQfname(result, i), PQfsize(result, i));
   }
}

void Exibe_Dados(PGresult *result)
{
   int coluna;
  
   for(coluna = 0; coluna < PQnfields(result); coluna++)
   {
      /*Verifica se o valor da coluna é nulo*/
      if(PQgetisnull(result, 0, coluna))
      {
         printf("DATA: <NULL> ");
      }
      else
      {
         printf("DATA: %s ", PQgetvalue(result, 0, coluna));
      }
   }
}

Considerações finais


A utilização da libpq é bem mais simples do que parece. Neste artigo e no anterior, vimos como fazer quase todas as ações possíveis pela libpq, claro, ainda existem outros tópicos a serem abordados, mas com o que temos até o momento, já temos o suficiente para escrever uma aplicação completa.

Um grande abraço!!!

Página anterior    

Páginas do artigo
   1. Introdução
   2. Uma breve explicação sobre cursores
   3. Declaração de cursores
   4. Retornando uma linha por vez
   5. Informações sobre colunas
   6. Acessando os dados recuperados
Outros artigos deste autor

PostgreSQL - Embutindo comandos SQL no seu código C

Instalando o CMS Drupal 4.7

Acessando PostgreSQL com C

Leitura recomendada

PostgreSQL - Embutindo comandos SQL no seu código C

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

Acessando PostgreSQL com C

Usando MySQL na linguagem C

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

  
Comentários
[1] Comentário enviado por jragomes em 28/04/2006 - 14:02h

Parabéns pelo artigo, muito bem escrito e detalhado.

[2] Comentário enviado por madsonbraz em 02/05/2006 - 08:53h

Me tire uma duvida, é possivel criar um cluster com o postgresql?

[3] Comentário enviado por poleto em 02/05/2006 - 14:54h

madsonbraz,

E possivel sim, mas eu particularmente nao sei como.

[]'s
Poleto

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

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!

[5] Comentário enviado por poleto em 13/03/2007 - 15:04h

Fala rjesus,

Parece que você esqueceu alguns parâmetros para o gcc na hora de executar.
Dá uma olhada neste artigo que tem os detalhes necessários para compilar programas com suporte ao PostgreSQL:

http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=4169

Qualquer coisa grita.
[]'s
Poleto

[6] Comentário enviado por evaldobarbosa em 04/12/2008 - 15:36h

Eu resolvi o problema criando um arquivo que já automatiza esse negócio pra mim, saca só:

#!/bin/bash

rm cursores

g++ -o arquivo -I/usr/include/postgresql/ arquivo.cpp -lpq
#clear
echo ###### executando #####
if [ -x cursores ] ; then
./cursores
fi

exit 0


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts