# Bancos de dados/Abstração

Ensaio acerca de bibliotecas de código aberto para abstração de acesso a banco de dados em linguagem C++
Este estudo é um ensaio acerca das ferramentas de programação em linguagem C++ destinadas a fornecer uma camada de abstração para operar indistintamente bibliotecas clientes nativas de servidores de banco de dados. Camadas de abstração de acesso a banco de dados são comuns em plataformas de desenvolvimento e disponíveis em diversas linguagens de programação. Para a linguagem C++ temos algumas opções disponíveis. Esse ensaio introduz o conceito de camadas de abstração e fornece uma analise introdutória de algumas ferramentas consideradas relevantes.

## Introdução

A metodologia mais utilizada em projetos de aplicativos de acesso a banco de dados é a que faz uso da arquitetura cliente-servidor, onde o aplicativo do usuário acessa um Sistema Gerenciador de Banco de Dados (SGBD), ou servidor de banco de dados, através de uma rede de computadores.
Nessa arquitetura o aplicativo do cliente é responsável por interagir com o usuário através de uma interface gráfica, enviando comandos ao SGBD, que por sua vez é responsável por armazenar e recuperar dados.
Existem diversos SGBD's disponíveis, como Oracle, MySQL, Firebird, etc. Cada um deles utiliza mecanismos próprios de comunicação, autenticação e representação dos dados resultantes das consultas. Ou seja, cada um deles opera segundo protocolos próprios de comunicação e aquisição de dados.
Dessa forma, um aplicativo cliente, aquele que interage com o usuário e opera os dados através do SGBD, deve ser capaz de comunicar-se com o servidor segundo o protocolo de comunicação próprio do SGBD em questão.
Os servidores SGBD normalmente vem acompanhados de softwares (mais especificamente, bibliotecas de programação conhecidas como "bibliotecas cliente") que fornecem funcionalidades para conectar-se ao servidor e realizar operações.
As bibliotecas cliente fornecidas juntamente com um SGBD são compatíveis apenas com o SGBD ao qual estão associadas, sendo incapazes de operar com outros servidores. por isso são também são chamadas de bibliotecas cliente nativas.
O diagrama abaixo representa a arquitetura de um aplicativo que acessa SGBD's através de bibliotecas nativas.
O uso de bibliotecas nativas é defendido por muitos desenvolvedores, mas sua adoção traz varias limitações ao aplicativo que faz uso das mesmas: 1) dependência do SGBD em questão, já que a biblioteca nativa acessa apenas o SGBD para o qual foi criada 2) dependência de plataforma de software e hardware, já que o aplicativo que faz uso da biblioteca nativa poderá operar apenas nas plataformas em que a biblioteca nativa também opera.
Além disso, o uso de bibliotecas nativas torna-se questionável se analisarmos as varias bibliotecas de abstração de acesso a SGBD's existentes para linguagem C++. Bibliotecas de abstração fornecem uma API genérica para acesso aos recursos de diferentes servidores, permitindo independência de SGBD, alem de oferecer diversos recursos extras, métodos próprios para manipulação dos diferentes tipos de dados e, em alguns casos, componentes gráficos para correta apresentação desses dados em interfaces gráficas (GUI´s).
Essas ferramentas são consideradas camadas de abstração, pois fazem uso das bibliotecas nativas de acesso as diferentes fontes de dados, ao mesmo tempo que fornecem ao programador uma única interface de programação, permitindo que diferentes SGBD's sejam acessados e operados de forma indistinta.
O diagrama abaixo representa a arquitetura de um aplicativo que acessa SGBD's através de camada de abstração.
O uso de bibliotecas para abstração de acesso a SGBD' s traz um grande numero de benefícios relevantes, sendo as principais:
1) Independência de SGBD: Uma mesma biblioteca de abstração normalmente opera sobre bibliotecas nativas de vários servidores de banco de dados diferentes. Isso propicia independência de servidor de banco de dados, tornando possível migrar entre diferentes SGBD's sem alterar o código. Essa funcionalidade, mesmo considerada isoladamente, seria suficiente para justificar o uso de camadas de abstração para a grande numero das aplicações.
2) Representação facilitada para tipos de dados: Bibliotecas de abstração de SGBD's normalmente utilizam uma representação genérica para tipos de dados próprios de cada SGBD, fazendo as conversões necessárias e, desse modo, facilitando a portabilidade entre SGBD's diferentes.
3) Uso de recursos modernos da linguagem C++: algumas bibliotecas de abstração fazem uso de modernos recursos de STL e Boost, como conteineres e tipos de dados como o 'tuple' [11]', alem de sintaxe inspirada em streams.
4) Sintaxe facilitada: Algumas bibliotecas fazem uso criativo de polimorfismo e sobrecarga de operadores para permitir operações utilizando sentenças curtas e legíveis, facilitando a criação de instruções SQL e subsequente tratamento dos dados resultantes.
5) Operação em ambiente multi-thread: mesmo que a biblioteca nativa do SGBD não seja thread-safe, a biblioteca de abstração pode cuidar do acesso concorrente permitindo a operação segura em ambientes multi-thread.
6) Conformidade com padrões e independência de plataforma: As bibliotecas apresentadas aqui são concordantes com padrões e, em principio, portáveis entre várias plataformas e compiladores.
7) Manutenibilidade: as bibliotecas estudadas aqui são softwares de código aberto, permitindo manutenção, depuração, extensão e alterações de forma facilitada, caso contrario ao da maioria das bibliotecas nativas de acesso a SGBD's.
8) Funcionalidades inéditas: algumas bibliotecas implementam facilidades que não estão presentes de forma facilitada na biblioteca nativa de acesso ao SGBD
9) Acesso a fontes de dados alternativas: algumas bibliotecas foram projetadas para acessar fontes de dados pouco populares ou não concordantes com a linguagem de consulta SQL, como servidores LDAP, arquivos CSV, MySQL, arquivos Microsoft Access ou bancos de dados Berkeley DB.
10) Criação de sentenças SQL: algumas bibliotecas fornecem ferramentas para facilitar a criação de querys no padrão SQL através de uma metodologia simplificada. Esse método pode gerar consultas otimizadas e adaptadas a cada tipo de servidor de banco de dados em particular a partir de uma construção padrão única.
11) Arquitetura modular: a maioria das bibliotecas de abstração são projetadas segundo uma arquitetura modular, permitindo a criação de extensões para acesso a novas fontes de dados de forma facilitada.
O uso de uma arquitetura de camada de acesso intermediaria aos recursos das bibliotecas nativas (camada de abstração) também oferece algumas desvantagens, sendo as principais:
1) Isolamento dos recursos da biblioteca de acesso nativa: nem todos os recursos da biblioteca nativa podem estar disponíveis através da camada de abstração, que busca reunir o conjunto de funcionalidades presentes na maioria das bibliotecas nativas. Embora normalmente bibliotecas de abstração forneçam acesso direto à biblioteca nativa, essa pratica deve ser evitada, pois vai contra os princípios da utilização de uma camada de abstração, tornando o aplicativo dependente de um SGBD em particular.
2) Overload: as bibliotecas de abstração são uma camada de acesso as bibliotecas nativas e, desse modo, é de se esperar que apresentem alguma perda de desempenho. Entretanto, testes de desempenho realizados pelos criadores de algumas bibliotecas de abstração mostram que essa perda é pouco significativa e não justifica desconsiderarmos o uso dessas ferramentas na grande maioria dos casos. Você deve consultar o site oficial de cada biblioteca para maiores informações sobre desempenho.
Existem diversas bibliotecas multiplataforma para abstração de acesso a SGBD's disponíveis para linguagem C++. Para esta versão deste documento, estudaremos três das ferramentas que consideramos relevantes: GDAmm [1] , SOCI [2] e DBIxx [3].
Outras bibliotecas viáveis são citadas brevemente na conclusão deste ensaio.

## GDAmm
### Introdução

GDA [1], acrônimo para GNU Data Access, é a biblioteca para acesso a banco de dados que integra a plataforma GNU de desenvolvimento, que inclui também uma serie de bibliotecas de programação para diversas finalidades. Como acontece com todas as bibliotecas de programação da plataforma GNU, GDA é desenvolvida utilizando a linguagem C e são desenvolvidas ligações para as mais diversas linguagens de programação. Em nosso caso, faremos uso de GDAmm, que é a ligação em linguagem C++ para a biblioteca GDA. GDAmm [8] é o que chamamos de wrapper, uma camada de abstração em linguagem C++ que faz uso de chamadas a uma biblioteca em linguagem C para realizar suas tarefas. Em outras palavras, GDAmm encapsula as chamadas a GDA, fornecendo acesso as funções da biblioteca em linguagem C através da semântica própria da linguagem C++. Essa arquitetura pode parecer estranha mas é bastante empregada. A ferramenta de abstração DBIxx, por exemplo, também faz uso da mesma arquitetura. GDAmm esta integrado ao toolkit gráfico da plataforma GNU de desenvolvimento, o GTKmm, [4], fornecendo componentes gráficos como tabelas (grids) e formulários para apresentação e edição dos dados retornados das consultas ao SGBD de maneira facilitada, funcionalidade também presente na maioria das plataformas de desenvolvimento populares. Uma questão relevante acerca da plataforma GNU é o fato de a mesma ser mantida pela Free Software Foundation, o que nos da alguma garantia de que essa ferramenta não será descontinuada, mas, pelo contrario, continuara a receber aperfeiçoamentos e correções por um longo período. Como veremos, trata-se de uma biblioteca muito versátil e bastante completa.

### Plataformas e backends

Oficialmente, GDAmm é compatível com as plataformas Windows, Linux, MacOS X e a maioria dos sistemas concordantes com Posix, mas é provável que possa ser utilizado em qualquer plataforma que ofereça um compilador compatível com ISO C++ e disponha da biblioteca STL. Segundo seus manuais, os backends suportados no momento são os seguintes: MySQL, Oracle, PostgreSQL, Berkeley DB, arquivos .mdb (com recursos limitados), SQLite, SQLCipher, JDBC e Firebird. Versões anteriores também acessavam Microsoft SQL, servidores LDAP, Sybase SQL, Xbase e IBM DB2, mas a versão atual de GDA ainda não foi atualizada para operar junto a esses backends.

### Principais componentes

Os principais componentes de GDAmm são os seguintes:
Gda::Value
Libgda é uma biblioteca nitidamente orientada a dados e baseada em um complexo mecanismo de tipagem dinâmica em linguagem C chamado GObject. O recurso de tipagem dinâmica [5] [6], comum em linguagens interpretadas como Python e PHP, necessita de um método complicado e trabalhoso para uma implementação em linguagem C. Consulte documentação adicional sobre tipagem dinâmica para obter mais informações sobre o assunto. Felizmente, a biblioteca GDAmm opera todos os tipos de dados de libGDA de forma facilitada através da classe Value, sem precisar lidar com o mecanismo de Gobject [6].
O uso correto de tipagem dinâmica pode ser muito útil para tratar dados operados junto aos SGBD's. O problema da arquitetura utilizada em GDA (na verdade, utilizada em todos os projetos que utilizam glib) diz respeito à intenção da biblioteca para tratamento de novos tipos de dados, que envolve a criação de objetos em C utilizando o complicado mecanismo da biblioteca gobject [7]. Value permite tratamento indistinto para diferentes tipos de dados, sendo capaz de realizar diversas conversões entre tipos de dados diferentes. Uma olhada na assinatura da classe nos da uma idéia precisa dos tipos de dados e conversões possíveis. Os tipos dados utilizados são os presentes em glib, que em alguns casos são typedefs para tipos primitivos. Seus correspondentes em linguagem C podem ser deduzidos a partir de seu nome, por exemplo, gchar é um tipo char primitivo, gulong é um unsigned long primitivo, assim por diante.
Construtores:
Métodos:
É obrigação do programador utilizar operações coerentes para conversão de dados, já que uma grande quantidade de tipos de dados incompatíveis é operada.
Espera-se que objetos do tipo Value sejam usados em conjunto com os outros objetos de GDAmm para entrada e recuperação de dados, embora tipos primitivos também possam ser usados em muitos dos casos.
Gda::Query
A classe query permite a definição de consultas através do uso de objetos que definem de forma genérica as operações, condições e tabelas que compõe uma consulta, gerando como saída uma string contendo uma query otimizada para o backend (SGBD) em uso. Seu propósito é fornecer uma interface de programação genérica para criação consultas apropriadas para as diferentes fontes de dados , lidando com limitações e diferenças na implementação da linguagem SQL de cada servidor em particular, gerar consultas otimizadas, assim como perimir acesso a fontes de dados incompatíveis com SQL. Sua adoção favorece a portabilidade entre SGBDs e seu uso é recomendado, embora a biblioteca permita a especificação direta da string de consulta, sem o uso dos recursos dessa classe.
Os principais objetos para programação de uma query são: GdaQueryTarget, que representa as tabelas a serem operadas, QdaQueryJoin, que especifica a operação de mesmo nome (join), e GdaQueryCondition, que representa uma condição (clausula WHERE). Consulte a referencia de GDAmm para exemplos de uso dessas classes.
Gda::Conection
Objeto que realiza a conexão com o SGBD, realiza as operações no banco e controla as transações de forma transparente. Tem métodos para especificação dos parâmetros de conexão com o banco, como set_username , set_password e set_dsn para especificação de usuário, senha e nome do banco, respectivamente. Os métodos execute_select_command(string) e execute_nom_select_command(string) são os principais métodos para realizar operações no banco de dados. Outras funcionalidades incluem acesso a alguns metadados e controle de transações. Um recurso interessante e utilização das funcionalidades de libsig++ para implementar um sistema de sinais e slots para associação de tratadores dos eventos de conexão, desconexão ou abertura de novo banco de dados. O objeto Gda::Connection retorna os dados da consulta em modelos de dados derivados de Gda::DataModel, estudados a seguir
Gda::DataModel A biblioteca cliente de cada SGBD em particular retorna dados estruturados de uma forma diferente, de modo que umas das funcionalidades mais importantes para permitir operação indistinta entre diferentes fontes de dados é um mecanismo que permita acessar os dados resultantes das consultas de uma forma genérica, independe do formato fornecido pela biblioteca cliente nativa do banco de dados em uso.
Gda implementa um modelo de dados bastante simples para representar dados de diferentes tipos em linhas e colunas (uma tabela), fornecendo dois métodos diferentes para recuperação de dados: através de seu índice ou através de um iterador.
Através do uso desse modelo de dados padrão, operamos os dados resultantes de operações no banco de uma forma única, seja qual for o formato nativo fornecido pela biblioteca cliente em uso.
Objetos gráficos (widgets)
O ambiente de desenvolvimento GNU oferece objetos de interface gráfica (visões) para visualização e manipulação dos dados em um modelo de dados Gda::DataModel usando arquitetura MVC. Essa funcionalidade é comum em ambientes de desenvolvimento populares. Inicialmente, GDA era integrante da biblioteca GNOME-DB, que incluía também os componentes gráficos de visualização de dados. Recentemente foi criado um projeto separado para tratar do desenvolvimento dos objetos gráficos (widgets), o projeto libgda-uimm. No presente momento, nem todos os componentes presentes em gnome-db foram portados, e houve mudanças na API.
Os principais componentes gráficos são:
Gda::Grid: Um componente semelhante aos existentes em muitas plataformas de desenvolvimento, que recebe como argumento um modelo de dados resultante de uma consulta ao SGBD e os apresenta em um objeto gráfico na forma de tabela (linhas e colunas) de forma automática.
Gda::Form: Componente para representação de dados contidos em um Gda::DataModel, mas apresentando um registro por vez, na forma de um formulário.
Gda::DataEntry: Componente de edição de texto para entrada e edição de dados de diferentes tipos, como valores numéricos, booleanos, strings e data.

## SOCI
### 1. Introdução

SOCI [2] é um acrônimo para “Simple Oracle Call Interface” e foi criada inicialmente para fornecer uma camada de abstração facilitadora para acesso ao banco de dados Oracle. Com o passar do tempo, novos backends foram adicionados e, em sua versão atual, os bancos de dados suportados são Oracle, MySQL, PostgreSQL, SQLite3, Firebird e ODBC, operando sobre as plataformas Linux e Windows. Conforme citado no site oficial da biblioteca [2], “SOCI cria a ilusão de embarcar consultas SQL em código C++ comum, permanecendo inteiramente compatível com STL”, “A idéia é prover aos programadores em C++ uma maneira de acessar bancos de dados SQL da maneira mais natural e intuitiva”.
De fato, o que chama a atenção em SOCI são suas criativas e redundantes maneiras para especificar instruções SQL e acessar os dados resultantes dessas consultas.. Podemos usar estruturas, tipos primitivos, utilizar tipos tuple [11] (de BOOST) ou receber os dados em objetos através de um método de mapeamento objeto-relacional. Um dos métodos possíveis, baseado em streams, bastante criativo e funcional, serviu de inspiração para o método de acesso utilizado em DBIxx, outra biblioteca de abstração incluída neste ensaio. SOCI está na versão 3.1, que foi disponibilizada em 2011, e vem sendo ativamente desenvolvida desde 2004.

### Principais componentes

    soci::session Estabelece uma conexão com o servidor de banco de dados e fornece diferentes métodos para realização de operações em linguagem SQL. Um dos métodos é a especificação de strings de instruções SQL baseado na sintaxe de streams, utilizando o operador de intração “<<” e dois métodos para associação de dados:
    soci::into especifica o destino dos dados resultantes de uma operação no banco
    soci::use Usado para fácil associação de uma variável local a string SQL.
O objeto de conexão pode receber argumentos de conexão de varias formas, uma delas usando uma sintaxe parecida com objetos de conexão de outras bibliotecas:
<objeto-de-conexao> nome_objeto (“nome do backend”, “argumentos”);
… o que resulta em:
soci::session sql ( “mysql”, ”db=teste user=root password='senha' ” );
O objeto session criado com soci::session é então usado para operações no banco, de várias maneiras, entre elas, são válidas operações como:
Podemos compor uma string de operação SQL de maneiras diferentes utilizando soci::use para associar dados de variáveis locais a string resultante, como no exemplo seguinte:
Também podemos recuperar os dados resultantes de consultas de maneiras distintas. Operações que retornam apenas um valor podem ser especificadas assim:
Para recuperação de múltiplos registros podemos recuperar registros seqüencialmente utilizando a classe soci::statement e seus métodos execute e fetch, como o código seguinte:
Outro método para recuperação de dados de múltiplos registros utiliza-se do objeto soci::row, que funciona de maneira parecida a um vetor STL, operando com iterador. Seu funcionamento segue um padrão parecido ao presente em outras ferramentas, por isso não trataremos desse método aqui.
Há também um método que consideramos muito simples e prático baseado na classe tuple da biblioteca BOOST [11], consulte a página oficial de SOCI para informações sobre o uso desse método[2].

## DBIxx
### Introdução

DBIxx [3] , assim como GDAmm, também é um wrapper, que no caso, encapsula a biblioteca DBI [9] . Inspirada na sintaxe da biblioteca SOCI [3], DBIxx também oferece ferramentas de fácil utilização para criação de consultas SQL e tratamento de dados. É uma difícil decisão de projeto escolher entre a adoção de DBIxx e SOCI, já que as mesmas têm API's extremamente semelhantes. DBI (e conseqüentemente DBIxx) opera sobre Firebird, Interbase, MySQL, PostgreSQL, Sqlite3, alem de MS SQL e Sybase através da biblioteca FreeTDS [10].

### Principais Componentes

Parte considerável dos objetos de DBIxx tem correspondente na API de SOCI, às vezes utilizando o mesmo nome. Tendo SOCI como referencia, o exemplo abaixo é praticamente auto-explicativo.
using namespace dbixx; using namespace std;
Ao primeiro olhar percebemos uma sintaxe ligeiramente diferente para composição de strings de instruções SQL, alem necessidade de chamar o método exec parar efetivamente realizar as operações, mas percebemos também a sintaxe básica de SOCI.
Para realizar a conexão com o banco, temos um objeto de mesmo nome, mas com passagem de parâmetros ligeiramente diferente:
O uso de intratores para especificar instruções SQL ao objeto de conexão:
E um mecanismo de recuperação de dados parecido com o utilizado através das classes soci::statement e statement.fech de SOCI, utilizando o objeto dbixx::result juntamente com método result.next:

## Outras ferramentas

CppDB: http://art-blog.no-ip.info/sql/cppdb/intro.html
Outra ferramenta claramente inspirada em SOCI. Teve ultimo release em 2011 e, em principio, pode ser uma ferramenta viavel, necessita de estudo e teste. Opera sobre MySQL, PostgreSQL, Sqlite3 e ODBC, nas plataformas Linux e Windows.
QT http://qt.nokia.com
QT é um framework de desenvolvimento multiplataforma. Fornece uma grande quantidade de funcionalidades diversas, incluindo camada de abstração de acesso a banco de dados e componentes graficos (widgets) para apresentação de dados resultantes de consultas ao banco da dados, utilizando a arquitetura MVC.
GQL http://gql.sourceforge.net/drivers.html
GQL suporta os bancos de dados MySQL, PostgreSQL e Sqlite, sua documentação é muito precaria, sabemos que utiliza glib e seu ultimo release foi feito em 2003 (obsoleto?)
DTL http://dtemplatelib.sourceforge.net/
Database Templete Library é baseada em ODBC e containeres SQL. Solução a ser considerada se voce prefere tratar tados como containeres e não se importa em estar limitado ao uso de ODBC.
SPTK http://www.sptk.net/index.php
Simply Powerfull Toolkit é uma biblioteca de abstração associada ao toolkit grafico fltk [12] e fornece componentes de conexao, operacao e tratamento de dados no acesso a servidores de banco de dados, fornecendo componentes graficos para visualização e edição de dados utilizando os componentes do toolkit gráfico FLTK. Infelizmente essa ferramenta é bem pouco documentada, o que dificulta sua análise.
OUTRAS...
Certamente existem outras bibliotecas de código aberto para abstração de acesso a bancos de dados disponiveis, procuramos citar as mais relevantes. Lembre-se que foram consideradas apenas ferramentas multiplataforma de código aberto para linguagem C++ que operam sobre multiplos backends. Ferramentas que operam sobre apenas um backend, como mysql++, foram desconsideradas. Gostariamos de lembrar que esse documento é um ensaio, você pode contribuir com alterações, correções e extenções atraves do mecanismo Wiki em:

## Referências

[1] (libgda) http://developer.gnome.org/libgda/4.2/
[2] (soci) http://soci.sf.net
[3] (DBIxx) http://art-blog.no-ip.info/wikipp/en/page/ref_dbixx
[4] (GTKmm) http://www.gtkmm.org/
[5] http://en.wikipedia.org/wiki/Type_system#Dynamic_typing
[6] http://developer.gnome.org/gobject/stable/chapter-gtype.html
[7] http://en.wikipedia.org/wiki/GObject
[8] http://ftp.gnome.org/pub/GNOME/sources/libgdamm/
[9] http://libdbi.sourceforge.net/
[10] http://freetds.sourceforge.net/
[11] http://www.boost.org/doc/libs/1_35_0/libs/tuple/doc/tuple_users_guide.html
[12] http://fltk.org