março 2010 março 2010 índice Delphi Delphi Editorial 04 Espero que nesse mês todos tenham recebido muitos ovinhos do coelhinho. Quem não recebeu seja um bom menino... Banco de Dados 14 05 Utilizando componentes ABCr no Delphi 2010 Autor: Antonio Spitaleri Autor: Antonio Spitaleri Banco de Dados 19 Indo mais além eplorando as tabelas de sistema Interbase/Firebird Stored Procedures e Triggers no MySQL Autor: Felipe Santos Autor: Bruno Alcarás Dicas - Dicas Delphi 10 Manipulando Streams no Delphi 2010 .NET 24 Novidades do Visual Studio 2010 Autor: Djonatas Tenfen Desafio The Club 28 - Cruzada 30 Legenda Iniciante Intermediário Avançado março 2010 03 Bem-vindo Espero que nesse mês todos tenham recebido muitos ovinhos do coelhinho. Quem não recebeu seja um bom menino ou menina que no próximo ano ele vem. Aproveito para convidar nossos leitores a comparecerem ao “Microsoft TechDay” que será realizado em Blumenau-SP no dia 24/04 e que tem com um dos idealizadores nosso colunista Djonatas Tenfen. O The Club tem prazer em apoiar essa iniciativa. Tenho certeza que será um grande evento. Saiba mais acessando: www.mstechday.com Av. Profº Celso Ferreira da Silva, 190 Jd. Europa - Avaré - SP - CEP 18.707-150 Informações: (14) 3732-1529 Suporte: (14) 3733-1588 Internet http://www.theclub.com.br Cadastro: [email protected] Suporte: [email protected] Informações: [email protected] Skype Cadastro: theclub_cadastro Skype Suporte: theclub_linha1 theclub_linha2 theclub_linha3 Nessa edição temos artigos pra todos os gostos. Nosso consultor técnico Antonio Spitaleri Neto trabalha dobrado esse mês e nos apresenta dois artigos. No primeiro, ”Manipulando Streams no Delphi 2010”, ele fala sobre um recurso presente no Delphi desde o seu início, os Streams, e que apesar de ser pouco utilizado nos dias de hoje, pode ser muito importante para alguns pontos específicos dos nossos aplicativos. No segundo, ”Utilizando os Componente ACBr com Impressoras Fiscais no Delphi 2010” ele fala sobre os componentes Open Source ACBr que são uma verdadeira “mão na roda” para nós desenvolvedores trabalharmos com ECF. Iniciando as páginas dedicadas a Banco de Dados dessa edição, Felipe Santos com seu artigo “Indo mais além, explorando as tabelas de sistema Interbase/ Firebird” nos mostra como trabalhar com as tabelas de sistema do Interbase/ Firebird visando uma melhor manutenção dos nossos Bancos de Dados. Nosso consultor Jr. Bruno Alcarás neste mês nos trás o artigo “Stored Procedure e Triggers no MySQL”, nos dando uma visão geral sobre esses ótimos recursos que são mais conhecidos em Banco de Dados Firebird mas que também tem um papel muito importante no desenvolvimento de um Banco MySQL. Djonatas Tenfen no seu artigo “Novidades do Visual Studio 2010” nos apresenta as principais novidades dessa nova versão do Visual Studio que foi oficialmente lançado no dia 12/04. www.twitter.com/theclubbr Copyright The Club Megazine 2009 Diretor Técnico Marcos César Silva Diagramação e Arte Vitor M. Rodrigues Revisão Tassiane Fileto Colunistas Antonio Spitaleri Neto Bruno Alcarás Djonatas Tenfen Felipe Santos Impressão e acabamento: GRIL - Gráfica e Editora Taquarituba-SP - Tel. (14) 3762-1345 Reprodução A utilização, reprodução, apropriação, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criações intelectuais em cada publicação da revista “The Club Megazine” são terminantemente proibidos sem autorização escrita dos titulares dos direitos autorais. Um grande abraço Marcos César Silva - Editor Chefe [email protected] 04 março 2010 Delphi é marca registrada da Borland International, as demais marcas citadas são registradas pelos seus respectivos proprietários. Delphi Manipulando Streams no Delphi 2010 FileStream Entre os vários recursos que existem desde versões mais antigas do Delphi e ainda assim são pouco explorados pelos desenvolvedores especializados na ferramenta, sem dúvida um dos mais destacados são os Streams. Streams são objetos que remetem ao início dos tempos da programação, quando a manipulação de dados era feita byte a byte. Com o surgimento de novas tecnologias, a utilização dos Streams ficou restrita a situações em que os mesmos são imprescindíveis. Nesse artigo estarei abordando de forma prática o uso dos Streams utilizando a versão 2010 do Delphi. Porém os exemplos funcionam em versões anteriores do Delphi com pouca ou nenhuma modificação. Mãos a obra! Como o próprio nome já sugere, a classe TFileStream, descendente de TStream, manipula arquivos em disco na forma de Streams. Em geral utilizamos essa forma de Stream para manipular arquivos de texto, mas a utilização da mesma para outros tipos de arquivos é perfeitamente possível. Inicie uma nova aplicação no Delphi e monte o layout da mesma conforme a figura 1: No Delphi existe uma classe base TStream e dela descendem as demais classes de manipulação de Streams: TMemoryStream, TFileStream, TBlobStream. Essas três classes que citei são as mais importantes na manipulação de Streams em Delphi. Apesar de possuírem diferenças entre si, a forma de trabalhar com cada uma das três classes é bem semelhante. Figura 1 março 2010 05 O que faremos a seguir é carregar um arquivo texto para um objeto FileStream e em seguida carregar esse Stream no objeto Memo para exibição do mesmo. cionado, iremos realizar a carga do mesmo para o FileStream e exibir o conteúdo do mesmo no objeto memo que inserimos na aplicação. Segue o código: Quando criamos um objeto FileStream no construtor do mesmo temos de informar além do caminho do arquivo o modo de abertura desse arquivo. FileStream nos possibilita quatro formas de abertura que são: procedure TForm1. btnexibirClick(Sender: TObject); var Fmcreate- Caso o arquivo não exista, será criado. Caso exista, será zerado e a escrita no mesmo irá sobrescrever seu conteúdo atual; sFilename:string; oFileStream:TFileStream; try sFilename:=edtcaminho. Text; oFileStream:=TFileStream. Fmopenreadwrite- Abre o arquivo para leitura e escrita. Create(sFilename,fmOpenRead); memstream.Lines. LoadFromStream(oFileStream); finally O primeiro passo será a busca do arquivo com o OpenDialog, que será feita no evento OnClick do botão “Carregar”. end; end; btncarregarClick(Sender: Salve as alterações e teste o aplicativo. Se tudo correu bem, o resultado será semelhante ao mostrado na figura 2: TObject); var sFilename:string; begin if(OpenDialog1.Execute) then sFilename:=OpenDialog1. FileName; edtcaminho. Text:=sFilename; end; Com o caminho do arquivo devidamente selemarço 2010 Embora não seja o mais recomendado, todos os servidores de banco de dados utilizados com o Delphi aceitam o armazenamento de dados na forma binária através de campos Blob. Esse tipo de campo em geral é utilizado para o armazenamento de imagens no banco de dados, mas pode ser utilizado para armazenar vídeos, textos entre outros dados de forma binária. Para se trabalhar com campos Blob nos componentes DataSet existentes no Delphi, podemos lançar mão de mais duas classes: TBlobStream, para os componentes BDE, e TMemorystream ou a própria classe TStream para demais tipos de DataSets. Com essas classes poderão ser feitos o envio e recuperação de dados a partir de campos Blob. Lembrando que para o Stream independe se o campo Blob contém um texto, uma imagem ou outra forma de dado. Sua função é apenas servir de veículo para envio e recuperação dessas informações. FreeAndNil(oFileStream); Segue o código: procedure TForm1. Stream com imagens begin Fmopenread- Abre o arquivo apenas para leitura; Fmopenwrite- Abre o arquivo apenas para escrita; Veja a Figura 2. Figura 2 Vamos a um exemplo prático com Blob em combinação com outros dois objetos para carga de imagens. No PageControl de nossa aplicação, adicione uma nova página e coloque como caption da mesma “Blobstream”. Em seguida adicione a página um componente Clientdataset, alterando seu nome para CdsBlob. Abra o FieldsEditor do clientdataset e adicione campo Blob com o nome de IMAGEM. Isso feito clique com o botão direito sobre o clientdataset e clique em CreateDataSet. Nesse exemplo estarei trabalhando com o clientdataset apenas em memória, mas ele poderia estar ligado a uma fonte de dados sem problemas. Com o clientdataset devidamente criado e configurado, monte o restante do layout da página conforme a figura 3. Os outros dois objetos que estaremos utilizando são: TStream para a recuperação do conteúdo do Blob após o mesmo ter sido carregado. E TJpegImage para armazenar a imagem proveniente do campo Blob. Veja a Figura 3. Lembrando que o componente OpenDialog não precisa ser criado novamente, será utilizado o que já havíamos criado na primeira página. Iremos selecionar o caminho de uma imagem para em seguida enviá-lo para o Blobstream. Para a seleção do arquivo, no evento OnClick do botão “Selecionar” faça: procedure TForm1. SelecionarClick(Sender: TObject); begin OpenDialog1. Filter:=EmptyStr; OpenDialog1. Filter:=’Image Files|*. jpg’; Figura 3 procedure TForm1.SalvarClick(Sender: TObject); var sFilename:string; oFilestream:TFileStream; oMemorystream:TStream; oImage:TJPEGImage; begin try sFilename:=edtcaminhoimg.Text; oFilestream:=TFileStream. Create(sFilename,fmOpenRead); oMemorystream:=TMemoryStream.Create; oImage:=TJPEGImage.Create; cdsblob.Open; cdsblob.Append; cdsblobIMAGEM.LoadFromStream(oFilestream); cdsblob.Post; oMemorystream:=cdsblob.CreateBlobStream(cdsbl obIMAGEM,bmRead); oImage.LoadFromStream(oMemorystream); Image1.Picture.Assign(oImage); finally FreeAndNil(oFilestream); FreeAndNil(oMemorystream); FreeAndNil(oImage); end; Listagem 4 if(OpenDialog1.Execute) then edtcaminhoimg. Text:=OpenDialog1. seguida salvamos o caminho do arquivo de imagem na Edit edtcaminho. FileName; end; Alteramos o filtro do OpenDialog para que apenas aceite imagens com a extensão jpeg e em Como estamos trabalhando com imagens em formato Jpeg devemos adicionar na uses da unit a biblioteca Jpeg. Iremos agora salvar essa imagem já selecio- nada em um FileStream, salvá-la no campo blob e depois recuperá-la com a técnica do blobstream combinada com o Jpegimage. Veja a codificação no evento OnClick do botão “Salvar”: Veja a listagem 4. março 2010 07 Repare que o objeto TJpegImage apenas serve de container provisório para receber a imagem proveniente do campo Blob. Com essa técnica podemos salvar e recuperar imagens em qualquer DataSet que ofereça suporte aos campos Blob. Salve as alterações e teste o aplicativo. Um exemplo de resultado pode ser visto na figura 4: Veja a Figura 4. Figura 4 Trabalhando com buffers Quando trabalhamos com Streams é importante termos em mente que o conteúdo do Stream irá ocupar uma certa quantidade de memória no computador. Em algumas situações pode ser importante que tenhamos um controle mais preciso desse espaço e de como ele será manipulado. Esse maior controle pode ser conseguido com a técnica de “bufferização”, que consiste em alocar previamente um espaço de memória onde o buffer irá trabalhar. Algo semelhante ao que é feio com ponteiros em linguagens como C++. Antes de passarmos a prática com buffers, é importante destacar duas propriedades importantes de um Stream, que são: Size e Position. Size retorna um inteiro com o tamanho ocupado pelo Stream, e Position também retorna um inteiro com a posição atual do cursor de leitura do Stream. Assim como os datasets, Streams também possuem um cursor interno responsável pela leitura dos dados. Figura 5 Botão “Selecionar Arquivo”: procedure TForm1.btnarqselecionarClick(Sender: TObject); begin if(OpenDialog1.Execute)then edtcaminhoarq.Text:=OpenDialog1.FileName; Vamos a prática. Adicione uma nova página ao PageControl da aplicação e monte seu layout conforme a figura 5: end; Botão “Copiar”: Veja a Figura 5. Nesse exemplo iremos selecionar um arquivo texto, carregá-lo para um FileStream, em seguida copiá-lo para outro FileStream com a técnica da bufferização e exibir seu conteúdo no Memo. procedure TForm1.btncopiarClick(Sender: TObject); var oStreamin, oStreamout:TFileStream; aBufferstream:array[0..1023]of Byte; 08 março 2010 iByteRead:integer; sFilename:string; begin try ProgressBar1.Position:=0; sFilename:=edtcaminhoarq.Text; oStreamin:=TFileStream. Create(sFilename,fmOpenRead); oStreamout:=TFileStream.Create(‘temp. txt’,fmCreate); repeat iByteRead:=oStreamin. Read(aBufferstream,1024); oStreamout.Write(abufferstream,iByteRead); ProgressBar1.StepBy(1); until(iByteRead=0); finally ProgressBar1.Position:=100; FreeAndNil(oStreamin); FreeAndNil(oStreamout); Memo1.Lines.LoadFromFile(‘temp.txt’); end; end; Veja o aplicativo em execução na Figura 6: Veja a Figura 6. Conclusão Streams são um excelente recurso disponibilizado pelo Delphi quando necessitamos utilizar técnicas avançadas de manipulação de arquivos em disco sendo carregados em memória. Espero que tenham gostado e até a próxima! Figura 6 Sobre o autor Antonio Spitaleri Neto Consultor Técnico The Club. [email protected] março 2010 09 Utilizando os componentes ACBr com Impressoras Fiscais no Delphi 2010 No dia-a-dia do desenvolvimento voltado para a área de automação comercial, uma grande preocupação dos desenvolvedores é a comunicação do aplicativo com as chamadas impressoras fiscais, conhecidas pela sigla “ECF”. Para quem trabalha nesse ramo a algum tempo, a solução mais simples e comumente utilizada eram as dll’s dos próprios desenvolvedores da ECF utilizada. Outro ponto importante a se destacar no Acbr é o fato de utilizar muitos dos conceitos da orientação a objetos. Conceitos esses muito raramente utilizados quando se trata de aplicativos e bibliotecas desenvolvidos em Delphi. O fato de utilizar orientação a objetos tornou o código do ACBr mais legível e extensível e ao longo dos últimos anos várias melhorias tem sido aplicadas ao projeto. Recorrer a essas dll’s sem dúvida torna o trabalho de se comunicar com as ECF’s mais tranqüilo, porém apresenta um incoveniente: E se o modelo e\ou fabricante da ECF for trocada pelo cliente? Ou ainda se um cliente novo utilizar um modelo de um fabricante diferente? Para essas situações, se faz necessário readaptar o aplicativo para trabalhar com o novo modelo\fabricante de ECF. Nesse artigo, estarei mostrando como podemos utilizar o ACBr para fazermos nosso aplicativo se comunicar com uma impressora fiscal. Para os que não dispõem de uma impressora fiscal para testes, é importante ressaltar que o exemplo funciona com emuladores de ECF sem problemas. O projeto ACBr vem de encontro a esse problema. Esse conjunto de componentes e rotinas totalmente Open Source e desenvolvido em Delphi, permite que a aplicação que irá se comunicar com a ECF seja desenvolvida apenas uma vez, e a troca de modelo ou fabricante de componente deixa de ser um problema. No artigo não estarei mostrando a instalação dos componentes ACBr no Delphi 2010, já que instruções para instalação acompanham o componente. Também não será abordada no artigo a instalação e configuração de emuladores de ECF. Iniciando a aplicação Criaremos uma aplicação que irá realizar as principais operações relacionadas às impressoras fiscais, como por exemplo: Leitura X, Redução Z, além é claro das operações de registro de itens em uma venda. Veja como ficará o layout principal da aplicação na figura 1: No alto e a esquerda da tela, temos dois componentes ComboBox onde no primeiro iremos colocar na propriedade Items uma lista com os modelos suportados pelo Acbr. São eles: ecfNenhum, ecfNaoFiscal, ecfBematech, ecfSweda, ecfDaruma, ecfSchalter, ecfMecaf, ecfYanco, ecfDataRegis, ecfUrano, ecfICash, ecfQuattro, ecfFiscNET, ecfEpson, ecfNCR, ecfSwedaSTX; No segundo componente ComboBox, colocaremos uma lista com os nomes das portas COM disponíveis no computador. No exemplo fiz a lista com as portas COM1 até COM6. Logo abaixo dos componentes ComboBox, 10 março 2010 temos uma série de 7 botões que utilizaremos para efetuar as operações com a ECF. A função de cada botão pode ser vista nos captions de cada botão. No lado direito do formulário temos um componente PageControl com duas páginas. Na primeira colocamos um componente TMemo, que será ligado ao componente ACBrEcf através da propriedade MemoBobina deste último. Na segunda página, colocamos um componente TWebbrowser para exibirmos as informações da bobina do ACBrECF. Finalmente, na parte inferior do formulário, pode ser visto o componente ACBrECF que será o responsável pela interação de nosso aplicativo com a impressora fiscal. Foi inserido no formulário também um componente StatusBar para exibir o staus da impressora fiscal. Com o layout da aplicação pronto, iremos criar as rotinas dos botões inseridos no formulário, com execeção do botão “Vender Item” que codificaremos depois. Seguem os códigos dos eventos OnClick dos botões: “Ativar ECF”: procedure TForm1. btnativarClick(Sender: TObject); begin ACBrECF1.Modelo:=TAC BrECFModelo(cmbmodelo. ItemIndex); ACBrECF1. Porta:=cmbporta. Items[cmbporta.ItemIndex]; ACBrECF1.TimeOut:=3000; ACBrECF1.Ativar; Application. ProcessMessages; if ACBrECF1.Ativo then begin btnativar. Enabled:=false; StatusBar1. Panels[0].Text:=’ECF Ativa’; end; end; Figura 1 “Leitura X”: procedure TForm1. btnleituraxClick(Sender: TObject); begin ACBrECF1.LeituraX; end; “Redução Z”: procedure TForm1. btnreducaozClick(Sender: TObject); begin if(MessageDlg(‘Se for emitida a Redução Z, a ECF ficará inoperante até o dia seguinte.Deseja Contin uar?’,mtConfirmation,[mbYe s,mbNo],0)=mrYes)then ACBrECF1. ReducaoZ(Now); end; “Abrir Cupom”: procedure TForm1. btnabrircupomClick(Sender: TObject); begin ACBrECF1.AbreCupom; StatusBar1.Panels[0]. Text:=’Cupom Aberto’; end; “Cancela Cupom”: procedure TForm1. btncancelacupomClick(Sender: TObject); begin ACBrECF1.CancelaCupom; StatusBar1.Panels[0]. Text:=’Livre’; end; “Desativar ECF”: procedure TForm1. btndesativarClick(Sender: TObject); begin if ACBrECF1.Ativo then ACBrECF1.Desativar; if not ACBrECF1.Ativo then begin btndesativar. Enabled:=false; btnativar. Enabled:=true; end; end; março 2010 11 Destaca-se nesse código a rotina da Redução Z. Como se trata de uma operação que irá deixar a ECF inoperante pelo restante do dia é altamente recomendável que peçamos uma confirmação ao usuário antes de efetuar a mesma. Em seguida faremos a codificação para exibir os dados da bobina da ECF no WebBrowser. O componente ACBrECF irá enviar os dados para o componente Memo apontado em sua propriedade MemoBobina. O que precisamos fazer é salvar o conteúdo do Memo em um arquivo .html e em seguida exibi-lo no WebBrowser. Segue o código. Ficará no evento OnChange do componente Memo: procedure TForm1. membobinaChange(Sender: TObject); begin membobina.Lines. SaveToFile(‘bobina.html’); Application. ProcessMessages; WebBrowser1.Navigate(‘file :///’+ExtractFilePath(Appl ication.ExeName)+’bobina. html’); end; Repare que com a utilização do componente ACBrECF, todas as operações envolvendo a ECF ficam transparentes ao desenvolvedor. Basta dar um comando através do componente para realizar a operação. Essa sem dúvida é a grande vantagem dessa suíte de componentes. Teste o aplicativo e salve as alterações. Com isso terminamos a primeira parte de nosso exemplo. A seguir mostrarei como registrar itens de uma venda através do componente ACBrECF. Operação de venda de itens Adicione um novo formulário a aplicação e monte o layout do mesmo conforme mostrado na figura 2: Veja a Figura 2. 12 março 2010 Figura 2 A função que utilizaremos para registrar a venda do item e a função VendeItem do ACBrECF. Essa função recebe os parâmetros necessários para se efetuar uma venda na ECF. Essa função será utilizada no botão “Vender Item”. Não poderemos permitir a saída da tela sem que a venda seja finalizada. Para isso, no botão “Sair” utilizaremos as funções SubtotalizaCupom e EfetuaPagamento. Essas funções irão encerrar a venda e permitir que a ECF fique livre para uma nova venda. Referente ao pagamento, é importante ressaltar que as formas de pagamento precisam estar cadastradas na impressora fiscal. Nesse exemplo, estarei trabalhando com forma de pagamento em dinheiro, representada pelo código 01, constante da maioria das ECF’s. Antes da codificação nesses botões, volte ao formulário principal e no evento OnClick do botão “Vender Item”, coloque o seguinte código: procedure TForm1. Button1Click(Sender: TObject); begin try frmvenderitem:=Tfrmvenderitem. Create(Self); frmvenderitem. ShowModal; finally FreeAndNil(frmvenderitem); end; end; Esse código irá chamar o formulário de venda de itens. Agora, segue a codificação dos eventos OnClick dos botões do formulário de venda de itens: Botão “Vender Item” : procedure Tfrmvenderitem. btnvenderitemClick(Sender: TObject); begin if(Form1.ACBrECF1. Ativo)and(Form1.ACBrECF1. Estado=estVenda)then begin Form1.ACBrECF1. VendeItem(edtcodigo. Text,edtdescricao. Text,edticms.Text, StrToFloat(edtquantidade.T ext),StrToFloat(edtvalorun itario.Text), StrToFloat(edtdesconto. Text),edtunidade.Text); end; end; Botão “Sair”: procedure Tfrmvenderitem. btnsairClick(Sender: TObject); var sValorpagamento:string; begin if(MessageDlg(‘Deseja finalizar a venda?’,mtConf irmation,[mbYes,mbNo],0)=m rYes)then begin Form1.ACBrECF1. SubtotalizaCupom; sValorpagamento:=In putBox(‘ACBr’,’Informe o valor pago’,’’); Form1.ACBrECF1.Efetu aPagamento(‘01’,StrToFloat (sValorpagamento)); Form1.ACBrECF1. FechaCupom(‘Obrigado Volte Sempre!’); Close; end; end; Figura 3 O projeto ACBr, é totalmente open source, podendo ser adquirido nos seguintes links: Pagina principal ACBR Veja o formulário com valores para teste na figura 3: Veja a Figura 3. Após a venda dos itens e o pagamento, a ECF ficará livre para uma nova venda. Fique atento para os tipos de dados necessários nas passagens de parâmetros para as funções, para evitar erros de conversão. Além da venda de itens e principais leituras, como a Leitura X e Redução Z, o ACBr, permite também o completo gerenciamento da ECF, como o cadastro de formas de pagamento e a emissão de relatórios gerenciais. Ao se trocar o modelo de ECF, nenhuma alteração precisará ser feita no código, já que o ACBrECF, envia os comandos de acordo com o modelo de ECF configurada em sua propriedade Modelo. Os modelos suportados são descritos no ínicio desse artigo. http://acbr.sourceforge.net/drupal/ Ferramenta de controle de versão SVN no Windows (Tortoise): h t t p : / / a c b r. s o u r c e f o r g e . n e t / drupal/?q=node/37 Para instalar o componente NFe: h t t p : / / a c b r. s o u r c e f o r g e . n e t / drupal/?q=node/36 FAQ - ACBrNFe h t t p : / / a c b r. s o u r c e f o r g e . n e t / drupal/?q=node/38 Nesses links também se pode obter maiores informações sobre os componentes. Abraços e até a próxima. Sobre o autor Antonio Spitaleri Neto Conclusão Na área de automação comercial, o projeto ACBr sem dúvida é uma grande ajuda quando precisamos operar com ECF’s, pois sua portabilidade e extensibilidade garante um grande ganho de desempenho no desenvolvimento. Consultor Técnico The Club. [email protected] março 2010 13 INDO MAIS ALÉM EXPLORANDO AS TABELAS DE SISTEMA INTERBASE/FIREBIRD Olá pessoal, Tem certos momentos em que quebramos a cabeça tentando montar fórmulas, queries, procedures e todo tipo de truques para resolver determinadas situações em nossos bancos de dados. Por exemplo: precisamos realizar uma grande atualização em nosso banco de dados, mas devido a toda integridade referencial que temos através de triggers, um único Update dispararia centenas, milhares de outras ações que, provavelmente, sairiam de nosso controle. Então uma saída seria a desativação das triggers. Mas como desativar todas as triggers de nosso banco? Usando o comando Alter trigger tal_de_tal inactive? Uma a uma? Pois é, um tanto quanto complicado, não? Ou mesmo essa outra situação: Temos uma coluna em nossos bancos chamada Tipo_Cliente que é validada por uma Check Constraint determinando que os valores possíveis são ‘F’ (Pessoa Física) e ‘J’ (Pessoa 14 março 2010 Jurídica). Quando nós criamos essa Constraint não especificamos o nome da mesma. Então o banco de dados cria um nome aleatório do tipo CHECK$10. Agora precisamos alterar essa validação, acrescentando um novo valor. Para isso precisamos dropar a constraint e recria-la novamente. Mas como dropar a constraint se não sabemos o nome da mesma? Outra tarefa difícil de cumprir. Por isso nesse mês abordaremos um assunto diferente: o uso das tabelas de sistema em bancos de dados InterBase/Firebird. São tabelas que contém informações extremamente úteis e que, se bem utilizadas e manipuladas, podem nos ajudar a ir muito mais além na administração e manutenção de nossos bancos. Na prática podemos realizar todo tipo de comando DML (Data Manipulation Language) sobre as tabelas de sistema, respeitando algumas restrições que o próprio banco de dados impõe para manter a integridade interna. Então vamos lá: AS TABELAS DE SISTEMA Assim como outros objetos internos, as tabelas de sistema são todas aquelas cujo nome se iniciam com os caracteres RDB$ ou, no caso do InterBase, também TMP$. Essa nomenclatura é de uso exclusivo do banco de dados e não pode ser utilizado na criação de novas tabelas pelo usuário. As TMP$ são tabelas temporárias de sistema, utilizadas no recurso de monitoramento do banco de dados. Já as RDB$ são as tabelas de sistema responsáveis por guardar todo tipo de informação relativa, principalmente, ao metadata do banco de dados, à estrutura do banco. Quando criamos um banco de dados, o sistema já cria automaticamente as tabelas RDB$. São elas: Veja a Tabela. Tabela de Sistema Funcionalidade RDB$CHARACTER_SETS Descreve todos os tipos de Character Sets disponíveis no banco de dados. RDB$CHECK_CONSTRAINTS Grava informações sobre todas as Constrainst do tipo Check presentes no banco de dados. Também armazena informações sobre todas as Constraints das colunas marcadas como Not Null. RDB$COLLATIONS Descreve as regras das Collations permitidas para uso do banco de dados. RDB$DATABASE Salva informações sobre o banco de dados. RDB$DEPENDENCIES Armazena todos os tipos de dependência entre os objetos do sistema. Tabelas / Stored Procedures / Triggers, enfim. É por aqui que o banco de dados valida se uma coluna pode ser alterada / excluída sem afetar outros objetos. RDB$EXCEPTIONS Descreve todas as exceções de erro geradas e utilizadas pelas Stored Procedures, inclusive as exceções criadas pelo usuário. RDB$FIELDS Contém informações sobre as características de cada coluna e domínio do banco de dados. Informações sobre valores default, not null, campos computados, enfim. Todas as colunas de todas as tabelas são referenciadas nessa tabela. RDB$FIELD_DIMENSIONS Descreve o tamanho de cada coluna. RDB$FILES Lista informações sobre todos os arquivos secundários do tipo shadow que estão em uso no banco de dados. RDB$FILTERS Contém informações sobre filtros de campos do tipo Blob. RDB$FORMATS Uma tabela interessante. Ela armazena informações sobre o versionamento de alterações realizadas nas tabelas do banco. Todas as vezes que executamos um comando de Alter/Drop/Create Table essa tabela grava o número dessa alteração. E isso que permite que uma aplicação possa acessar tabelas alteradas sem a necessidade de ser recompilada. O sistema permite que sejam feitas até 255 alterações na estrutura de tabelas. Ao atingir esse limite, um backup e um restore do banco precisa ser feito para zerar esse contador e permitir novas alterações. RDB$FUNCTION_ARGUMENTS Define atributos de funções utilizadas pelo banco de dados, inclusive as UDFs. RDB$FUNCTIONS Descreve as UDFs utilizadas pelo banco de dados. RDB$GENERATORS Contém informações sobre todas as Generators utilizadas pelo banco de dados. RDB$INDEX_SEGMENTS Uma tabela de sistema muito importante que grava informações sobre todas as colunas que são referenciadas em todos os índices do banco de dados. Modificar manualmente essa tabela pode causar grandes corrupções! RDB$INDICES Descreve todos os índices criados no banco de dados. Cada índice dessa tabela deve ser suas respectivas referencias na tabela RDB$INDEX_SEGMENTS. RDB$LOG_FILES Essa tabela não é mais utilizada nos bancos de dados InterBase/Firebird, mas permanece listada por legado. RDB$PAGES Uma tabela bem técnica, que grava informações sobre cada página de dados alocada do banco de dados. Qualquer tipo de modificação manual nessa tabela irá corromper o mesmo. RDB$PROCEDURE_PARAMETERS Essa tabela grava informações sobre os parâmetros (input e output) usados em todas as Stored Procedures do banco de dados. RDB$PROCEDURES Contém a descrição das Stored Procedures do banco de dados. RDB$REF_CONSTRAINTS Grava informações sobre as Constraints de Integridade Referencial usadas no banco (Primary e Foreing Keys). RDB$RELATION_CONSTRAINTS Aqui são listadas as relações entre as Constraints e de Integridade Referencial e as respectivas tabelas relacionadas. RDB$RELATION_FIELDS Descreve informações complementares sobre as colunas e domínios do banco de dados, bem como as relações entre as colunas e as tabelas. RDB$RELATIONS Define algumas características de tabelas e Views. RDB$ROLES Listas todos os Roles criados no banco, bem como o usuário dono desse Role. RDB$SECURITY_CLASSES Define as listas de controle de acesso (ACLs) criadas no banco, bem como a relação dessas regras com os objetos do sistema. RDB$TRANSACTIONS Grava informações sobre todas as transações multi-banco que estão em uso no sistema. RDB$TRIGGER_MESSAGES Contém informações sobre todas a mensagens de Triggers, bem como as Triggers relacionadas às mensagens. RDB$TRIGGERS Descreve todas as Triggers do banco de dados. RDB$TYPES Lista todos os tipos de dados e apelidos para os Character Sets e Collations usados no banco de dados. RDB$USER_PRIVILEGES Contém informações sobre o direito de acesso de cada usuário criado no banco de dados. Sempre que usamos os comandos Grant e Revoke, o sistema grava essas referências nessa tabela. RDB$VIEW_RELATIONS Aqui são listadas as relações entre as Views e suas respectivas tabelas. março 2010 15 Também pode existir outras tabelas de sistema de forma distinta entre o InterBase e o Firebird, conforme a ODS (On Disk Structure) do banco de dados. VISUALIZANDO AS TABELAS DE SISTEMA Para acessar e visualizar as tabelas de sistema devemos: 1. Usando o utilitário de linha de comando ISQL, executamos o comando: Imagem 2 SQL> show system; RDB$CHARACTER_SETS RDB$CHECK_CONSTRAINTS RDB$COLLATIONS RDB$DATABASE RDB$DEPENDENCIES RDB$EXCEPTIONS [...] SQL> 2. Usando o utilitário gráfico IBConsole, selecionamos no menu: 3. Usando o utilitário gráfico IBExpert, marcamos na propriedade da conexão: Veja a imagem 2. MANIPULANDO AS TABELAS DE SISTEMA Devemos sempre tomar cuidado antes de assim proceder, mas vamos dar alguns exemplos de comandos DML que podemos executar sobre as tabelas de sistema. Ampliando o tamanho de um campo Char/ Varchar: Muitas vezes precisei ampliar o tamanho de 16 março 2010 uma coluna Char/Varchar. Por exemplo: Precisamos ampliar a coluna NOME de 30 para 60 caracteres. Mas como fazer de uma só vez em todas as tabelas do banco de dados onde essa coluna existe? Manipulando as tabelas de sistema: Update rdb$fields Set rdb$field_length = 60 Where rdb$field_name = (select f.rdb$field_ source from rdb$relation_ fields f where f.rdb$field_name = ‘NOME’) Esse comando irá buscar todas as colunas descritas com o nome “NOME” e aumentar na tabela que descreve os campos o Length dessa coluna para 60 caracteres. Ativando e Desativando Triggers: Quando precisamos realizar uma atualização em massa no banco de dados ou quando temos um banco de dados vazio que precisa ser populado, podemos nos deparar com um problema: as Triggers. Isso porque, muitas vezes usamos as Triggers para realizar a integridade referencial de nossos bancos. Ai quando vamos inserir um dado em determinada tabela, a Trigger impede por não existir relação com outra tabela principal, por exemplo. Precisamos então rodar comandos do tipo Alter Trigger ... Inactive/Active. Mas como fazer isso de forma prática quando temos centenas / milhares de Triggers? Executando o comando DML abaixo: UPDATE RDB$TRIGGERS SET rdb$trigger_inactive = 1 WHERE (rdb$system_flag = 0 or rdb$system_flag IS NULL) AND rdb$trigger_name NOT LIKE ‘CHECK%’ AND rdb$trigger_name NOT LIKE ‘RDB$%’ Esse comando irá desativar todas as Triggers do banco de dados, com exceção das Triggers de sistema e das Checks Constraints. Para reativar novamente as mesmas, basta realizar o Update novamente, ajustando o valor para “0” (Zero). Apagando Checks Constraints sem saber o nome: Como no exemplo que demos na abertura do nosso artigo, como podemos apagar todas as Checks Constraints relacionadas à uma determinada coluna de nosso banco de dados, se não sabemos o nome de nossa Check Constraint? Basta executar o comando DML abaixo: DELETE FROM RDB$RELATION_ CONSTRAINTS A Where (Select count(*) from RDB$CHECK_CONSTRAINTS B, RDB$TRIGGERS C where (A.RDB$CONSTRAINT_TYPE = ‘CHECK’) and (A.RDB$CONSTRAINT_ NAME = B.RDB$CONSTRAINT_ NAME) and (B.RDB$TRIGGER_NAME = C.RDB$TRIGGER_NAME) and (C.RDB$TRIGGER_TYPE = 1) and (A.RDB$RELATION_NAME in (SELECT DISTINCT r.rdb$relation_name FROM rdb$check_ constraints C JOIN rdb$relation_ constraints R ON (C.rdb$constraint_name = R.rdb$constraint_name) WHERE C.rdb$trigger_ name IN (SELECT D.rdb$dependent_name FROM rdb$dependencies D WHERE D.rdb$field_ name = ‘TIPO_CLIENTE’ and d.rdb$dependent_name like ‘CHECK%’)) )) > 0; Club Megazine comentamos a respeito do uso das UDFs. Segue um exemplo de uso de UDF contra uma tabela de sistema: Select F_UUID1MACMAC(F_ UUID1MAC()) from rdb$database; Esse comando executado a partir de qualquer computador cliente retornará o endereço Mac Address do servidor do banco de dados. Isso pode ser muito útil por exemplo para se criar uma rotina de validação da aplicação para liberação de licenças de uso. de Tamanhos’ WHERE RDB$RELATION_NAME=’ T02P007LJ’; UPDATE RDB$RELATIONS SET RDB$DESCRIPTION=’Cadastro de Cores’ WHERE RDB$RELATION_NAME=’ T03P007LJ’; UPDATE RDB$RELATIONS SET RDB$DESCRIPTION=’Tabelas de Preco’ WHERE RDB$RELATION_NAME=’ T04P009LJ’; UPDATE RDB$RELATIONS SET RDB$DESCRIPTION=’Imagens de Produtos’ WHERE RDB$RELATION_NAME=’ T05P015LP’; Trabalhando com Descrições em Tabelas: Esse é outro ponto interessante. É muito comum encontrar bancos de dados com centenas de tabelas, mas onde o nome da tabela não identifica seu real propósito. Por exemplo: ao invés de chamar uma tabela de cadastros de produto de TABPRODUTOS, o nome da tabela é algo do tipo T01P007LJ. Então novo desenvolvedor ou mesmo um usuário mais experiente acaba ficando perdido ao tentar encontrar uma determinada tabela. Uma maneira interessante de se tratar esse problema é criando uma descrição para as tabelas de sistema. Para isso usamos o comando DML: E assim por diante. Quando abrimos o utilitário IBExpert, podemos facilmente identificar as tabelas: Veja a Imagem 3. Ou mesmo podemos executar um comando DML para pesquisar uma determinada tabela pela sua descrição: Select rdb$relation_name, rdb$description from rdb$relations where rdb$description like ‘%rodutos%’; UPDATE RDB$RELATIONS SET RDB$DESCRIPTION=’Cadastro de Produtos’ WHERE RDB$RELATION_NAME=’ T01P007LJ’; UPDATE RDB$RELATIONS SET RDB$DESCRIPTION=’Cadastro Esse nosso comando irá apagar todas as Checks Constraints que validarem a coluna Tipo_Cliente, em todas as tabelas do banco de dados. Depois, podemos recriar as mesmas com a nova regra de validação. Rápido e Seguro. Resgatando o MAC Address do Servidor InterBase/Firebird: Recentemente em um artigo nosso aqui na The Imagem 3 março 2010 17 Retornaria algo como: RDB$RELATION_NAME Nos vemos no próximo artigo para falar mais sobre o InterBase e seus recursos. Valeu pessoa e Até lá! RDB$DESCRIPTION T01P007LJ Cadastro de Produtos T05P015LP Imagens de Produtos Referência: CONCLUSÃO E esses são apenas alguns exemplos. Novamente explorando mais dos recursos de nossos bancos de dados. Se pesquisarmos mais e estudarmos as tabelas de sistema de nossos bancos, podemos extrair muito mais. Claro e novamente repetindo: tudo com muito cuidado para não derrubar alguma integridade ou mesmo corromper nossos bancos. Mas recomendo a todos a leitura complementar do Capitulo 6 do guia Language Reference do InterBase SMP 2009, que contém informações completas sobre as tabelas de sistema e sobre as tabelas temporárias de sistema. Afinal, 18 março 2010 as informações estão lá o tempo todo. Cabe a nós desenvolvedores irmos mais além, usar essas informações à nosso favor. InterBase 2009 Language Reference – cap. 6. http://edn.embarcadero.com Sobre o autor Felipe Santos Felipe Santos é especialista em InterBase. Trabalha com o InterBase desde 2001. atuando como consultor e instrutor do produto em todo Brasil. Especialista em ambientes críticos. Atua e trabalha com os maiores clientes do InterBase no Brasil. Participante ativo na comunidade, com diversos artigos publicados. Participante do grupo de beta testers mundial do produto. Palestrante em eventos como IB Tour, Borcon Conference, CodeRage Latin América, Delphi Developers Day, Linux Day, entre outros. Atualmente trabalhando na área técnica do InterBase na Presence Tecnologia – agente oficial especializado do produto no Brasil. [email protected] STORED PROCEDURES E TRIGGERS NO MYSQL As Stored Procedures e Triggers são mais conhecidas no Firebird, mas também são muito importantes na otimização do desempenho de um Banco de Dados no MySQL, neste artigo mostrarei o que elas são, como funcionam no MySQL e farei alguns exemplos. STORED PROCEDURES Introduzidas a partir da versão 5.0 do MYSQL as Stored Procedures (SP) ou Procedimentos Armazenados são um conjunto de comando SQL que podem ficar armazenados no servidor e poupar os usuários da necessidade de enviar extensos comandos SQL ao servidor só sendo necessário fazer a chamada a SP. As vantagens do uso das SP’s são muitas, entre as principais que posso destacar estão: • Melhora do desempenho – por serem armazenadas e processadas no servidor elas enviarão ao usuário somente os resultados das consultas diminuindo assim o trafego na rede; • Economia de código – é necessária apenas uma linha de código para se chamar uma SP já que a instrução SQL está toda encapsulada no corpo da SP, você não terá mais que escrever várias linhas toda vez que quiser uma operação específica em seu banco; • Facilidade de manutenção – elas podem ser alteradas sem a necessidade de se alterar as aplicações que as utilizam e sem importar a linguagem em que foi escrita essa aplicação; • Segurança – os usuários terão acesso somente as SP’s e não as tabelas, isso diminui a possibilidade de algum usuário fazer alguma alteração que prejudique o Banco de Dados; • Distribuição de tarefas – as tarefas da criação de uma aplicação podem ser divididas entre um profissional especializado em Banco de Dados e um Programador que criará a aplicação. As SP são basicamente classificadas em três tipos: 1. As que retornam algum valor, como a contagem de registros de uma tabela; 2. As que retornam registros funcionando como um Select , e; 3. As que fazem ações específicas no banco, como inserções, alterações, atualizações etc. março 2010 19 STORED PROCEDURES NO MYSQL A sintaxe geral de uma SP no MySQL é a seguinte: CREATE PROCEDURE nome_ proc([parâmetro ...]) [características] BEGIN comandos procedurais executados automaticamente em resposta a algum evento executado no banco de dados, como por exemplo na inserção de um registro em uma tabela de pessoas, a trigger automaticamente gerará na tabela de salários um campo referente ao salário daquela pessoa. As triggers são usadas geralmente para: • Para manter a integridade entre as tabelas: podem ser criados grandes processos de controle dos relacionamentos entre as tabelas, principalmente aos usuários de tabelas MyISAM que não suportam relacionamnetos via chave estrangeira; Corpo da SP; END; Onde: • Nome_proc - aqui se define o nome da procedure, um padrão muito adotado entre os desenvolvedores é SP_nome_da_procedure; • Parâmetro – os parâmetros utilizados em SP no MySQL dividem-se em três: 1. IN – São os parâmetros de entrada que serão trabalhados no corpo da SP e produzirão algum resultado; 2. OUT – É o parâmetro interno que retorna algum resultado para o lado externo; 3. INOUT - É o parâmetro que pode funcionar das duas formas. • Características – definem o tipo da procedure, se determinística ou não, questões de segurança do banco de dados e linguagem de escrita da SP,não setem a obrigatoriedade de declara – las quand se escrevea SP ; • Corpo da SP – onde são escritos os comandos SQL. • Manter a segurança do Banco: as triggers podem controlar o acesso, atualizações e alterações nas tabelas; • Melhorar o desempenho do banco: imagine um banco com 500.000 registros que de tempos em tempos requer uma simples alteração nos registros, atrvés de uma trigger essas alterações podem ser feitas automaticamente através da trigger.; • Auditoria do Banco de Dados: por serem executadas automaticamente são excelentes ferramentas para auditria do BD. TRIGGERS NO MYSQL. A sintaxe geral de uma Trigger no MySQL é a seguinte: CREATE [DEFINER = { USER | CURRENT USER}] Onde: • DEFINER: checa quais os privilégios que usuário do banco tem para disparar a trigger. Quando a trigger é criada esse campo é preenchido por padrão com CURRENT_USER ou pode ser preenchida com o usuário(ex: ‘bruno’@’localhost’); • nome_trigger: define-se o nome da trigger, o padrão adotado entre os desenvolvedores é TRG_nome_trigger; • tempo_trigger: aqui se define quando a trigger será executada: • BEFORE: a trigger será ativada antes do comando que a disparou; • AFTER: a trigger será ativada depois do comando que a disparou; • evento trigger: o evento que será executado quando a trigger for disparada: • INSERT: um ou mais registros serão inseridos em uma tabela; • UPDATE: um ou mais registros serão atualizados em uma tabela; • DELETE: um ou mais registros serão apagados em uma tabela; • nome_tabela: tabela onde a trigger trabalhará; • corpo_trigger: comandos executados pela trigger. TRIGGER nome_trigger tempo_trigger evento_ trigger TRIGGERS ON nome_tabela As triggers (ou gatilhos em português) são FOR EACH ROW março 2010 corpo_trigger EXEMPLOS Para ilustrar melhor as explicações vamos criar alguns exemplos de Triggers e Stored Procedures. O primeiro passo é criar as tabelas, para este exemplo vamos criar duas tabelas, uma tabela de pessoas e outra de usuários. Abaixo seguem os scripts de criação das tabelas: PESSOAS Essa tabela servira para o cadastro de pessoas, como por exemplo clientes e funcionários, essa especificação se dará no campo PESSOA_TIPO que receberá G para gerente(que terá todos os privilégios), C – para cliente ou F – para funcionário. int(11) default NULL, PRIMARY KEY (`ID_ USUARIO`), KEY `FK_PESSOA_USUARIO` (`FK_PESSOA_USUARIO`), CONSTRAINT `USUARIO_ PESSOA_FK` FOREIGN KEY (`FK_PESSOA_USUARIO`) REFERENCES `pessoas` (`ID_ PESSOA`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 CREATE PROCEDURE SP_ADD_ USUARIOS ( IN USUARIO VARCHAR (80), IN SENHA VARCHAR (35), IN TIPO CHAR(1), IN FK_PESSOA INT) BEGIN INSERT INTO `usuarios` (USUARIO_NOME, USUARIO_ SENHA, USUARIO_TIPO,FK_ PESSOA_USUARIO) VALUES (USUARIO,SENHA,TIPO,FK_ PESSOA); END; TRG_CRIP_SENHA CREATE TABLE `pessoas` ( `ID_PESSOA` INTEGER(11) NOT NULL AUTO_INCREMENT, `PESSOA_NOME` VARCHAR(80) NOT NULL, `PESSOA_RG` VARCHAR(15) DEFAULT NULL, `PESSOA_TIPO` CHAR (1) DEFAULT NULL, PRIMARY KEY (`ID_ PESSOA`) ) ENGINE=InnoDB; Agora vamos criar nossa primeira trigger, essa trigger se encarregará de criptografar a senha de usuário quando este for inserido, o método de criptografia é o MD5 que já é uma função presente no banco MySQL, o MD5 é um algoritmo unidirecional que criptografa uma string e não permite que essa criptografia seja revertida. Percebam que usamos o operador NEW (NEW. USUARIO_SENHA) esse operador significa que queremos o dado que acaba de ser inserido, se porventura apagássemos esse registro poderíamos recuperá – lo através do operador OLD (OLD. USUARIO_SENHA). USUARIOS Essa tabela guardará os dados dos usuários de um suposto programa, desde que eles sejam definidos com F no campo PESSOA_TIPO. O campo USUARIO_TIPO deve ser marcado com A – Administrador ou C- Comum sendo que só o Administrador tem permissões para inserir registros na tabela de pessoas. CREATE TABLE `usuarios` ( `ID_USUARIO` int(11) NOT NULL auto_increment, `USUARIO_NOME` varchar(80) default NULL, `USUARIO_SENHA` varchar(35) default NULL, `USUARIO_TIPO` char(1) default NULL, `FK_PESSOA_USUARIO` CREATE TRIGGER TRG_CRIP_ SENHA BEFORE INSERT ON `usuarios` FOR EACH ROW BEGIN SET NEW.USUARIO_SENHA = MD5(NEW.USUARIO_SENHA); END; SP_ADD_USUARIOS O nosso próximo passo é criar uma Stored Procedure que será usada em conjunto com a próxima trigger e que quando executada incluirá dados na tabela de usuários. TRG_USUARIOS Essa trigger incluirá automaticamente uma pessoa cadastrada na tabela de pessoas, desde que seu pessoa tipo na tabela seja F, na tabela de usuários como um usuário do sistema. Por padrão, que será definido na trigger, o nome de desse usuário será o seu nome em letras minúsculas, a senha será 123456 e o tipo será definido como C - Comum. CREATE TRIGGER TRG_ USUARIOS AFTER INSERT ON `pessoas` FOR EACH ROW BEGIN IF (NEW.ID_PESSOA IS NOT NULL) AND (NEW.PESSOA_TIPO = ‘G’) THEN CALL SP_ADD_ USUARIOS(LOWER(NEW.PESSOA_ NOME),’123456’,’A’,NEW. ID_PESSOA); ELSE IF (NEW.ID_PESSOA IS NOT NULL) AND (NEW.PESSOA_ TIPO = ‘F’) THEN CALL SP_ADD_ USUARIOS(LOWER(NEW.PESSOA_ NOME),’123456’,’C’,NEW. ID_PESSOA); END IF; END IF; END março 2010 21 TESTES Agora vamos efetuar alguns testes nesse banco para verificar o funcionamento das Triggers e Stored Procedures. Para efetuar esses testes estou usando a IDE Gráfica EMS SQL Manager Lite for MySQL que é gratuita e pode ser encontrada no seguinte endereço: Imagem 1 Imagem 2 Vamos inserir um registro na tabela de PESSOAS com o tipo definido com G –GERENTE. Imagem 3 INSERT INTO `pessoas` (PESSOA_NOME, PESSOA_RG, PESSOA_TIPO) VALUES (‘BRUNO’,’12.345.6789’,’G’); Imagem 4 um registro, referente ao funcionário DANIEL Veja a Imagem 1. Veja a Imagem 4. No momento da inserção a trigger que insere um usuário(TRG_USUARIOS) é automaticamente executada e gera na tabela de usuários um novo registro com a senha já criptografada (TRG_CRIP_ SENHA), e como o PESSOA_TIPO é = G esse usuário será um administrador. Veja a Imagem 2. Vamos inserir agora mais dois registros, um funcionário (que também é um usuário do sistema) e um cliente. INSERT INTO `pessoas` (PESSOA_NOME, PESSOA_RG, PESSOA_TIPO) VALUES (‘DANIEL’,’87.654.3210’,’F’), (‘FREDERICO’,’87.654.3210’,’C’); COMMIT; Veja a Imagem 3. Na tabela de usuários foi gerado apenas mais 22 março 2010 Vamos criar agora uma Stored Procedure que controlará a inserção de dados na tabela PESSOAS. SP_PERMISSOES Essa procedure quando executada servirá para incluir dados na tabela de pessoas, mas ela controlará quem o fará, só poderão incluir registros usuários cadastrados como A – Administrador e que tenham digitado o nome e senha de usuário correta, caso o usuário seja C – comum retornará uma mensagem avisando que não é possível fazer essa inserção. CREATE PROCEDURE SP_ PERMISSOES ( IN USUARIO VARCHAR (80), IN SENHA VARCHAR (35), IN NOME VARCHAR(80), IN RG VARCHAR(15), IN TIPO CHAR(1)) BEGIN DECLARE V_TIPO CHAR(1); DECLARE V_SENHA VARCHAR (35); SELECT USUARIO_TIPO, USUARIO_SENHA INTO V_TIPO, V_SENHA FROM USUARIOS WHERE USUARIO_NOME = USUARIO; IF V_TIPO = ‘A’ AND V_ SENHA = MD5(SENHA) THEN INSERT INTO `pessoas` (PESSOA_NOME, PESSOA_RG, PESSOA_TIPO) VALUES (NOME, RG, TIPO); ELSE SELECT ‘VOCÊ NÃO TEM PERMISSÃO PARA EXECUTAR ESSA TAREFA’ AS AVISO; END IF; END Vamos agora testar essa SP: CALL SP_PERMISSOES(‘bruno’ ,’123456’,’ANTONIO’,’71.82 5.936.-4’,’C’) Percebam que o registro ANTONIO foi inserido: Veja a Imagem 5. Vamos tentar inserir um registro como um usuário C – comum: Imagem 5 CALL SP_PERMISSOES(‘daniel ’,’123456’,’JEREMIAS’,’84. 369.521-7’,’G’) Imagem 6 Ele retornará uma mensagem de erro: Veja a Imagem 6. Sobre o autor Bruno Alcarás CONCLUSÃO Neste artigo procurei demonstrar de forma simples algumas das operações que podem ser feitas com Triggers e Stored Procedures no MySQL, mas elas podem ser usadas de muitas outras formas na busca de um melhor desempenho do seu banco, sempre que possível as utilize. Consultor Técnico The Club. [email protected] E isso é tudo pessoal, até outra hora. março 2010 23 Olá, Então pessoal como alguns devem saber no dia 12/04/2010 foi lançado o Visual Studio 2010 oficialmente e na edição de hoje eu vou falar sobre algumas novidades dessa versão, nessa edição eu vou focar nas área e nas novidades que mais gostei área de arquitetura e modelos UML. Além dos modelos básicos de programação WCF, WPF, Windows Form, Silverlight, WebApplication e a novidade agora é Azure ou seja Cloud Computing, e essa nova versão conta com Unit Tests, ao contrário da versão Professional do Visual Studio 2008. Visual Studio Professional 24 março 2010 • Debugging histórico com IntelliTrace • Ferramentas de testes compreensi- Visual Studio Premium (além das funcionalidades da versão Professional): As versões Ao contrário de seus antecessores, o Visual Studio 2010 conta com SKUs (edições) mais simplificadas, de anteriormente 9 para simplesmente 4 agora: Ultimate, Premium, Professional e a versões Express. Irei abordar aqui individualidades de cada uma das três versões pagas, Ultimate, Premium e Professional: Visual Studio Ultimate (além das funcionalidades da versão Premium): • Debugging e desenvolvimento de aplicações avançado • Unit Tests com cobertura de código (Code Coverage - mostra quanto por cento do código está sendo testado), prioritização de testes, análise, métrica e otimização de código • Desenvolvimento e testes unitários de banco de dados • Diagramas de arquitetura (apenas leitura) vas • Ferramentas avançadas de UML • Ferramentas de descoberta de arquitetura • Test Case e gerenciamento do laboratório de testes Modelagem UML Para criar um modelo novo basta clicar em New Project e escolher a opção Modeling Projects e escolher o template Modeling Project, depois só indique o caminho aonde será salvo e pronto você terá um Projeto de modelos, esse projeto você pode tranquilamente fazer controle de versão com o Visual Studio team System ( falarei mais sobre ele em outro artigo ). Figura 1 Veja a figura 1. Diagrama de Sequência A UML significa muito para arquitetos e analistas de sistema. Parqa criar os modelos basta clicarmos com o botão direito sobre qualquer método de classe que desejemos visualizar o diagrama de sequência e escolhermos a opção Generate Sequence Diagram, que em seguida será aberta uma janela para customização do método, como profundidade, referências externas, entre outras. Após o OK, teremos o Diagrama de Sequência do método, como visto a seguir: Figura 2 Figura 1. Criando um projeto de diagrama Veja a figura 2. Diagrama de Dependências Um sistema, por menor que seja, terá algumas referências (bibliotecas externas) o acompanhando, seja elas do próprio sistema ou de terceiros. Mas a medida que o projeto vai crescendo, suas referências também vão aumentando, dificultando assim a visualização do que cada parte do sistema necessita. Com o diagrama de sequência do do Visual Studio 2010, fica mais fácil fazer e de visualizar o mesmo melhorando a vida do arquiteto do sistema. Para que geremos um novo diagrama de dependências, basta irmos no menu Architecture -> Generate Dependency Graph e escolher o tipo de diagrama que será mostrado, por assembly, por namespace, entre outras opções. Veja aqui um Figura 2. Diagrama de sequência exemplo: Figura 3 Vejaa figura 3. dendo ser expandida até um nível mais profundo e com isso os arquitetos, desenvolvedores, analistas e designers conseguem entender e vizualizar melhor o impacto das alterações a serem realizadas. Note que cada dependência está contraída, pomarço 2010 25 Diagrama de Componentes Quando utilizamos componentes de terceiros em nossos sistemas, várias vezes nos perguntamos como eles se relacionam com o código desenvolvido pela equipe. Esta pergunta surge principalmente quando um desenvolvedor novo entra no time que já tem um projeto em andamento. Como a UML conta com o diagrama de componentes, a equipe de desenvolvimento do Visual Studio achou interessante incorporá-lo ao template de projetos de modelagem, para que seja de fácil visualização e modificação para aqueles que estão entrando no time depois de um tempo de desenvolvimento. Este diagrama contém os seguintes objetos na toolbox: Component, Provided Interface, Required Interface, Part Assembly, além dos objetos de relacionamento e comentários. Confira como é seu design no Visual Studio: Figura 4 Figura 3. Diagrama de dependências Veja a imagem 4. Diagrama de Camadas Hoje em dia, nos deparamos com diversos padrões de projeto que dividem o sistema em camadas. Seja MVC (Model-View-Controller), MVP (Model-View-Presenter), MVVM (ModelView-ViewModel) ou N camadas, esta divisão de camadas está presente no nosso dia a dia, pois permite uma manutenibilidade boa, além de não ficarmos focados em apenas um tipo de visão, ou banco de dados, por exemplo. Figura 4. Diagrama de componente Por isso é importante enxergarmos o sistema como um todo dividido em algumas partes, para sabermos qual parte faz o quê. Partindo deste princípio, o diagrama de camadas foi criado, e agora o Visual Studio conta com um template para diagramação das mesmas. Apenas arrastando itens da toolbox, poderemos facilmente, por exemplo, criar um diagrama de camadas MVC, de acordo com a figura a seguir: Figura 5 Veja a figura 5. Figura 5. Diagrama de camadas 26 março 2010 Agora que já falamos de UML e diagramas vou falar um pouco das novas funcionalidades do editor. References Highlighting Agora é possível encontrar onde cada propriedade e outros símbolos definidos em determinada classe estão sendo usados, através do recurso References Highlighting. Clicando sobre qualquer referência de determinada propriedade da sua classe, a IDE vai destacar todas as suas ocorrências. Além disto, ainda é possível navegar pelas referências, com as teclas CTRL + SHIFT + Seta para cima ou CTRL + SHIFT + Seta para baixo, levando para a ocorrência anterior ou superior, respectivamente. Figura 6. - Propriedade Nome selecionada, mostrando as ocorrências na classe Veja a figura 6. Call Hierarchy Figura 7. - Chamadas ao MetodoFilho, e chamadas do MetodoFilho Quem nunca precisou saber quais métodos chamam outros métodos enquanto está melhorando aquele código imenso? A nova versão do Visual Studio agora lhe possibilita isto, através do Call Hierarchy. Como exemplo, criei um projeto Silverlight, que conta com a MainPage.xaml.cs, uma classe chamada ClassePai e outra chamada ClasseFilha. Criei alguns métodos para interpretação, o MetodoPai na ClassePai, que chama o MetodoFilho, na ClasseFilha. E por sua vez, no construtor da MainWindow.xaml.cs, o MetodoPai é chamado. Seria algo parecido como: Conclusão Então o que concluimos é que a Microsoft está trabalhando intensamente em cima das necessidades da comunidade e dos Feedback enviados. E esses novos diagramas e funcionalidades facilitam a vida dos arquitetos, analistas e desenvolvedores, vale a pena conferir. Mais informações podem ser obtidas em: http://www.microsoft.com/visualstudio/ en-us/ MainPage.xaml.cs -> MetodoPai -> MetodoFilho. Indo lá no cabeçalho do MetodoFilho, clicamos com o botão direito, indo em View Call Hierarchy, o que nos abrirá a seguinte janela: Veja a figura 7. Sobre o autor Djonatas Tenfen Trabalha a quase 7 anos com Delphi, trabalha na empresa Benner Sistemas (www.benner.com.br ) na área de tecnologia desenvolvendo ferramentas em Delphi e como hobby e visão de mercado está migrando seus conhecimentos para a plataforma .NET. Faz parte do grupo .NET Blumenau http://dotnetblumenau.ning.com/ . Possue certificação 70-536 (Microsoft .NET Framework 2.0 Application Development Foundation ) . Twitter: djonatastenfen - blog http://www.djonatastenfen.blogspot.com/ [email protected] março 2010 27 Dicas DELPHI Limitar número de caracteres digitados em um Memo ou RichEdit Mude a propriedade MaxLenght do Memo ou RichEdit para o valor desejado(neste exemplo usaremos 140), adicione também uma label para mostrarmos a contagem dos caracteres. Serial,DirLen,Flags,nil,0); Result := IntToHex(Serial,8); Except Result :=’’; end; Estado da memória do computador Adicione um Memo ao Form. No evento OnChange Label1.Caption:= IntToStr(length(Memo1.Text)); // uma label mostrando o número de caracteres digitados const cBytesPorMb = 1024 * 1024; var M: TMemoryStatus; begin M.dwLength := SizeOf(M); GlobalMemoryStatus(M); No evento KeyUp Memo1.Clear; with Memo1.Lines do begin Add(Format(‘Memória em uso: if length(Memo1.Text) = 140 then // se o tamanho do memo igual a 140 então ShowMessage(‘Somente 140 caracteres permitidos’); // mostra mensagem %d%%’, [M.dwMemoryLoad])); Add(Format(‘Total de memória física: %f MB’, [M.dwTotalPhys / cBytesPorMb])); Add(Format(‘Memória física disponível: %f MB’, [M.dwAvailPhys / cBytesPorMb])); Add(Format(‘Tamanho máximo do arquivo de paginação: %f MB’, [M.dwTotalPageFile / cBytesPorMb])); Serial HD Add(Format(‘Disponível no arquivo de paginação: %f MB’, [M.dwAvailPageFile / Function SerialNum(FDrive: String): String; var Serial:DWord; DirLen,Flags: DWord; DLabel : Array[0..11] of Char; begin Try GetVolumeInformation(PC har(FDrive+’:’),dLabel,12,@ 28 março 2010 cBytesPorMb])); Add(Format(‘Total de memória virtual: %f MB’, [M.dwTotalVirtual / cBytesPorMb])); Add(Format(‘Memória virtual disponível: %f MB’, [M.dwAvailVirtual / cBytesPorMb])); end; end; março 2010 29 Horizontal 30 Vertical março 2010 março 2010 março 2010