Como criar uma conexão do banco de dados PostgreSQL com a linguagem C

Introdução

O PostgreSQL é um poderoso banco de dados open source, relacional, com gerenciamento multiusuário e compatível com as plataformas Linux, FreeBSD, Solaris, Microsoft Windows e Mac OS X. Ele é utilizado em pequenas, médias e grandes aplicações de diferentes tipos de soluções. Por ele ser capaz de suportar o gerenciamento de dados de grandes sistemas, muitas IDEs (Integrated Development Environment) e ambientes de desenvolvimento já possuem métodos de comunicação com este banco.

Entretanto, hoje não é comum ver soluções desenvolvidas na linguagem C e integradas com o PostgreSQL. Aqui, vou demonstrar como é simples realizar a comunicação entre um programa escrito em C e uma base de dados criada no PostgreSQL.

 

Objetivo

Na internet e na documentação do PostgreSQL você vai encontrar muitos exemplos de programas em C que usam API para realizar a comunicação com o Postgres. Mas todos eles, por terem uma finalidade didática, deixam a implementação dessa comunicação na função main e processos como conectar, criar, selecionar ou fechar a conexão não são separados em funções, o que pode dificultar um pouco a implantação para quem tem menos experiência em C.

Organizar seu software em funções e, consequentemente em bibliotecas (ou classes), é o básico a se fazer para manter um código organizado, claro e de fácil manutenção, principalmente quando falamos de programação em C, já que se torna muito mais fácil de entender. Por isso, esse artigo tem o objetivo de mostrar como criar um pequeno programa em C (de forma estruturada) fazendo uso da include libpq para se comunicar com o PostgreSQL.

O ponto mais complicado nessa tarefa é criar estruturas que possam ser dimencionadas dinâmicamente e essa tarefa não tem como ser feita sem algum dominio na manipulação de ponteiros.

 

Situação problema

Estou desenvolvendo um projeto para coleta de dados de um medidor de energia, são dados de geração, consumo, tensão e corrente e até que esses dados possam ser enviados ao webservice  ou se for necessário fazer algum tipo de pré-processamento ficam gravados em um banco de dados SQLite3.

O SQLite é um banco de dados voltado para pequenos aplicações e apesar de possuir menos recursos que um SGDB convencional, é de fácil implatação e nativo em várias linguagens, também esta presente em software como o Firefox que utiliza ele para organizar os favoritos, senhas e outros dados do usuário.  Até o momento nenhuma novidade, pois já desenvolvi outros projetos utilizando o SQLite que é muito prático e rápido para pequenas aplicações (no site tem uma relação de limitações ou indicações).

Porém, com o SQLite sinto falta de alguns recursos, como por exemplo, PROCEDURES, variáveis ou campos CALCULATE. Mas nada que utilizando as alternativas do próprio banco ou da linguagem de programação não pudessem ser contornados, até mesmo porque o que  falta de recursos nele, surpreende em outros pontos.

A coisa ficou complicada quando precisei programar com o framework Django. Pelo fato do SQLite ser mono usuário e o projeto necessitar que o banco de dados fosse acessado por um daemon (software que executa como um processo em plano de fundo) que fica coletando dados e o próprio Django responsável pelos cadastro, alterações, relatórios de log etc, a chance de ocorrer travamentos quando estivesse em produção seria grande.

Isso porque o daemon tem prioridade de acesso o Django não iria conseguir acessar o banco de dados, fazendo com que a aplicação fique praticamente todo tempo fora do ar. Mas, após algum tempo procurando uma solução para isso, decidi usar o PostgreSQL, já que o Django também suporta PostgreSQL e existe uma extensa documentação da API para utilizar o PostgreSQL com diversas linguagens.

 

Disclaimer

Mas porque faço isso em C se com Python, por exemplo, é muito mais fácil e rápido?

  1.  C ainda é uma linguagem relevante para o desenvolvimento de software embarcado, como mostrado no Ranking das Linguagens de Programação mais usadas em 2018 (IEEE Spectrum).
  2.  Porque eu gosto.

Os passos que vou descrever ou exemplos que constam nesse artigo foram feitos no Linux (Slackware 14.1, eu sei ja passou da hora de desapegar) com o compilador GCC v4.8.2 mas nos exemplos não tem nenhum header que não seja comum a outros compiladores.

 

Escovando bits

Não vou entrar em detalhes de como instalar, configurar, criar um banco de dados ou usuários no PostgreSQL, os dois primeiros passos variam de acordo com o sistema operacional utilizado, entretanto, faz parte da instalação a biblioteca libpq.h que é utilizada para acessar o PostgreSQL em C.


/*
 * helloworld.c
 */
#include <stdio.h>
#include <libpq-fe.h> 

int main() 
{   
    int lib_ver = PQlibVersion();

    printf("Versao libpq: %d\n", lib_ver);
    
    return 0;
}

Esse programa irá imprimir a versão da libpq e para compilá-lo é necessário indicar o local dos headers do PostgreSQL utilizando o parâmetro -lpq durante a compilação:

 
$ gcc -o helloworld helloworld -lpq
$ ./helloworld 
Versao libpq: 90309

Se você conseguiu compilar e executar esse exemplo, é sinal que instalou e configurou o PostgreSQL corretamente, a partir de agora nosso foco será os comandos e estruturas necessárias para estruturar os exemplos.

Para fazer uma conexão com o servidor de banco de dados você deve utilizar a função PQconnectdb que recebe uma string com os parâmetros de conexão, veja:

“password=masterkey user=postgres dbname=concrete”

Essa string você pode gerar dinamicamente, lendo as configurações de um arquivo ou recebendo como parâmetro. No exemplo deixei estático para ficar mais simples.


/*
 * connect.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <libpq-fe.h> 

int main() 
{   
    PGconn *conn = PQconnectdb("password=masterkey user=postgres dbname=concrete");
   
    if (PQstatus(conn) == CONNECTION_BAD) {
        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
        PQfinish(conn);
        exit(1);
    }

    printf("Database connected!\n");
    printf("User: %s\n", PQuser(conn));
    printf("Database name: %s\n", PQdb(conn));
    printf("Password: %s\n", PQpass(conn));

    PQfinish(conn);
    return 0;
}

 

Uma vez que a aplicação já esta conectando com o banco de dados é hora de criar uma tabela, inserir registros, fazer a seleção e processar os dados recebidos. Deixei o software completo e comentado em meu github.

Com esses exemplos espero ter contribuído para que possa montar as suas próprias bibliotecas de acesso. Fique a vontade para utilizar ou modificar os códigos aqui apresentados e/ou sugerir melhorias.

Agradecimentos

Ellayne Cristin (Revisão texto)


Leave a Reply

Your email address will not be published. Required fields are marked *