quarta-feira, 28 de setembro de 2011

Campo auto incremento no Firebird usando isql (Generator + Trigger)


Hoje vamos criar um campo auto incremento usando Generator e Trigger no Firebird, com o isql.

O que faremos é o seguinte, criar um GENERATOR para armazenar um valor para o campo ID da tabela depois um Gatilho para alterar o novo valor de ID quando inserirmos o registro.

Vamos abrir um terminal como root no Linux ou o Prompt de comando no Windows.

Abra a ferramenta isql com o comando

# no Linux
isql-fb


Agora vamos criar o banco de dados:

CREATE DATABASE “/home/alex/firebird_data/tutorial2.fdb” user “SYSDBA” password “senha”;

Criamos também a tabela:

CREATE TABLE TESTE_AI(
ID INTEGER NOT NULL PRIMARY KEY,
NOME VARCHAR(50) NOT NULL,
IDADE INTEGER NOT NULL
);

Agora vamos à criação do GENERATOR que controlará o auto incremento de ID.

CREATE GENERATOR GEN_ID_TESTE_AI;

O comando para a criação de Generators é simples:

CREATE GENERATOR NOME_GENERATOR;

Eu costumo usar GEN + Nome do campo + tabela, mas fica a cargo de cada um a escolha deste nome.

Agora vamos criar um Gatilho que vai incrementar o valor do ID.

Antes, vamos alterar o terminador padrão, que é “;” para outro caractere que não será usado no bloco de código do gatilho, no caso vou colocar um “!”. Qualquer outro caractere pode ser usado, mas você deve ter muito cuidado aqui, pois se usar algum que apareça no meio do caminho, seu comando será fechado e todo seu trabalho será perdido.

Usamos o comando SET TERM + o novo caractere que usaremos (no caso o “!”) e fechamos com o caractere terminador atual, no caso o “;”.

SET TERM !;

CREATE TRIGGER T_G_ID_TESTE_AI
FOR TESTE_AI
ACTIVE
BEFORE INSERT
POSITION 0
AS
BEGIN
     NEW.ID = GEN_ID(GEN_ID_TESTE_AI, 1);
END!


Nesta primeira linha crio o Gatilho, dando um nome para ele, no caso, usei o T (trigger) + G (porque ele está associado a um Generator), + Campo + Tabela).

CREATE TRIGGER T_G_ID_TESTE_AI

Na segunda linha uso o FOR para mostrar a qual tabela ele está relacionado, no caso TESTE_AI.

FOR TESTE_AI

Digo que quero que este Gatilho esteja ativado.

ACTIVE

Ele será executado antes de Inserir, quando executamos o comando Insert, antes dos dados serem salvos no banco, ele executa este comando.

BEFORE INSERT

Agora digo que ele será o primeiro a ser executado, isto é preciso quando temos mais de um gatilho sendo executado no mesmo ponto de alteração, então se eu tivesse outro gatilho nesta tabela para ser executado em BEFORE INSERT, eu uso este comando para controlar o fluxo de execução. POSITION 0 para o primeiro, POSITION 1 para o segundo, etc...

POSITION 0

Inicio o bloco de comandos

AS
BEGIN

Altero o valor do novo ID para o valor armazenado no Generator incrementando 1 ao mesmo usando GEN_ID.

Veja que aqui nesta linha, eu preciso fechá-la com o “;”, se não tivéssemos alterado o terminador de linha, o comando SQL seria fechado neste momento de forma incompleta e perderíamos todo o trabalho.

NEW.ID = GEN_ID(GEN_ID_TESTE_AI, 1);

Agora fecho o comando, veja que para fechar o comando SQL, agora eu uso o novo terminador que escolhemos no início do comando.

END!

Para não mantermos este terminador para os próximos comandos voltamos o mesmo para o “;”.

SET TERM ;!

Vamos testar o comando inserindo alguns valores:

INSERT INTO TESTE_AI VALUES(NULL, 'TESTE', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE1', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE2', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE3', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE4', 20);

Agora selecione os valores.

SELECT * FROM TESTE_AI;

Se alguma coisa der errada, tente refazer cada passo, entendendo o porque de cada comando.

Até a próxima.

terça-feira, 27 de setembro de 2011

Erro no Debian, wrong fs type, bad option, bad superblock on /dev/sdb1...

Após instalar o Debian 6.0 squeeze, eu fui montar uma das partições de um segundo HD que tenho no computador e este erro apareceu:

wrong fs type, bad option, bad superblock on /dev/sdb1,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail  or so.


Dei uma olhada no /etc/fstab e pra minha surpresa encontrei esta linha:

/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto     0       0

Vejam que no fstab, sdb1 está configurado como um cdrom...

Quando fiz minha primeira instalação do Debian, eu havia usado um CD como mídia, e isto não havia ocorrido, desta vez, eu usei o netinstall e não usei o CD como mídia, e sim um pendrive...

Para conseguir corrigir isto, apenas comentei esta linha no fstab:

Abra o terminal como root:

nano /etc/fstab

Comente a linha indicada:

#/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto     0       0

F2 para salvar

CTRL + X para sair

Pode fazer a mesma coisa com o gedit ou outro editor de texto que vocês possuam aí.

Tente montar o HD novamente, se não conseguir, tente Reiniciar e montar novamente.

Espero ter ajudado.

quinta-feira, 15 de setembro de 2011

A lista com todos os links do tutorial de wxWidgets + sqlite3

Configurações

Tutorial wxWidgets e sqlite3 parte 1 – Configurando sqlite3 no Windows

Tutorial wxWidgets e sqlite3 parte 4 – Compilando wxSqlite3 no Linux

Tutorial wxWidgets e sqlite3 parte 5 - Iniciando com o exemplo


Criando um banco de dados

Tutorial wxWidgets e sqlite3 parte 2 – Criando um banco de dados pelo prompt de comando.

Tutorial wxWidgets e sqlite3 parte 3 – Criando um banco de dados pelo Black Cat - SQLite3 database manager


Sistema em si

Tutorial wxWidgets e sqlite3 parte 6 - Criando o Projeto e a Interface do programa

Tutorial wxWidgets e sqlite3 parte 7 - Comunicando-se com um banco de dados

Tutorial wxWidgets e sqlite3 parte 8 - Criando um banco de dados e a tabela contatos

Tutorial wxWidgets e sqlite3 parte 9 - Inserindo valores no banco de dados

Tutorial wxWidgets e sqlite3 parte 10 - Selecionando valores e colocando em um wxGrid

Tutorial wxWidgets e sqlite3 parte 11 - Passando os dados do wxGrid para a edição

Tutorial wxWidgets e sqlite3 parte 12 - Limpando os Campos após alterações e aproveitando para acertar algumas coisas...

Tutorial wxWidgets e sqlite3 parte 13 - Editando valores no banco de dados

Tutorial wxWidgets e sqlite3 parte 14 - Excluindo registros


O download do código fonte comentado você pode fazer aqui.

Tutorial wxWidgets e sqlite3 parte 14 - Excluindo registros

Para finalizar o sistema, vamos escrever a função para deletar os registros.

Ela vai funcionar da seguinte maneira:

Vamos criar uma função que vai receber o ID do registro que está sendo editado, vamos passar este ID para um comando SQL, vamos chamar ExecuteUpdate(SQL).

Escreva a função:

sqlf.h
//Função para deletar um registro...
//Passo como parâmetro o ID do registro que será deletado...
void DeleteInDB(wxString ID);

sqlf.cpp
void DeleteInDB(wxString ID)
{
    //Abro o banco de dados
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //SQL para deletar o registro...
    wxString SQL = wxT("DELETE FROM contatos WHERE ID=") + ID + wxT(";");

    //ExecuteUpdate para deletar o registro...
    db->ExecuteUpdate(SQL);

    //Fecho db...
    CloseDB(db);
}

Agora vamos chamar esta função no frame principal, na função OnClickDelete.

Nó vamos confirmar com o usuário se ele quer mesmo que delete o registro, depois deletamos o registro.

framep.cpp
//Aqui o evento quando eu clicar no botão deletar...
void wxFramePrincipal::OnClickDeletar(wxCommandEvent& event)
{
    //Vamos verificar também se o registro está em modo de edição...
    //Pois se não estiver, não teremos quem deletar lá no banco de dados...
    if(ID == -1)
        return;

    //Vamos perguntar primeiro se o usuário tem certeza que quer deletar o registro...
    int confirma = wxMessageBox(wxT("Tem certeza que quer deletar o registro?"), wxT("Confirmação"), wxYES_NO);

    //Se o usuário clicar em não, cancelo a função...
    if(confirma == wxNO)
        return;

    //Executo a função para deletar o registro...
    DeleteInDB(wxString::Format(wxT("%d"), ID));

    //Após deletarmos um registro atualizamos o wxGrid lista contatos...
    SelectInDB(lista_contatos);

    //E limpamos os campos de edição...
    LimparCampos();
}

Pronto, o sistema está completo, agora vocês podem refazer o mesmo, adicionando novas funcionalidades, adicionando outros campos, tabelas, etc...

Espero que tenham aproveitado a sequencia de tutoriais sobre wxWidgets e sqlite3 usando a biblioteca wxSqlite3.

Até a próxima.

quarta-feira, 14 de setembro de 2011

Tutorial wxWidgets e sqlite3 parte 13 - Editando valores no banco de dados

A edição de dados vai ser feita com base na função de inserção de dados, para isto criaremos a mesma nos arquivos sqlf.* do projeto.

Como ela irá funcionar:

Nó passaremos como parâmetros, o ID do registro que está sendo editado, para fazermos o controle na cláusula WHERE do SQL, passaremos também o nome que foi editado e a idade.

Antes de executarmos qualquer alteração verificamos se os dados são válidos, se não estão em branco ou se idade é realmente um número.

O comando usado aqui será o ExecuteQuery(), o mesmo usado na inserção dos dados.

Vamos escrever.

No arquivo sqlf.h digite:

sqlf.h
//Aqui a função para editar os dados...
void UpdateDB(wxString ID, wxString nome, wxString idade);

No arquivo sqlf.cpp:

sqlf.cpp
void UpdateDB(wxString ID, wxString nome, wxString idade)
{
    //Primeiro vejo se o nome ou idade estão em branco
    if(nome.IsEmpty() || idade.IsEmpty())
    {
        //Aviso ao usuário que algum dado está em branco:
        wxMessageBox(wxT("Nenhum campo pode estar em branco!"));
        //Cancelo a função...
        return;
    }

    //Agora preciso ver se a idade é um número...
    //Crio um long int
    long int confere_idade;

    //Tento converter a string idade em um número...
    if(!idade.ToLong(&confere_idade))
    {
        //Se não conseguir, significa que ele não é um inteiro...
        //Aviso o usuário...
        wxMessageBox(wxT("O valor da idade (") + idade + wxT(") não é um número"));
        //Cancelo a função...
        return;
    }

    //Se chegamos até aqui, é porque tudo está correto...
    //Vamos abrir o banco de dados:
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //Agora vamos montar o sql para editar os dados...
    wxString SQL = wxT("UPDATE contatos \n");
    SQL += wxT("SET NOME = '") + nome + wxT("',\n");
    SQL += wxT("IDADE = ") + idade + wxT("\n");
    SQL += wxT(" WHERE ID = ") + ID + wxT(";");

    //Agora executo a função ExecuteUpdate, que vimos no tutorial inserir, passando como
    //parâmetro a wxString SQL...
    db->ExecuteUpdate(SQL);

    //Fecho db...
    CloseDB(db);
}


Agora vamos chamar a mesma em framep.cpp:

framep.cpp
if(ID == -1)
    {
        //Se a variável ID for = -1, é porque estamos em inserção...
        //E passamos as duas como parâmetros para a função InsertInDB()...
        InsertInDB(get_nome, get_idade);
    }
    else
    {
        //Pegamos o valor do ID...
        wxString get_id = wxString::Format(wxT("%d"), ID);
        //Passamos como parâmetros, para a função...
        UpdateDB(get_id, get_nome, get_idade);
    }


Pequenas alterações que fiz na GUI do sistema.

framep.cpp
//Adicionei um tamanho padrão para a janela...
this->SetSize(wxSize(450, 350));

//Adiciono o box dos botões ao box principal...
//Aqui arrumei o tamanho do sizer dos botões em relação
//a janela e dei um espaço de 10px na base
boxp->Add(box_btns, 0, wxEXPAND|wxBOTTOM, 10);

Estamos quase terminando nosso sistema, falta apenas implementar a função de deletar...

Até a próxima.

Tutorial wxWidgets e sqlite3 parte 12 - Limpando os Campos após alterações e aproveitando para acertar algumas coisas...

Nesta parte do tutorial, iremos implementar a função LimparCampos(), do arquivo framep.cpp.

O que ela irá fazer?

1 – Vai alterar o valor de ID para -1, ou seja, cancelar a edição...
2 – Vai limpar o campo nome.
3 – Vai limpar o campo idade.
4 – Alterar o título da janela para modo de inserção.

O código vai ficar assim:

Digite o seguinte em framep.cpp

framep.cpp
//Esta função eu vou usar para limpar os campos
//como eu precisarei fazer isto sempre que eu completar uma alteração
//vou escrever este código em uma função em separado...
void wxFramePrincipal::LimparCampos()
{
    //A função mais simples de todas...
    //Será usada na criação do frame.
    //Na função OnClickSalvar
    //Na função OnClickLimpar
    //e na função OnClickDeletar

    //Primeiro vamos alterar o valor do ID para -1
    //Para voltarmos ao modo de Inserção...
    ID = -1;

    //Agora limpamos o nome...
    nome->Clear();

    //limpamos o campo idade...
    idade->Clear();

    //Alteramos o valor da janela para modo de Inserção...
    this->SetTitle(wxT("Teste Tutorial Sqlite3 - Modo de Inserção"));
}

Agora vamos chamá-la no final da criação do frame principal:

    boxp->Add(box_btns, 1, wxEXPAND, 0);

    //"Digo" ao meu frame que o boxp é o box principal...
    this->SetSizer(boxp);

    //Aqui apenas faço com que tudo seja arranjado de maneira correta...
    this->Layout();

    //Aqui chamo a função limpar campos...
    LimparCampos();

    //Vamos carregar os dados no grid...
    SelectInDB(lista_contatos);
}

Também no final da função OnClickSalvar

    }

    //Após editarmos um valor, recarregamos os valores no grid...
    SelectInDB(lista_contatos);

    //E também limpamos os valores de edição/inserção...
    LimparCampos();
}

Aproveitamos para implementar a função OnClickLimpar

//Aqui o evento que vai limpar os campos...
void wxFramePrincipal::OnClickLimpar(wxCommandEvent& event)
{
    //Chamamos a função LimparCampos()...
    LimparCampos();
}

E adiantamos algumas coisas na função OnClickDeletar

//Aqui o evento quando eu clicar no botão deletar...
void wxFramePrincipal::OnClickDeletar(wxCommandEvent& event)
{
    //Vamos verificar também se o registro está em modo de edição...
    //Pois se não estiver, não teremos quem deletar lá no banco de dados...
    if(ID == -1)
        return;

    //Após deletarmos um registro atualizamos o wxGrid lista contatos...
    SelectInDB(lista_contatos);

    //E limpamos os campos de edição...
    LimparCampos();
}


Vejam que tínhamos uma função chamada ConfereCampos em framep.h e framep.cpp, por descuido, acabei implementando isto na função de inserir registros de sqlf.cpp, para não enrolarmos a continuidade do tutorial, deletem esta função ConfereCampos dos dois arquivos, o *.h e o *.cpp.

Mais uma parte do tutorial concluída, no próximo iremos finalizar o código do tutorial.

Até a próxima.

Tutorial wxWidgets e sqlite3 parte 11 - Passando os dados do wxGrid para a edição

Hoje vamos escrever a função do duplo click no wxGrid.

O objetivo desta função é:

Ao clicar duas vezes em alguma célula do wxGrid lista_contatos, pegaremos a linha que foi clicada, depois passaremos os valores do ID, NOME e IDADE para seus respectivos valores de edição que são:

A variável ID que vai controlar se estamos em modo de edição ou não, se for em modo de edição qual registro que está sendo editado.

A caixa de texto nome.

A caixa de texto idade.

Vamos ao código:

Em framep.cpp, altere a seguinte parte:

framep.cpp
//Aqui o evento que será executado
//quando eu der 2 cliques em uma célula...
void wxFramePrincipal::OnDoubleClickCell(wxGridEvent& event)
{
    //Primeiro vamos pegar o índice da linha que está sendo clicada:
    int row = event.GetRow();

    //Agora vamos passar os valores desta linha para nossos dados...

    //Primeiro a variável ID
    long int get_id;
    lista_contatos->GetCellValue(row, 0).ToLong(&get_id);

    ID = get_id;
    //Veja que neste momento, a varável ID assume um valor maior que -1
    //Então entramos no modo de edição...

    //Agora pego o valor atual para nome...
    nome->SetValue(lista_contatos->GetCellValue(row, 1));

    //E por último a idade...
    idade->SetValue(lista_contatos->GetCellValue(row, 2));

    //Agora podemos fazer as alterações dos valores, passando como parâmetro
    //o valor do ID...

    //Uma alteração que podemos fazer também é
    //colocar um aviso no título da janela
    //para dizer ao usuário qual a função que ele está executando:

    this->SetTitle(wxT("Teste Tutorial Sqlite3 - Modo de Edição"));
}

Pronto, agora o usuário poderá selecionar qual registro ele quer editar.

No próximo tutorial, implementar a função que limpa os campos após as edições.

Até a próxima.