terça-feira, 3 de julho de 2012

Usando SQLite em aplicações Visual Studio C++ 2010


Neste tutorial estarei demonstrando como configurar a biblioteca sqlite3 para acessar o banco de dados com SQLite.

Você pode acessar um banco de dados SQLite em qualquer sistema operacional, Windows, Linux ou Mac com suporte para as arquiteturas x86 e x64. Para este tutorial estarei utilizando a arquitetura x86 e sistema operacional Windows, já que o Visual Studio existe apenas para o Windows.

Antes de codificar o exemplo deste tutorial é necessário realizar algumas configurações de projeto que são descritas a seguir. 

Para seguir neste tutorial é necessário possuir instalado em seu computador o Microsoft Visual Studio C++ Express: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express
Para configurar siga os seguintes passos:
  • Faça o download da DLL no endereço: http://www.sqlite.org/sqlite-dll-win32-x86-3071300.zip
  • Descompacte o arquivo em sua pasta de preferência, neste exemplo descompactei no diretório criado na raiz principal do Windows, chamado SQLite. Após descompactar serão visualizados dois arquivos: sqlite3.def e sqlite3.dll.
  • Abra o Visual Studio Command Prompt (2010) pelo menu iniciar ou acesse pelo prompt de comando, vcvarsall.bat x86, que se encontra no diretório de instalação do Visual Studio 2010, no meu caso esta no seguinte diretório: C:\Program Files\Microsoft Visual Studio 10.0\VC\. O comando vcvarsall.bat é utilizado para configurar o ambiente Microsoft Visual Studio 2010 para ser utilizado via prompt de comando.
  • Acesse o diretório onde foi descompactado os arquivos sqlite3.def e sqlite3.dll.
  • Agora vamos criar o arquivo necessário para utilização com o Visual Studio, sqlite3.lib, para isso digite o seguinte comando: lib /DEF:sqlite3.def. Após a execução do comando será exibida a mensagem no console conforme a figura 1.1 abaixo, indicando que foi gerado com sucesso os arquivos sqlite3.lib e sqlite3.exp.


Figura 1.1 – Mensagem no prompt após geração do arquivo
  • Agora faça o download do arquivo contendo o código fonte do SQLite utilizado para codificar é acessar a base de dados: http://www.sqlite.org/sqlite-amalgamation-3071300.zip.
  • Descompacte o arquivo em sua pasta de preferência, neste exemplo descompactei no diretório criado na raiz principal do Windows, chamado SQLite. Após descompactar serão visualizados quatro arquivos: shell.c, sqlite3.c, sqlite3.h e sqlite3ext.h. Os arquivos principais são: sqlite3.c e sqlite3.h. Esses arquivos que serão utilizados para criar uma aplicação com banco de dados em SQLite.
  • Após tudo configurado abra o Visual Studio 2010 C++ e escolha o template de projeto Win32 Console Application e defina o nome do projeto como ExemploSQLite e clique em Ok, na janela seguinte clique em Next, por fim na última janela do wizard selecione a opção Empty Project, figura 1.2.


Figura 1.2 – Wizard Projeto
  • Copie o arquivo de cabeçalho sqlite3.h para o seu projeto.
  • Agora devemos configurar a biblioteca sqlite3.lib gerada anteriormente. Acesse as propriedades do seu projeto é configure o diretório onde se encontra o arquivo em Additional Library Directories, conforme a figura 1.3.

Figura 1.3 – Configurando o diretório da biblioteca sqlite3.lib

  • Por fim, na opção Input, clique no item Additional Dependencies e adicione o nome da biblioteca, sqlite3.lib , conforme a figura 1.4.

Figura 1.4 – Adicionando a biblioteca sqlite3.lib


Testando a aplicação

Após toda a configuração do projeto crie um arquivo chamado main.cpp. Para criar, clique com o botão direito na pasta  Source File do SolutionExplorer, logo em seguida New Item... -> Add, na janela seguinte selecione o template C++ File (.cpp) e defina o nome do arquivo como main.


Figura 1.5 – Adicionando arquivo main.cpp

No arquivo main.cpp adicione o seguinte código da listagem 1.1.

#include < ios >
#include < iostream >
#include < tchar.h >
#include "sqlite3.h"

using namespace std; 

void pausa();

int _tmain(int argc, _TCHAR* argv[])
{
 //Handler (manipulador) que representa o banco de dados. 
 //Para cada conexão com banco de dados deve-se criar uma variável do tipo sqlite3
 sqlite3 *db;

 char *error; //Variável utilizada para armazenar mensagens de erro

 cout << "Abrindo o banco de dados DADOS.db ..." << endl; 

 //Abrindo conexão com o banco de dados e verificando se a conexão foi realizada com sucesso
 if (sqlite3_open("DADOS.db", &db) == 0)
 {
  cout << "Conexão realizada com sucesso\n";
 }
 else
 {
  cerr << "Erro ao abrir o banco de dados SQLite3: " << sqlite3_errmsg(db) << endl << endl;
  sqlite3_close(db);   
  return 1;
 } 

 pausa();

 return 0;
}

void pausa()
{
 cout << "\nPressione qualquer tecla para continuar...";
 cin.get();
 cout << "\n";
}
Listagem 1

Agora execute a aplicação. Observe que após executar o programa uma mensagem de erro será exibida, figura 1.6. Esse erro acontece, pois o aplicativo não esta encontrado a DLL sqlite3.dll que é necessária para utilização do banco de dados. Para corrigir esse problema é necessário copiar o arquivo sqlite3.dll para o diretório onde se encontra o executável do programa.

Ao compilar o Visual Studio cria uma pasta no diretório do projeto chamado Debug ou Release de acordo com a opção de compilação, é nestas pastas que o executável é gerado, e a DLL deve estar neste mesmo diretório para que a aplicação consiga executar normalmente.


Figura 1.6 – Erro aplicação

Após adicionar a DLL no diretório a aplicação é executa normalmente. Um detalhe muito importante é que se o banco de dados não for encontrado o programa cria automaticamente.


Figura 1.7 – Aplicação executando normalmente

A listagem 2 possui o código completo da aplicação que demonstra como criar o banco de dados, tabelas, povoar as tabelas e retorna os dados a partir de uma consulta SQL.

#include < ios >
#include < iostream >
#include < tchar.h >
#include "sqlite3.h"

using namespace std; 

void pausa();

int _tmain(int argc, _TCHAR* argv[])
{
 //Handler (manipulador) que representa o banco de dados. 
 //Para cada conexão com banco de dados deve-se criar uma variável do tipo sqlite3
 sqlite3 *db;

 char *error; //Variável utilizada para armazenar mensagens de erro

 cout << "Abrindo o banco de dados DADOS.db ..." << endl; 

 //Abrindo conexão com o banco de dados e verificando se a conexão foi realizada com sucesso
 if (sqlite3_open("DADOS.db", &db) == 0)
 {
  cout << "Conexão realizada com sucesso\n";
 }
 else
 {
  cerr << "Erro ao abrir o banco de dados SQLite3: " << sqlite3_errmsg(db) << endl << endl;
  sqlite3_close(db);   
  return 1;
 } 

 //Criando uma tabela no banco de dados
 cout << "Criando a tabela USUARIO" << endl;

 const char *sqlCreateTable = "CREATE TABLE USUARIO (CODIGO INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, NOME VARCHAR(100), LOGON VARCHAR(15), SENHA VARCHAR(15)  );";

 if (sqlite3_exec(db, sqlCreateTable, NULL, NULL, &error) != 0)
 {
  cerr << "Erro ao executar o comando SQL: " << sqlite3_errmsg(db) << endl << endl;
  sqlite3_free(error); //libera recursos
 }
 else
 {
  cout << "Tabela criada com sucesso\n";
 }  

 pausa();

 //Inserindo dados
 cout << "Inserindo dados na tabela usuário" << endl;
 
 const char *sqlInsert = "INSERT INTO USUARIO VALUES(NULL, 'Paulo Vinícius', 'paulovinicius', '123456');";
 
 if (sqlite3_exec(db, sqlInsert, NULL, NULL, &error) != 0)
 {
  cerr << "Erro ao executar o comando SQL: " << sqlite3_errmsg(db) << endl << endl;
  sqlite3_free(error); //libera recursos
 }
 else
 {
  cout << "Registro inserido com sucesso\n";
 }

 pausa();

 //Retornando dados
 cout << "Retornando dados da tabela" << endl;

 const char *sqlSelect = "SELECT CODIGO, NOME, LOGON, SENHA FROM USUARIO";

 char **resultado = NULL; //Armazena o resultado da consulta SQL

 int linhas = 0;   //quantidade de linhas retornados da consulta
 int colunas = 0;  //quantidade de colunas retornados da consulta

 if (sqlite3_get_table(db, sqlSelect, &resultado, &linhas, &colunas, &error) != 0)
 {
  cerr << "Erro ao executar o comando SQL: " << sqlite3_errmsg(db) << endl << endl;
  sqlite3_free(error); //libera recursos
 }
 else
 {
   
  //Percorrendo as linhas e colunas do retorna da consulta
  //OBS: A primeira linha do resultado são os nomes da colunas
  for (int lin = 0; lin <= linhas; ++lin)
  {
         
   for (int col = 0; col < colunas; ++col)
   {
    
    //Determinando a posição da celular
    int cellPosition = (lin * colunas) + col; 

    //Definindo o tamanho do contéudo que será impresso na tela
    cout.width(15);
    cout.setf(ios::left);
    cout << resultado[cellPosition] << " ";

   } 
         
   cout << endl;

   // Imprime um separador para o cabeçalho
   if (0 == lin) //Primeira linha
   {
    
    for (int colCtr = 0; colCtr < colunas; ++colCtr)
    {
     cout.width(15);
     cout.setf(ios::left);
     cout << "--------------- ";
    }

    cout << endl;
   }

  }

 } 
 
 //liberando recursos
 sqlite3_free_table(resultado);
 
 cout << "Fechando DADOS.db ..." << endl;
 sqlite3_close(db); 
   
 pausa();

 return 0;

}

void pausa()
{
 cout << "\nPressione qualquer tecla para continuar...";
 cin.get();
 cout << "\n";
}   
Listagem 2

2 comentários:

  1. Paulo:
    estava procurando um exemplo de utilização de SQLite no Visual Studio C++ 2010 e que bela surpresa: me deparei com este "curso" rápido, sucinto e criativo. Estudado, testado e executado me poupou horas de "tentativas & erros".
    Parabéns pelo tutorial.
    Lopes, JB.

    ResponderExcluir
    Respostas
    1. Muito Obrigado Lopes. Que bom que este tutorial ajudou você. Alguns meses antes de escrever esse tutorial também esta enfrentando problemas ao trabalhar com sqlite com C++, no final, consegui trabalhar com sqlite e resolvi escrever o tutorial para ajudar quem precisar.

      Excluir