|
jun 14
|
O PostgreSQL permite que usuários possam desenvolver funções em outras linguagens, além de SQL. Essas linguagens são chamadas de procedural languages (PLs), ou linguagens procedurais. Linguagens como C, Tcl, Python, Perl, Java, e outras, são suportadas desde que informadas no momento da compilação e instalação do postgres.
Para verificar as PLs suportadas pelo seu postgres (as que foram ativadas no momento da instalação) basta executar a seguinte SQL:
- SELECT * FROM pg_language;
Você pode adicionar o suporte a outras linguagens, que não estejam listadas ao executar a SQL acima. Mas para isso seria necessário recompilar e reinstalar o postgres ou, em algumas distribuições Linux, por exemplo, instalar o pacote RPM adicional para suportar a linguagem desejada.
O postgres já vem com suporte nativo a algumas linguagens, sem a necessidade de informá-las no momento da instalação, como: SQL, PLPgSQL, Internal e C. Utilizar uma dessas linguagens nativas nos poupa tempo e tem um custo menor, uma vez que não precisaremos instalar novos interpretadores ou compiladores na máquina onde está instalado nosso postgres.
No órgão onde trabalho surgiu a necessidade de se criar uma PL no postgres para envio de e-mail. Ao fazer uma busca pelo Google encontrei facilmente duas soluções: uma delas utilizando a linguagem Tcl e a outra utilizando Python. Ambas as soluções são simples e de fácil implementação, além de funcionarem perfeitamente. O problema em utilizar uma dessas duas soluções é que possuímos mais de 8 servidores rodando o PostgreSQL, o que aumentaria o custo para implementar tal função, já que teríamos que recompilar o postgres com suporte a uma dessas duas linguagens, além de termos que instalar seus compiladores e interpretadores.
Depois de exaustivas tentativas buscando alguma solução para envio de e-mail em linguagem C para o postgres acabei optando por desenvolver uma. Claro que para diminuir o trabalho fui em busca de uma solução já pronta em C apenas para envio de e-mail. Achei algumas bibliotecas e códigos em C, mas um tanto complicados e grandes demais para uma pequena tarefa. Eu queria apenas um código simples, de poucas linhas e que atendesse à necessidade: envio de e-mail (não necessitava nem mesmo de autenticação via SMTP, já que eu iria adicionar o endereço dos servidores postgres como Open Relay no servidor de e-mail). Achei então o que eu estava procurando: apenas um arquivo de código, simples e funcional, que envia e-mail via socket, sem a necessidade de bibliotecas adicionais. Até o nome da solução é simples: Simple SMTP Mailer desenvolvido por Mayukh Bose. (O código pode ser encontrado em seu site pessoal: http://www.mayukhbose.com/freebies/c-code.php#smtp).
Com o código de envio de e-mails em mãos, fui em busca de uma boa documentação para integrar tal funcionalidade ao PostgreSQL. Encontrei na própria documentação do postgres, inclusive já traduzida para o português no site: http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html. Esta documentação é bem completa e explica detalhadamente como desenvolver uma PL em linguagem C para o postgres. Sugiro que leia toda a documentação antes de iniciar o desenvolvimento de uma PL para o postgres.
Para desenvolver a função, utilizei a convenção mais atual para PL chamada de Versão 1 (mais fácil e com mais recursos que a versão anterior chamada Versão 0). Essa versão diminui a complexidade de troca de dados entre o postgres e seu código em C.
Para declarar uma função em C utilizando a Versão 1, basta declará-la desta forma:
Datum nome_da_função(PG_FUNCTION_ARGS)
e chamar a macro:
PG_FUNCTION_INFO_V1(nome_da_função);
que deve obrigatoriamente estar no mesmo arquivo fonte da sua função e, por convenção, estar escrita antes da própria função.
Na função em versão-1 os argumentos enviados pela função do postgres são recuperados utilizando a macro PG_GET_xxx(y), onde xxx corresponde ao tipo de dado do argumento e y corresponde ao número do argumento da função a ser buscado, iniciado a partir de 0. Podemos também retornar dados para o postgres utilizando a macro PG_RETURN_xxx(y) onde xxx corresponde ao tipo de dado a ser retornado e y corresponde ao valor a ser retornado.
Veja como exemplo a função abaixo, escrita em C, retirada do site da documentação do Postgres:
Código em C:
#include "postgres.h"
#include
#include "fmgr.h"
PG_FUNCTION_INFO_V1(somar_um);
Datum
somar_um(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg + 1);
}
A função acima é simples: apenas recebe do postgres um inteiro como parâmetro e retorna como valor o resultado do incremento do valor recebido em 1 unidade.
Para que a função acima funcione precisamos obviamente de compilar nosso código e criar sua função relativa em SQL:
Função em SQL para integração com o código em C:
CREATE FUNCTION somar_um(integer) RETURNS integer
AS 'DIRETÓRIO/funcs', 'somar_um'
LANGUAGE C STRICT;
Perceba que na função SQL somar_um(integer) acima recebemos um integer como parâmetro, exatamente como estamos esperando no nosso código em C. Para cada tipo de dado em nossa SQL existe um tipo de dado relativo em C, que pode ser visto na tabela encontrada em: http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html#XFUNC-C-TYPE-TABLE.
Não vou entrar em detalhes de como criar uma PL em C, até porque a documentação (http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html) é bem completa e esperamos que você a tenha lido pelo menos uma vez para a leitura deste artigo.
De volta à nossa função de envio de e-mails para postgres, criamos nosso código em C, integrando à solução de envio de e-mails já pronta encontrada na Internet, a qual adicionei apenas o suporte para e-mails em HTML, além de texto plano, e é claro, adicionei a funcionalidade para integração com o PostgreSQL. Para facilitar o entendimento, traduzi os comentários dos métodos de envio de e-mail para o português.
O método “sendmail” desenvolvi baseado na documentação do postgres, e traduzi os comentários meus para inglês, para que possa ser distribuído facilmente na Internet.
Antes de utilizar e redistribuir o código abaixo, peço apenas que leia os direitos autorais localizados no próprio código fonte e mantenha sempre os nomes dos autores responsáveis pelo desenvolvimento do mesmo.
Para nossa solução bastou apenas 3 arquivos:
- Makefile: contendo as diretivas necessárias para compilação do código fonte;
- smtp.h: arquivo contendo as configurações básicas para funcionamento de nosso código em C;
- sendmail.c: código da nossa função em C.
Abaixo segue o link para baixar o arquivo contendo o código completo da solução, bem como o arquivo README explicando detalhadamente seu processo de instalação.
Para testar a solução, não esqueça de adicionar o host do seu servidor postgres como Open Relay no seu servidor de e-mail.
Espero que esta solução possa ajudar muita gente e que várias pessoas possam contribuir melhorando o código e adicionando funcionalidades ao mesmo =]
Link para download do programa
cy-a
