domingo, 4 de setembro de 2011

Usando funções no MySQL


Vou tentar passar aqui, um pequeno exemplo de como usar funções do MySQL em nossas instruções SQL.
Em primeiro lugar, certifique-se que você possua instalado uma versão a partir da 5.x do MySQL em seu micro.
No nosso exemplo, criaremos e utilizaremos uma função que retornará a idade do cliente
Crie uma pequena tabela com a seguinte estrutura:

CREATE TABLE `clientes` (
`ID` int(11) NOT NULL auto_increment,
`NOME` varchar(45) default NULL,
`DATANASC` date default NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;



Inclua as linhas abaixo na tabela, ou digite suas próprias informações:


INSERT I NTO `clientes` (`ID`, `NOME`, `DATANASC`) VALUES
(1, 'SILVIO SANTOS', '1971-09-18'),
(2, 'SILLAS SANTOS', '1993-04-27');


Agora, crie a função conforme o exemplo abaixo:


CREATE FUNCTION `idade`(pDATA DATE)
RETURNS varchar(15) CHARSET latin1
NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER
COMMENT ''
Begin
DECLARE vIDADE varchar(30);
IF DATE_FORMAT(NOW( ),'00-%m-%d') >= DATE_FORMAT(pDATA,'00-%m-%d') THEN
SET @idade=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(pDATA,'%Y');
ELSE
SET @idade=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(pDATA,'%Y')-1;
END IF;
RETURN(concat(@idade,' anos'));
end;


Esta função, retornará a idade da pessoa de acordo com o campo DATANASC, da tabela ‘clientes’.
Veja que a função receberá um valor (pDATA, que no nosso exemplo será o campo ‘DATANASC’ de nossa tabela) e fará a subtração da “dat a corrente” pela data do campo DATANASC.
Dentro da função, criamos uma variável (vIDADE), onde armazenaremos o valor a ser retornado pela função. Note também que a função possui retorno do tipo String (RETURNS varchar(30)), que deverá ter o tamanho suficiente para comportar o resultado retornado. Ou seja, se o valor retornado tiver 15 caracteres, o ‘RETURNS’ da função precisa ter tamanho de 15 ou mais caracteres, senão, pode acontecer de não retornar nenhum valor.

Após ter criado a tabela, inserido as linhas na mesma e criado a função, execute a seguinte instrução:


SELECT NOME, idade(DATANASC) IDADE FROM clientes;


No SQL acima, a consulta irá retornar o Nome, e a idade assim: “XX anos”, para cada cliente.

Como você viu, utilizar funções dentro do banco de dados por ser muito mais prático do que fazê-lo dentro da aplicação (me refiro a funções para retorno de dados, claro).

Lembrando que este exemplo é apenas uma base, pois podemos criar funções para qualquer necessdiade, como: calculo de preços, juros de mora, datas, horas, concatenação de campos complexos, junções de tabelas (como nos inner, left e right joins (desde que precise retornar apenas um valor), e muito mais.

JSON e Generics - Serializando Objetos


Desta vez vou demonstrar duas novas tecnologias que estão sendo muito melhoradas no Delphi desde a versão 2009 até a ultima versão o Delphi XE. Generics é uma forma de poder

...passar parâmetro de tipos para classes e métodos, possibilitando assim reutilização de código, por exemplo e, JSON (JavaScript Object Notation) é uma forma de troca de dados entre aplicações, semelhante ao XML, porém com uma sintaxe bem mais simples e leve. O Delphi XE, como algumas versões anteriores, dá suporte a implementação usando JSON, e em nosso exemplo vamos criar um método totalmente genêrico que recebe um objeto e um tipo e usaremos o JSON para formatar este objeto e gravar no disco usando a nova classe de IO (input/output) do Delphi, e um método de leitura deste arquivo no formato JSON para retornar o mesmo a um Objeto, novamente passando o tipo do objeto e o caminho onde se encontra o arquivo.

Primeiro vamos criar uma nova classe do tipo TPessoa:

type
  TPessoa = class
  private
    { Private declarations }
    FPessIden: Integer;
    FPessNome: string;

  public
    { Published declarations }
    property PessIden: Integer read FPessIden write FPessIden;
    property PessNome: string read FPessNome write FPessNome;

  end;

Para conseguirmos desenvolver nossos métodos, temos antes que adicionar ao uses as unit’s citadas abaixo. Acima de cada unit tem a descrição de sua função no projeto:

uses
  SysUtils,

  { Unit que contém os novos métodos de I/O }
  IOUtils,

  { Unit's necessárioas para usar JSON }
  DBXJSONReflect, DBXJSON,

  { Unit necessária para usar Generic }
  Generics.Collections;

Agora vamos criar nossa classe que irá conter os métos necessários para carregar e salvar os dados no disco. O class antes da function indica que estes métodos serão estáticos, não sendo necessário instânciar a classe TJSONTools para usar estes métodos, e a descrição T : class, indica que este método recebe um tipo e que a variável obj passada por parâmetro é deste tipo e, na outra função que ela retorna o tipo especificado.

type
  TJSONTools = class
    public
    { Public declarations }
    class function saveFileJSON(obj: T; const filePath: string): Boolean;
    class function loadFileJSON(const filePath: string): T;
  end;

Agora nosso método que irá gravar no disco o objeto da classe descrita acima.:

class function TJSONTools.saveFileJSON(obj: T; const filePath: string): Boolean;
var
  Marshal: TJSONMarshal;

begin
  Marshal := TJSONMarshal.Create(TJSONConverter.Create());
  try
    try
      TFile.WriteAllText(filePath, (Marshal.Marshal(obj) as TObject).ToString);

      Result := True;
    except
      Result := False;
    end;
  finally
    FreeAndNil(Marshal);
  end;
end;

Agora o método responsável por ler o arquivo e carregar novamente os dados para um objeto:

class function TJSONTools.loadFileJSON(const filePath: string): T;
var
  Unmarshal: TJSONUnMarshal;
  obj: TJSONObject;

begin
  Unmarshal := TJSONUnMarshal.Create();
  try
    try
      if not(FileExists(filePath)) then
        Exit(nil);

      obj := TJSONObject.ParseJSONValue(
        TEncoding.ASCII.GetBytes(TFile.ReadAllText(filePath)),
        0) as TJSONObject;

      Result := T(Unmarshal.Unmarshal(obj));
    except
      Exit(nil);
    end;
  finally
    FreeAndNil(Unmarshal);
  end;
end;

Agora uma forma de poder usar nossas classes:

var
  objPessoa: TPessoa;

begin
  objPessoa:= TPessoa.Create();
  objPessoa.PessIden := 1;
  objPessoa.PessNome := 'Active Delphi';

  if (TJSONTools.saveFileJSON&ltTPessoa&gt(objPessoa, 'C:\pessoa.txt')) then
    ShowMessage('Criou o arquivo no caminho: ' + #13 + ' C:\pessoa.txt');

  objPessoa := TJSONTools.loadFileJSON&ltTPessoa&lt('C:\pessoa.txt');
  if (Assigned(objPessoa)) then
  begin
    ShowMessage(
      'PessIden: ' + IntToStr(objPessoa.PessIden) + #13 +
      'PessNome: ' + objPessoa.PessNome
    );
  end
  else
    ShowMessage('Não foi possivel des-serializar o objeto');
end;

Este foi apenas um exemplo didático usando JSON e Generics no Delphi. Estes métodos ainda podem ser refatorados e até criado validações para tratar possíveis erros de parâmetros, que podem ser identificados criando testes unitários sobres estes métodos.

Obrigado pela leitura e até a próxima!

Clique aqui para fazer o download do exemplo, feito com Delphi XE

domingo, 14 de agosto de 2011

Dicas para melhorar a performance do servidor Firebird


Defina índices para todas as colunas que vão ser usadas para join’s ou ordenações. Os índices são estruturas de dados de árvores balanceadas que fornecem um grande aumento na velocidade da procura dos valores nas colunas em que os índices são definidos. Isto é especialmente útil quando ordenamos por uma coluna em particular ou juntamos duastabelas por uma coluna que as duas têm em comum.Lembre que um índice Firebird é específico para uma direção de ordenação, ascendente ou descendente (ASCENDING x DESCENDING), e a direção de um índice deve ser igual à direção escolhida quando se faz a ordenação. Se você for usar as duas direções, ascendente ou descendente, crie dois índices para as chaves de ordenação. As inclusões e alterações usam índices para serem gravadas, o que pode prejudicar a performance durante um INSERT ou UPDATE, mas alguns custos impostos durante a entrada de dados podem resultar em um grande ganho de performance mais tarde na pesquisa destes dados. Para minimizar a perda de performance durante um INSERT, considere em desabilitar os índices durante um grande volume de INSERTs. Isto irá ‘desligar’ os índices, tornando-os indisponíveis para ajudar a acelerar as pesquisas, mas também não vão ser atualizados durante os INSERTs.Então, reabilite-os depois de terminados os INSERTs, e os índices serão atualizados e balanceados uma vez para todos os dados incluídos.Periodicamente reconstrua os índices, desativando e ativando novamente (ALTER INDEX nome INACTIVE; seguido de ALTER INDEX nome ACTIVE;). Recalcule o índice seletivamente (SET STATISTICS INDEX nome;) se uma mudança na tabela afeta a distribuição regular dos valores e dados. Os índices também são reconstruídos do mesmo modo durante o restore.

Otimize as pesquisas 


O Firebird irá analisar uma pesquisa (query) e o otimizador fará a melhor estimativa de quais índices deverão ser empregados para acelerar a pesquisa. Mas nenhum otimizador automático é infalível. Para queries complexas que serão usadas freqüentemente, ou que serão aplicadas a um número elevado de dados, construa a pesquisa cuidadosamente. Usea opção SET PLAN da ferramenta ISQL para testar queries, ver sua performance e ver qual PLAN o otimizador escolheu. No Interbase v4.0, v4.1 e v4.2 existem alguns problemas conhecidos em tais queries usando a sintaxe JOIN na linguagem ANSI SQL-92, que não são analisados e otimizados corretamente. Evite esta sintaxe ou, se tiver que usá-la, especifique seu próprio PLAN.  


Ajuste o cache do Firebird 


O Firebird mantém seu próprio cache de páginas do banco de dados correntemente em uso na RAM do servidor. O tamanho padrão do cache na versão superserver (Windows) é 2048 páginas de banco de dados (isto é compartilhado por todos os clientes conectados a um dado banco de dados). Para um banco de dados com 1Kb de páginas, isto ainda ésomente 2048Kb. A maioria dos servidores tem muita memória, então ponha em uso! Experimente ajustar o cache de 256 até 10.000 páginas. Em algum ponto verá diminuir os retornos, mas alguma experimentação irá revelar este ponto. 


Faça Backup / Restore 


Existem vários benefícios em fazer periodicamente um backup/restorede um banco de dados Firebird usando o utilitário GBAK:-reconstruir índices;-eliminar versões obsoletas de registros (‘garbage’);-defragmentar páginas de dados;-regravar tabelas de dados contiguamente; e

-fazer uma cópia dos dados!

Use processamento Cliente-servidor 


Usando funções externas (UDFs), Triggers, Stored Procedures e Select Procedures fazem com que o banco de dados faça muito processamento no servidor, que provavelmente é um computador muito mais potente que a estação de trabalho. Esta técnica evita também tráfego de rede desnecessário.  


Use o cache de disco do Sistema Operacional 


A maioria dos sistemas operacionais oferece sistema de cache de disco para leitura/gravação. Com isto os programas podem fazer suas gravações na RAM do servidor, e o sistema operacional irá salvar este conteúdo fisicamente no disco periodicamente. Fazendo sempre pequenas gravações ou fazer de uma só vez numa operação maior podeaumentar bastante a performance de leitura/gravação de dados. Usar este sistema de cache de disco é algumas vezes chamado de leitura/gravação assíncrona (asynchronous I/O) ou gravação em cache (cached writes). Forçando a gravação direta dos dados no disco,sobrepondo o sistema de cache, é chamado de leitura/gravação síncrona (synchronous I/O) ou gravação forçada (forced writes). O sistema de leitura/gravação assíncrona tem o benefício de aumentar a performance, mas como a RAM é um sistema volátil de armazenamento, pode perder dados se houver uma queda de energia ou uma falha no servidor ou ainda uma reinicialização do servidor quando o cache ainda não tiver sidodescarregado no disco. A leitura/gravação síncrona garante que nada será perdido por estar no cache, mas ler ou gravar diretamente no disco é bem mais lento que fazê-lo na RAM.O Firebird permite fazer a leitura/gravação assíncrona ou síncrona. O comando GFIX –WRITE SYNC .GDB faz o banco de dados usar a gravação forçada (forced writes), e o comando GFIX –WRITE ASYNC .GDB faz o banco usar a gravação em cache (cached writes).A gravação em cache pode ganhar muito em performance no Firebird, mas devem ser tomadas medidas de proteção contra perda de dados. Por exemplo, usando espelhamento de disco para manter uma duplicação dos dados. Usando também no-break e estabilizadores para garantir uma energia estável e ininterrupta para o servidor. Com medidas como estas,a leitura/gravação assíncrona pode trazer benefícios sem sacrificar a segurança. 


Administre o protocolo de rede 


O protocolo TCP/IP é muito mais rápido que o SPX ou NetBEUI. Conectar sua rede usando TCP/IP resultará em uma melhor performance. O serviço NetBEUI tem um prioridade baixa em servidores NT, mas existe um meio no sistema operacional para aumentar a prioridade deste serviço. Alguns usuários dizem ter aumentado a performance depois de ter feito isto. Veja na documentação do Windows NT as instruções paraajustar a prioridade dos serviços NetBEUI. NOTA: A partir do Windows NT 4.0, a performance da implementação do Microsoft NetBEUI foi aumentada. É agora pelo menos tão boa quanto a implementação do Microsoft TCP/IP, entretanto, em uma rede ocupada, o NetBEUI é ainda limitado por ser um protocolo independente de conecção. Isto significa que cada host na rede deve checar cada pacote para ver seu conteúdo. Com mais hosts transmitindo na rede, cada host deve manipular uma crescente leitura de "números errados". 


Escolha o sistema operacional 


Sistemas operacionais basados no UNIX/Linux são sempre mais rápidos em multiprocessamento que sistemas Windows em um mesmo equipamento. Se velocidade é algo importante para você considere o uso desta plataforma. Pense sempre em utilizar o Firebird como servidor dedicado, que não funcione como servidor de arquivos, pois ele poderá ficar sentado no "banco de trás" nas questões de prioridade de processamento.No Windows NT o servidor é configurado para dar prioridade ao compartilhamento de arquivos. Você pode modificar esta configuração no servidor: Painel de Controle -> Rede -> Software de Rede. Modifique para "balancear" ou "servidor de banco de dados". Esta modificação irá resultar em uma melhora dramática na performance do Firebird.O uso de sistemas operacionais não específicos para uso de Servidores como os Windows 9x, Me ou XP Home podem prejudicar sua performance, além das fragilidades conhecidas. 


Considere a limpeza do lixo (garbage collection) 


O Firebird tem por padrão a função de automaticamente limpar as antigas versões dos registros quando estas se tornam muito numerosas. O problema deste método é que se um processo cliente que for sem sorte suficiente para iniciar uma transação que coincida com o início da limpeza automática, vai ter que esperar o trabalho de limpeza. O processo clienteatrasa enquanto o processo de limpeza é feito. Desabilite a limpeza automática (automatic garbage collection), usando GFIX –h 0, em favor da limpeza programada (scheduled database sweep), usando GFIX –s. Isto irá eliminar a perda na performance do cliente.Fazer um backup e restore efetivamente faz a mesma coisa do que uma limpeza completa no banco de dados. O backup somente copia a versão mais recente de cada registro, nunca copia versões anteriores, assim, quando os dados são restaurados, existe somente uma versão de cada registro. Existem também outros benefícios de fazer backup/restore,descritos na seção própria deste artigo. Falando em limpeza do lixo, muitos programadores não se dão conta da necessidade de iniciar e terminar (START e COMMIT) suas transaçõescom o banco de dados. Abrir transações impede que a varredura periódica complete a limpeza do lixo, e a performance irá sofrer progressivamente com o tempo. 


Normalize seu banco de dados 


Projete seu banco de dados com uma normalização adequada dos dados. Registros que têm muitos grupos de campos repetidos são maiores que deveriam ser, podem aumentar o custo de ordenação e ainda podem causar a ocupação de mais páginas do que o necessário,resultando em uma maior fragmentação de páginas e um banco de dados enorme sem necessidade.


Pense nas transações 


Projete sua aplicação para que resolva o mais rápido possível as transações depois de abertas. Freqüentemente os programadores de aplicação abrem uma transação e apresentam uma tela de entrada de dados para o usuário. Ao invés disso, pegue os dados com o usuárioantes, abra uma transação para dar o INSERT e então dê o COMMIT na transação imediatamente. O propósito disto é diminuir o tempo de duração das transações, que diminui a probabilidade de duas aplicações concorrentes conflitarem em um bloqueio de registro. Isto também ajuda a evitar muitos ROLLBACKs e tráfego de rede, já que a sua aplicação decide quando submeter os dados ao banco ou descartá-los.  


Programe com a API do Firebird 


Um programa escrito em C com SQL embutido responde melhor que uma aplicação cliente Firebird escrita em Paradox, Delphi ou outra ferramenta visual. A idéia é programar diretamente na API do Firebird ao invés de adicionar camadas intermediárias com mais um protocolo de rede sobre ele.

domingo, 31 de julho de 2011

Migrando aplicativos do Delphi 5 para o 6 e 7


Neste artigo, será demonstrado como solucionar alguns problemas comumente encontrados por desenvolvedores Delphi quando fazem migração de aplicativos e componentes de versões anteriores ao Delphi 6 (mais precisamente o Delphi 5) para as versões 6 e/ou 7. O que funcionar para o Delphi 6 provavelmente funcionará para o Delphi 7, já que as mudanças mais expressivas nas bibliotecas padrões para a criação de componentes foram realizadas no Delphi6, por motivos de compatibilidade.
A Borland realizou diversas mudanças em métodos e classes nas antigas bibliotecas (VCL) em decorrência da necessidade de compatibilizar o máximo possível o Delphi 6 com o Kylix, ou em outras palavras, a biblioteca de componentes VCL (Visual Component Library) com a biblioteca inter-plataforma CLX (Component Library for Cross-Plataform), utilizada mais especificamente no Kylix (apesar da mesma ser utilizada no Delphi também).

Serão listadas a seguir as principais mudanças que conheço e que devem ajudar o leitor a migrar seus aplicativos e componentes para as versões 6 e 7 do Delphi. São estas:

* A implementação de Classes e Métodos da unit "Dsgnintf.pas" foram divididos em duas units (pelo menos até onde conheço): a DesignIntf.pas e a DesignEditors.pas. Ambas estão localizadas em ($Delphi)\Source\ToolsAPI, onde ($Delphi) é o diretório onde o Delphi está instalado. Ao invés de incluir o caminho citado em seu "Enviroment Options\Library\LibraryPath" para utilizar as units, você pode optar por colocar na seção requires (e realmente acho preferível isto se estiver trabalhando com pacotes) o pacote "designide.dcp", localizado na pasta ($Delphi)\Lib. Ele já inclui estas bibliotecas e outras comumente utilizadas além de uma nova interface, a IComponentDesigner, contida em ComponentDesigner.pas.

* A procedure EditProperty da classe TDefaultEditor teve seus parâmetros alterados; no Delphi 5, a mesma era declarada desta forma:

  EditProperty(PropertyEditor: TPropertyEditor; var Continue, FreeEditor: Boolean); virtual;

e agora a mesma é declarada assim:

  procedure EditProperty(const Prop: IProperty; var Continue: Boolean); virtual;

Observe que o parâmetro PropertyEditor do tipo classe TPropertyEditor passou agora a se chamar Prop e ser do tipo interface IProperty e, o parâmetro FreeEditor deixou de existir. Essa nova implementação é realizada na unit "DesignEditors.pas".

* As rotinas de manipulação de objetos ou variáveis do tipo Variant passaram da unit System.pas para uma unit própria, a Variants.pas.

* Interfaces como a IFormDesigner , IDesignerSelection e IdesignerSelection sofreram alterações. Quanto as duas primeiras, as mudanças são respectivamente estas: mudança de nome para "IDesigner" e a adição de uma função GET que retorna um TPersistentequando indicado o índice do seu membro. Exemplo:

Nas versões anteriores ao Delphi 6, se você quisesse usar o TPersistent de um objeto, deveria escrever:

  var p: TPersistent;
  ...
  P := Selections[i] as TPersistent;

Agora basta escrever:

  var p: TPersistent;
  ...
  P := Selections.get[i];

* A função CollectionsEqual implementada na Unit Classes.pas teve seus parâmetros alterados; no Delphi 5, a mesma era declarada desta forma:

  function CollectionsEqual(C1, C2: Tcollection): Boolean;

e agora a mesma é declarada assim:

  function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;

* As constantes que estavam na unidade DesignConsts.pas, foram colocadas juntamente com os menus em DesignMenus.pas.

Dicas

Para aproveitar um mesmo código-fonte em diferentes versões do Delphi, você pode utilizar a diretiva de compilação {$IFDEF name}, que especifica que um determinado bloco de código compreendido pela cláusula só será compilado se o parâmetro "name" estiver definido.

Parâmetros de versão

  Delphi3 - VER80;
  Delphi5 - VER130;
  Delphi6 - VER140;
  Delphi7 - Ver150;

Como utilizar

Exemplo1:
No caso de um código que referencie a DsgnIntf.pas e seja utilizado no Delphi 6 ou posterior, você pode fazer o seguinte:

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  {$IFDEF VER130} // se for Delphi5
    DsgnIntf
  {$ELSE}
    {$IFDEF VER140} // se for Delphi6
      DesignIntf, DesignEditors
    {$ELSE}
      {$IFDEF VER150} // se for Delphi7
        DesignIntf, DesignEditors
      {$ENDIF}
    {$ENDIF}
  {$ENDIF}

Observação: No lugar de você colocará o caractere adequado, "," para continuar a declaração de Units ou ";" para fechamento de declaração.

Exemplo 2:
No caso de um código que referencie a System.pas e seja utilizado no Delphi 6 ou posterior, você pode fazer o seguinte:

uses
  Windows, Messages, SysUtils, Classes, Graphics, System,
  {$IFDEF VER140} // se for Delphi6
    Variants
  {$ELSE}
    {$IFDEF VER150} // se for Delphi7
       Variants
    {$ENDIF}
  {$ENDIF}

Bem, desejo que isto possa ajudar todos aqueles que trabalhem com Delphi, seja usuário iniciante, intermediário ou avançado.

domingo, 24 de julho de 2011

Criando um Calendário Simples

Veja nesta dica como criar um calendário bastante simples, explorando o componente TMonthCalendar

    Crie um novo formulário em sua ara de trabalho(file > new > form).
    Altere suas propriedades de acordo com a tabela seguinte:

Propriedade         Valor

BordeStyle          bsDialog
Caption             Calendário
Color               clBtnFace
Font.Name           Arial
Font.Size           7
FormStyle           fsNormal
Height              437
Name                Calendario
Position            poScreenCenter
Width               703

    Insira no formulário do calendário um componente monthcalendar localizado na paleta win32.
    Ajuste suas propriedades para:

Propriedade         Valor
Aling               alClient
WeekNumbers         True (exibe o numero das semanas)

    Caso seja necessario, ajuste a altura e largura da janela até que o calendário apresente os 12 meses.

    O componente MonthCalendar possui a propriedade chamada Date, cuja função é definir a data a ser exibida. O problema é que esta propriedade fica ancorada com a data de criação do componente, ou seja, se você o inserir em um form em 16/12/08, sua data ficará fixada em 16/12/08, independente de qual seja a data em que você estiver executando o programa. Para resolver este problema, insira no evento onActivate da janela calendário:

procedure TCalendario.FormActive(Sender: TObject);
begin
  MONTHCALENDAR1.DATE := DATE;
end;

    Pressione F9 e veja o resultado.

Você também pode personalizar seu calendário através da propriedade CalColors. Se puder usar um form com uma maior extensão para visualização, sugiro a fonte arial 8 em negrito. Fica perfeito.

terça-feira, 19 de julho de 2011

Criação de DLL - Dynamic Link Libraries


Vou explicar em breves palavras como criar um sistema com a utilização de arquivos dll’s.
1º Regras para escrever uma DLL no Delphi : As funções e/ou procedimentos de DLL devem seguir estas regras:
- Precisam estar listados na cláusula exports da DLL. Isso possibilita que no momento de chamar a funções e/ou procedimentos, seja aceito pelo programa principal.
- As funções exportadas precisam ser declaradas como stdcall;
- Os tipos de parâmetros de uma DLL devem ser de tipos padrão do Windows, pelo menos se você quiser usar a DLL dentro de outros ambientes de desenvolvimento, como por exemplo, C++.
- Uma DLL pode usar dados globais que não serão compartilhadas pelos programas base. Sempre que uma aplicação carrega uma DLL, ele armazena os dados globais da DLL em seu próprio espaço de endereço
 
2º Neste passo vamos tirar a dúvida a uma pergunta muita frequente; “Como criar uma DLL?”.
Dando início ao desenvolvimento de DLLs no Delphi, vou mostrar a vocês uma biblioteca muito simples. O principal objetivo desse exemplo é mostrar a sintaxe utilizada para definir uma DLL no Delphi.
Para começar, selecione o comando File/New, escolha a opção DLL na página New do Object Repository. Isso cria um Codigo-Fonte muito simples.
Aqui está código fonte da nossa primeira DLL:
 
Library MINHADLL.DLL;
uses SysUtils,
Classes;
{$R *.res}
function Triple(N: Integer): Integer; stdcall;
begin
  Result := N * 3;
end;
function Double (N: Integer): Integer; stdcall;
begin Result := N * 2;
end;
exports Triple, Double;
end.

3ª E agora por fim vamos incluir a dll num projecto Win32.

Para fazer um formulário usando nossa DLL vamos abrir o Delphi e criar uma nova aplicação.
Colocar dois Edits e dois Buttons, no evento OnClick dos botões faremos as chamadas das funções. Para chamar um função de uma DLL é preciso apenas declarar as funções de forma igual a declarada na dll, ou seja, nome, parâmetros e tipos.
Aqui fica um exemplo:

unit Unit1;
  interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
  type TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
  procedure Button1Click(Sender: TObject);
  procedure Button2Click(Sender: TObject);
  private { Private declarations }
  public { Public declarations }
end;
var Form1: TForm1;
implementation
{$R *.dfm}
 
{funções da DLL Delphi}
  function Double (N: Integer): Integer; stdcall; external 'MINHADLL.DLL';
  function Triple (N: Integer): Integer; stdcall; external 'MINHADLL.DLL';
  procedure TForm1.Button1Click(Sender: TObject);
  var x, y: integer;
  begin
    x := StrToInt(Edit1.Text);
    y := Double(x);
    Edit1.Text := IntToStr(y);
  end;
 
  procedure TForm1.Button2Click(Sender: TObject);
  var x, y: integer;
  begin
    x := StrToInt(Edit2.Text);
    y := Triple(x);
    Edit2.Text := IntToStr(y);
  end;
end.

domingo, 10 de julho de 2011

Guia Inicial Rápido Para Otimização de Índices


Veja neste artigo a tradução de um post feito por Paul Beach em seu blog, que foi mencionado pelo site firebirdnews.org, mas cujos conceitos se aplicam a praticamente todos os SGBDs.

Abaixo, é apresentado um rápido guia inicial com cinco (na verdade seis) pontos para a otimização de índices, cortesia de Pavel Cisar.

1. Sempre defina TODAS as regras (constraints) de integridade: chaves primárias, estrangeiras e índices únicos. Isto será automaticamente utilizado na otimização de junções (joins).

2. Defina índices separados para CADA COLUNA que será utilizada em regras adicionais de suas consultas (ex: filtros em cláusulas WHERE), que não fazem parte do primeiro ponto (pk's, fk's e uniques).

3. Atualize as estatísticas de seus índices regularmente, visto que dados são inseridos / modificados / excluídos em sua base de dados. Uma boa regra geral é atualizar as estatísticas dentro de suas rotinas de manutenção (quando fizer backup, sweep, etc.), e/ou sempre que você inserir / alterar um quarto de todos os registros, uma vez que a tabela possua mais de 10.000 registros.

4. Uma vez tendo dados representativos do mundo real em seu banco de dados, você pode avaliar a usabilidade dos índices para eliminar aqueles que não ajudam suas instruções SQL (um índice insignificante apenas tornará lento seus inserts e updates!) e adicionar novos índices compostos ou de expressões, que aumentem a performance de instruções específicas.

5. Índices inúteis são normalmente aqueles com baixa seletividade (poucos valores distintos). Execute algumas consultas com filtros condicionais em colunas com baixa cardinalidade e verifique quando o otimizador usa o índice ou não. Se o índice de baixa seletividade é sempre ou frequentemente usado em outras condições de filtro, você pode melhorar a sua seletividade e consequentemente a sua usabilidade, criando um índice composto com as colunas que são usadas nestes outros filtros, ao invés de usar índices independentes em cada coluna.

6. Se você sempre / frequentemente usa um grupo de colunas para filtros, um índice composto nestas colunas pode melhorar a performance do comando, mas faça isso apenas se não estiver satisfeito com a performance que os índices em colunas individuais provêem.

De Enum para String e de String para Enum


Há algum tempo atrás precisei criar um enumerado e depois carregar este enumerado em um ComboBox. Toda vez que surgia essa necessidade eu criava o enum e criava um array de string com todas as opções do enum, aí com um loop no array eu populava o ComoboBox. Só que toda vez que precisava acrescentar um nova opção no enum eu tinha que atualizar o array.

Isso começou me incomodar! Foi aí que lembrei que quando desenvolvemos componentes e criamos uma property do tipo de um enum na seção published, o Delphi exibe esse enum no ObjectInspector com um ComboBox, e ele faz isso automaticamente! Aí pensei: “isso deve ser possível” já que o Delphi faz. Então entrei em contato com um amigo meu muito fera em Delphi, “Adriano Santos”, e ele conseguiu a solução que eu gostaria de publicar.

Vamos lá, vou dar o exemplo referente a minha necessidade na época que estava desenvolvendo uma comunicação com uma balança através da porta COM.

Criando o enum:

type
  TPorta = (COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9);

Criando a property do tipo do enum:

  private
    FPort: TPort;
  public
    property Port: TPort read FPort write FPort;
  end;

Criando um método que vai popular uma lista do Tipo TStrings, assim, com esse método posso popular objetos como: TComboBox, TMemo, TListBox ou até mesmo uma variável do Tipo TStrings. Primeiro deve ser declarado na seção uses a unit: TypInfo.

class procedure TSerialComunication.PopulateListPort(AList: TStrings);
var
  i: Integer;
Begin
  for i := Ord(Low(TPort)) to Ord(High(TPort)) do
    AList.Add(GetEnumName(TypeInfo(TPort), i));
end;

Agora basta chamar o método e popular o ComboBox:

procedure TfrmPrincipal.btnPopulatePortClick(Sender: TObject);
Begin
  TSerialComunication.PopulateListPort(cbbPort.Items);
end;

Essa foi a solução que meu amigão Adriano Santos meu passou, achei genial.

Agora imagina se precisar pegar um item do ComboBox que é uma string e passar pra uma variável do tipo do Enum? Antigamente eu usaria um case pra saber qual foi o item selecionado e passar a opção do enum correta, mas agora posso usar a mesma idéia e converter automaticamente enum para string ou vice-versa! Então criei dois overload de um método Convert:

class function TSerialComunication.Convert(const APort: string): TPort;
begin
  Result := TPort(GetEnumValue(TypeInfo(TPort), APort)) ;
end;

class function TSerialComunication.Convert(const APort: TPort): string;
begin
  Result := GetEnumName(TypeInfo(TPort), Integer(APort)) ;
end;

Agora ficou facil, basta chamar os métodos de conversão!

Convertendo o item do combobox para o enum:

procedure TfrmPrincipal.btnStringToEnumClick(Sender: TObject);
var
  vPort: TPort;
begin
  vPort := TSerialComunication.Convert(cbbPort.Text);
end;

Convertendo de Enum para uma string:

procedure TfrmPrincipal.btnEnumToStringClick(Sender: TObject);
var
  vPort: TPort;
begin
  vPort := COM1;
  ShowMessage(TSerialComunication.Convert(vPort));
end;

terça-feira, 5 de julho de 2011

Repositório do Delphi


O repositório do Delphi é um local para armazenamento de objetos, como formulários e projetos, que facilita o compartilhamento desses objetos por vários projetos. Quando você clica em File|New... para criar um novo objeto, você pode escolher um dos itens do repositório.
Acrescentando um formulário ao repositório
    
Abra um projeto DPR, e dentro dele o formulário "Form" (Form1.pas). Esse formulário está sendo compartilhado dentro do mesmo projeto, mas se você quiser reutilizá-lo em outros projetos, pode acrescentá-lo ao repositório. 
     Para isso, clique com o botão direito e em Add to Repository. Você deve informar o título do item, uma descrição e qual a página onde ele será inserido (se você digitar um nome de página que não existe, uma nova será criada), além do seu nome para indicar qual o autor desse item. Opcionalmente você pode escolher um ícone que será usado para representar o item. Para o exemplo digite o seguinte: 

   Title: Formulário para uma tabela
   Description: Formulário de banco de dados para uma tabela
   Page: Forms (default)
   Author: seu nome 

     O botão "Browse" permite você procurar um ícone , para representar sua classe de formulário, caso não informe ele irá mostrar o seguinte ícone . Clique Ok. O novo item será adicionado ao repositório. Agora crie um novo projeto com File|New Application e veremos como o item pode ser reutilizado.
     Formas de criar novos objetos
    
Se você clicar em File|New... e na página "Forms", você verá que o novo item ("Formulário para uma tabela") está dentro do repositório. Agora ele está disponível em qualquer projeto, permitindo criar novos formulários a partir dele.
     Existem três opções para criar novos objetos a partir do repositório: copiar [copy] o item, herdar [inherit] do item (criar uma nova classe derivada) ou usar [use] o item diretamente.
Se você marcar a opção "Copy" e clicar Ok, o Delphi cria uma cópia separada do objeto original que está no repositório. Qualquer alteração no original posteriormente não vai afetar essa cópia e qualquer alteração na cópia é independente do que está no repositório. Note que a unidade do formulário não foi salva e está em memória como "Unit2". Isso permite você salvar com um nome qualquer.
     A opção "Inherit" (herdar) faz diferente: faz uma referência ao original (ou seja, acrescenta o formulário original dentro do projeto) e cria uma nova classe derivada da original, TForm1. O novo formulário será chamado de 'FormBase1', com a classe 'TFormBase1'. A unidade do formulário não foi salva ainda. Nesse caso, qualquer alteração no original, que está no repositório, será herdada pela classe derivada.
     A opção "Use" não copia o objeto original, mas compartilha com o projeto atual. Nesse caso, alterações feitas no item dentro do projeto afetam o item no repositório e vice-versa. Se vários projetos usarem o mesmo item, todos eles compartilham o mesmo item.
     Adicionando um projeto ao repositório
    
Para reutilizar um projeto inteiro, você pode acrescentá-lo ao repositório com o menu Project|Add to Repository... e informar a descrição do item como antes.
     Gerenciando o repositório
    
Para gerenciar as páginas do repositório e os itens de cada página, você pode clicar em   Tools|Repository. Na caixa de diálogo você pode criar, renomear ou excluir uma página do repositório (você só pode excluir se ela estiver vazia). É possível também mudar a ordem das páginas.
     Você pode mover os itens entre páginas arrastando o item da lista da esquerda e soltando sobre a página desejada. Também é possível renomear ou alterar características de um item ou excluir o item.
     Compartilhando o repositório numa equipe
    
Quando uma equipe de desenvolvedores trabalha em conjunto, é importante que eles possam compartilhar o repositório, de forma que novos itens adicionados a ele estejam disponíveis para toda a equipe.
     Para compartilhar o repositório, você deve usar um diretório na rede que seja acessível a todos os desenvolvedores. Por exemplo, se G: é uma letra de drive que aponta para a rede, você pode usar G:\REPOS. Você deve também copiar os arquivos do repositório do Delphi para esse diretório.
     Os arquivos do repositório do Delphi são armazenados num subdiretório OBJREPOS, abaixo do diretório onde o Delphi foi instalado (geralmente C:\Arquivos de Programas\Borland\Delphi6). Além desses arquivos, o Delphi usa um arquivo de texto chamado DELPHI32.DRO, localizado no subdiretório BIN do Delphi.
     Para compartilhar o repositório na rede, faça o seguinte: 
     • Crie um diretório compartilhado (e.g. G:\REPOS). Verifique que todos os desenvolvedores têm acesso a ele e usam a mesma letra de drive; 
     • Copie o repositório de um computador para o diretório compartilhado (G:\REPOS), ou seja, todos os arquivos do subdiretório OBJREPOS do Delphi, mais DELPHI32.DRO, do subdiretório BIN; 
     • Em cada um dos computadores, no Delphi, clique em Tools|Environment Options. Na página Preferences Em "Shared Repository", digite o caminho do diretório compartilhado. 
Agora lembre-se que qualquer alteração ou acréscimo feito por um desenvolvedor afeta todos os outros. É importante também notar que quando você quiser compartilhar um objeto, ele deve ser salvo num diretório compartilhado também, acessível a todos (por exemplo, G:\BIBLIOTECAS).

Como instalar componentes no delphi


Existe a possibilidade de instalar componentes através de três tipos de extensões de arquivos: *.pas, *.dcu, *.dpk.
Explicando um por um:
1 - Para arquivos que necessitam de um Package (normalmente componentes que possuem somente o *.PAS), execute o Delphi e feche o projeto, acesse o menu 'Component' e clique na opção 'install component'. Na janela que se apresenta, acesse a aba ' Into New Packages', clique no botão 'Browse' ao lado da caixa de texto 'Unit File Name' abra o arquivo com extensão *.pas, dê ok e logo após 'Compile' e 'Install' e o arquivo criará uma aba na barra de componentes com um nome para a sua localização.

2 - Para instalar pacotes de componentes (Packages, arquivos com a extensão *.DPK), execute o Delphi e feche o projeto, acesse o menu 'File' e clique na opção 'Open', abra o arquivo que contém os componentes. Dê Ok e depois é só clicar en 'install'. Pronto seu pacote de componentes será instalado.


3 - Para arquivos com a extensão *.dcu, é um pouco mais complicado. Acesse o menu 'Component' e clique na opção 'install package'. Verifique se na lista 'Design packages' existe a opção 'Borland user component', se sim, clique no botão 'edit', abrirá uma caixa de mensagens, clique no botão 'yes'. Na janela que aparece clique no botão 'add', na janela que se abrirá clique no botão 'browse' da caixa de texto 'unit file name'. Na caixa de combinação 'files of type' escolha 'Delphi compiled unit(*.dcu)', depois na caixa de texto 'File name' direcione o arquivo a ser instalado, clique no botão 'open'. Clique no botão 'ok' na janela que aparece e clique no botão install. Pronto o seu componente será instalado.


Obs:Se na lista 'Design packages' não tiver a opção 'Borland user component' você deverá primeiro instalar componentes que estão em arquivos com extensão *.pas.

terça-feira, 28 de junho de 2011

Stored Procedure para saber os aniversariantes por dia/mês


Administrador Essa procedure lhe retorna todos os aniversariantes de um determinado período de dia e mês. Foi feita originalmente para Firebird, mas pode ser facilmente adaptada para qualquer outro banco que suporte Stored Procedures

Observação: este artigo é uma alternativa ao material enviado pelo amigo cruzeirense, pois em sua dica, exige-se que o ano de nascimento também seja informado como parâmetro da procedure. Seu material pode ser visto neste link:

No exemplo, utilizarei uma tabela chamada FUNCIONARIO, conforme pode ser visto abaixo:

/* Estrutura da tabela FUNCIONARIO
CREATE TABLE FUNCIONARIO (
    ID               INTEGER,
    NOME             VARCHAR(50),
    SALARIO          NUMERIC(15,2),
    DATA_NASCIMENTO  TIMESTAMP
);
*/

SET TERM ^ ;

CREATE PROCEDURE ANIVERSARIANTES (
    strdta_ini varchar(5),
    strdta_fim varchar(5))
returns (
    nome varchar(50),
    salario numeric(15,2),
    dta_nasc timestamp)
as
declare variable dta_ini timestamp;
declare variable dta_fim timestamp;
BEGIN
    SELECT CAST(:STRDTA_INI||'.'||CAST(EXTRACT(YEAR FROM
        MAX(DATA_NASCIMENTO)) AS VARCHAR(10)) AS TIMESTAMP) AS B
        FROM FUNCIONARIO INTO DTA_INI;
    SELECT CAST(:STRDTA_FIM||'.'||CAST(EXTRACT(YEAR FROM
        MAX(DATA_NASCIMENTO)) AS VARCHAR(10)) AS TIMESTAMP) AS B
        FROM FUNCIONARIO INTO DTA_FIM;
    WHILE (DTA_INI <= DTA_FIM) DO
    BEGIN
        FOR SELECT NOME, SALARIO, DATA_NASCIMENTO FROM FUNCIONARIO WHERE
        EXTRACT(DAY FROM DATA_NASCIMENTO) = EXTRACT(DAY FROM :DTA_INI) AND
        EXTRACT(MONTH FROM DATA_NASCIMENTO) = EXTRACT(MONTH FROM :DTA_INI)
        ORDER BY NOME, DATA_NASCIMENTO INTO :NOME, :SALARIO, :DTA_NASC DO
            SUSPEND;
        DTA_INI = DTA_INI + 1;
    END
END^

SET TERM ; ^

Agora é só fazer um select como o abaixo e pronto! ;-)

SELECT * FROM ANIVERSARIANTES('01/01', '31/01');

Migração de dados entre bancos ou tabelas


Administrador Esta é uma dica simples de como fazer migração de dados entre bancos ou entre tabelas diferentes, utilizando poucas linhas de código e deixando o trabalho maior na organização dos componentes

Você deve deixar os campos com as mesmas posições em seus componentes DataSet de origem e destino (componentes que farão a leitura de uma tabela e edição na outra). Este DataSet, obviamente pode ser um TQuery, TTable, TIBQuery, TADOQuery, TClientDataSet ou, enfim, qualquer outro componente descendente da classe TDataSet.

Vamos supor que estamos fazendo a migração de um banco Access para Firebird. Para acessar o Access, usaremos um ADOQuery, e para Firebird, ClientDataSet.

Feitas as conexões, o que precisamos fazer é organizar os campos no ADOQuery e no ClientDataSet para que fiquem com as mesmas posições, ou seja, campo[0] do ADOQuery equivale ao campo[0] no ClientDataSet, assim como os demais, campo[1], campo[2], etc.

Organizados os campos, o seguinte código seria suficiente para transferir os dados entre as tabelas:

//código do botão "Transferir"
var
  c: integer;
begin
  //abre a tabela Destino
  ClientDataSet1.Open;
  //abre a tabela Origem
  ADOQuery1.Open;
  //enquanto não chegar ao fim da origem
  while not ADOQuery1.EOF do
  begin
    //abre um novo registro no destino
    ClientDataSet1.Append;
    //para cada campo da tabela destino
    for c := 0 to ClientDataSet1.FieldCount-1 do
      //preenche cada campo com seu valor respectivo da origem
      //ClientDataSet1.Fields[c].Value := ClientDataSet1.Fields[c].Value;
      //Corrigido em 16/07/2009 15:45
      ClientDataSet1.Fields[c].Value := ADOQuery1.Fields[c].Value;
    //grava o registro na tabela destino (em memória)
    ClientDataSet1.Post;
    //confirma as alterações no banco de dados
    //(desnecessário se não for um ClientDataSet)
    ClientDataSet1.ApplyUpdates(0);
    //vai para o próximo registro da origem
    ADOQuery1.Next;
  end;
  //fecha a origem
  ADOQuery1.Close;
  //fecha o destino
  ClientDataSet1.Close;
end;

Backup com MySQL e Delphi


Mesmo que saibamos tudo sobre o MySQL Server 5.0, comandos, sintaxe, recursos entre outras coisas, tudo ficará perdido se um vírus ou outra praga digital invadir o computador e acabar com os nossos dados. Por isso é bom fazer backups da base de dados

O MySQL Server 5.0 tem um recurso chamado mysqldump, que ajuda a fazer backups da base de dados, mas, o problema é que tudo por meio de linhas de comando, o que um usuário final (na maioria dos casos) não saberá fazer.

Para contornar essa barreira, podemos utilizar os arquivos bat, automatizando o processo de backup, ou melhor, do mysqldump! Veja um exemplo:

  cd C:\Arquivos de programas\MySQL\MySQL Server 5.0\bin
  mysqldump nome_da_base_de_dados > caminho_onde_ficara_salvo_o_bakup
  -u Nome_do_usuario_do_mysql -p senha_do_mysql -x -e -a -v
  exit

Essa é a sintaxe do comando que deve conter o arquivo bat, e pronto!

Para executar o bat de uma aplicação em Delphi, use a seguinte linha de comando:

  WinExec(Pchar('Caminho onde esta salvo o arquivo bat'), SW_SHOWNORMAL);

Bom pessoal, espero que tenham gostado da dica.

Segue um link para baixar um pequeno programa que fiz para demonstrar como fazer a conexão com MySQL Server 5.0 e com o exemplo de arquivo bat para o backup: exemplo_backup_mysql.zip

Um lembrete: para compilar o exemplo, copie-o para o seu C:\

segunda-feira, 20 de junho de 2011

Consulta entre datas Usando SQL

Essa é minha primeira dica aqui. Antes de mais nada, gostaria de agradecer muito ao Planeta Delphi, que com suas dicas tem me ajudado a aprender a programar no Delphi. Bom, eu sou iniciante ainda, apesar de estar no meu terceiro programa, que possui uso real em um escritório, estou contente pois estou aprendendo "na raça", sem curso e nem nada, apenas com as dicas daqui e o help do Delphi.

Bom, essa dica se destina a quem estiver tendo problemas na hora de fazer consultas SQL entre datas.

Quem nunca recebeu a mensagem "EDataBase Error: Unassigned Code" quando fez essa pesquisa? O que acontece é que mesmo que utilizemos funções de conversão de data como StrToDate, StrToDateTime e similares, ainda assim não estaremos no mesmo formato de data utilizado nos SGBDs (eu uso o Interbase 7.5).

Acontece que mesmo para os campos de data simples "Date", quando vamos nos relacionar com esses dados devemos estar no tipo primário do BD, que é SqlTimeStamp. Assim sendo, devemos incluir na cláusula "uses" da nossa unit que contém a consulta a unit "SqlTimSt", que nos proporcionará o uso do tipo de dados referido acima.

Devemos então realizar duas conversões:

1 - Converter o tipo de dados DateTime nativo do Delphi em SqlTimeStamp
2 - Passar esse dado convertido como parâmetro da busca.

Eu utilizei dois DateTimePickers do Delphi, pra quem não conhece é "aquele calendariozinho" utilizado para que o usuário selecione a data como se estivesse acertando a data no calendário do Windows, pois ele já nos fornece os dados no formato DateTime nativo do Delphi e nos poupa linhas de código adicionais para ter informação convertida nesse formato, por[em quem quiser fazer isso a partir de um Edit por exemplo, que fique à vontade.

Bom, segue o código que eu usei e funcionou direitinho:


procedure TForm_Planilha.SpeedButton5Click(Sender: TObject);

var
D1,D2 : TDateTime;

begin
      D1 := DateTimePicker_Inicial.DateTime;
      D2 := DateTimePicker_Final.DateTime;

      DM.Query_Geral.Close;
      DM.Query_Geral.CommandText := 'Select * from GERAL Where DATA_FATURA >= :D1 and DATA_FATURA <= :D2';
      DM.Query_Geral.ParamByName('D1').AsSQLTimeStamp := DateTimeToSQLTimeStamp (D1);
      DM.Query_Geral.ParamByName('D2').AsSQLTimeStamp := DateTimeToSQLTimeStamp (D2);
      DM.Query_Geral.Open;
end;

sábado, 18 de junho de 2011

Como colocar seus "Forms" e "Projetos Modelos" no Repository

Fonte: www.activedelphi.com.br

Acredito que muitos já tentaram colocar seus forms mais usuais ou projetos modelos que são utilizados em várias aplicações no repository do Delphi, mas não tiveram muito sucesso.
Por isso resolvi escrever este artigo demonstrando uma maneira fácil de fazer isso.

O Repository ou "Repositor de objetos" é um conjunto de forms e projetos que podemos usar para criar um programa ou inserir determinados formulários à aplicação, por exemplo o "About".
    Nos rendemos a facilidade de ir no menu "File -> New -> Other..." e escolher os modelos existentes ali para adicionar ao nosso programa, por isso adicionar os nossos próprios modelos de forms e projects ao repository pode nos render facilidade e economia de tempo ao programar.
    Então mãos a obra, digo, ao teclado.
    Os arquivos do Repository, em uma instalação padrão, ficam em: "C:\Arquivos de programas\Borland\DelphiX\Objrepos" onde "X" refere-se a versão do Delphi.
    Aí encontramos diversos diretórios organizando os diferentes tipos de modelos.
    Portanto seus modelos também deverão ser colocados ai, de preferência dentro de um diretório criado por você.     Ex.: "C:\Arquivos de programas\Borland\DelphiX\Objrepos\Adair"
    Importante: Para um form é necessário ter os seguintes arquivos dentro deste diretório:
    "Sobre.dfm" -> Formulário
    "Sobre.pas" -> Código fonte do formulário Sobre
    "Sobre.ico" -> Ícone representativo do formulário Sobre(Irá parecer na lista do Repository)
    Para um project modelo deve-se criar um diretório próprio para o projeto.
    Ex.: "C:\Arquivos de programas\Borland\DelphiX\Objrepos\Adair\Projeto"
    Todos os arquivos do projeto (*.pas, *.dfm, *.res, e os demais) devem estar dentro deste diretório.
    Depois disso devemos alterar as configurações do Delphi para que os nossos modelos apareçam no repository.
    Para isso devemos localizar o arquivo "C:\Arquivos de programas\Borland\DelphiX\Bin\delphi32.dro" que contém as configurações referentes ao repository.
    Devemos editar este arquivo com o bloco de notas do Windows.
    Importante: Este arquivo só pode ser editado por um editor de textos simples, pois não pode conter outras informações a não ser texto, e muito cuidado ao alterar as informações contidas ali, se forem modificadas sem o devido cuidado, o repositoy pode não funcionar direito. Para prevenir, faça uma cópia do arquivo antes de altera-lo.
    Em primeiro lugar devemos localizar a seguinte expressão "[Repository Pages]" (que está bem no final do arquivo) e adicionar "Adair=" (que se refere ao diretório que criamos).
    Para incluir um Form devemos adicionar as seguintes linhas ao arquivo (de preferência já no início do arquivo para faciliar futuras alterações):
    [C:\Arquivos de programas\Borland\Delphi7\Objrepos\Adair\Sobre]
    Type=FormTemplate
    Name=Meu Sobre
    Page=Adair
    Icon=C:\Arquivos de programas\Borland\Delphi7\Objrepos\Adair\Sobre.ICO
    Description=Sobre do meu programa.
    Author=Adair
    DefaultMainForm=0
    DefaultNewForm=0
    Ancestor=
    Designer=dfm
    ATENÇÃO: As opções abaixo não podem ser modificadas:
    Type=FormTemplate
    DefaultMainForm=0
    DefaultNewForm=0
    Ancestor=
    Designer=dfm
  
    Para incluir um Project devemos adicionar as seguintes linhas ao arquivo:
    [C:\Arquivos de programas\Borland\Delphi7\Objrepos\Adair\Projeto\Modelo]
    Type=ProjectTemplate
    Name=Projeto Modelo
    Page=Adair
    Icon=C:\Arquivos de programas\Borland\Delphi7\Objrepos\Adair\Projeto\Modelo.ico
    Description=Meu Projeto Modelo.
    Author=Adair
    DefaultProject=0
    Designer=dfm
  
    Onde "Modelo" é o Delphi Project.
    ATENÇÃO: As opções abaixo não podem ser modificadas:
    Type=ProjectTemplate
    DefaultProject=0
    Designer=dfm
    Depois de adicionado todas as entradas, deve-se salvar e fechar o arquivo.

quinta-feira, 16 de junho de 2011

Acessando o Firebird via ASP

Fonte: www.activedelphi.com.br

Este artigo demonstra como desenvolver uma aplicação web utilizando a linguagem asp, acessando uma base de dados Firebird. Um caso típico para a aplicação disto é a necessidade de disponibilizar na web algum tipo de informação ou funcionalidade de um sistema local/desktop. Muitos fazem isso via php ou com o próprio delphi. Aqui vai uma outra alternativa
O Firebird é usado na maioria das vezes para ser acessado através de um programa executável (exe). Entretanto ele também pode ser utilizado em aplicações para Web, onde atualmente o banco de dados mais utilizado para é o poderoso MySQL. Entretanto o Firebird não deixa nada a desejar quando usado para esta finalidade também.
No nosso exemplo mostrarei como utilizar o ASP para acessar um banco de dados Firebird através de VisualBasicScript, JavaScript e PerlScript. Apesar de não ser minha linguagem favorita, o ASP servirá para ilustrar o exemplo. Note ainda que o ASP utiliza a tecnologia ADO para acesso ao banco de dados. Isto implica em muitas “camadas” para que o acesso ocorra. Naturalmente isso pode deixar o acesso um pouco lento, mas não é o objeto de estudo deste artigo. Também pressupõe-se que o leitor conheça um pouco da tecnologia ASP.
Nos três casos utilizaresmos os códigos como scripts dentro da página ASP. O Perl entretanto pode ainda ser utilizado como script a parte nos famosos “cgi-bin”. A estrutura básica da conexão será a seguinte:
ASP(asp.dll) -> VBS(vbscript.dll) | JS(jscript.dll) | Perl(PerlSE.dll) -> Oledb(oledb32.dll) -> ODBC(odbc32.dll) -> ODBCfb(odbcfb.dll) -> fbclient(fbclient.dll)
Precisaremos instalar o Microsoft Internet Information Services (IIS - servidor web), o Firebird, o Firebird ODBC Driver e o ActiveState Perl.
Para instalar o IIS:
1.Vá até o Painel de Controle,
2.Adicionar ou Remover Programas,
3.Adicionar ou Remover Componentes do Windows,
4.Marque a opção Internet Information Services (IIS),
5.Coloque o CD do Windows no Drive e click em avançar.
Para instalar o Firebird, faça download do programa na página official do Firebird e proceda a instalação padrão (superserver).
Para instalar o Firebird ODBC Driver, faça download do programa no site da IBPhoenix e proceda a instalação com as opções padrão.
Para instalar o ActiveState Perl, faça download do programa no site da ActiveState e proceda a instalação com as opções padrão.
Antes de criar a página, precisamos configurar a conexão:
1.Vá até o Painel de controle,
2.Ferramentas administrativas,
3.Fontes de dados (ODBC),
4.Fontes de Dados do Sistema e click em adicionar.
5.Selecione o driver “Firebird/InterBase(r) driver” e click em concluir.
6.Preencha os campos com os dados abaixo:

DSN
: examples
Database
: C:\Arquivos de programas\Firebird\Firebird_2_1\examples\empbuild\EMPLOYEE.FDB
Client
: C:\Arquivos de programas\Firebird\Firebird_2_1\bin\fbclient.dll
Database Account
: sysdba
Password
: masterkey
Transaction
: nowait
Se utilizar uma versão diferente de 2.1, o nome do banco de dados e DLL cliente podem alterar. Caso tenha mudado a senha do sysdba, também lembre-se de colocar a correta. Você pode clicar no botão “Testar Conexão” para se certificar de que tudo deu certo.
Digite o conteúdo abaixo e salve em C:\Inetpub\wwwroot\firebird.vbs.asp:
<% @LANGUAGE = VBScript %>
<%
Dim oConn, oRs, i
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open "Driver=Firebird/InterBase(r) driver;Data Source=examples"
Set oRs = oConn.Execute("SELECT * FROM PHONE_LIST")
Response.Write("")
Do while (Not oRs.eof)
 Response.Write("")
 For i = 0 to (oRs.fields.count - 1)
  Response.Write("")
 Next
 Response.Write("")
 oRs.MoveNext 
Loop
Response.Write("
" & oRs(i) & "
") oRs.close oConn.close %>
Digite o conteúdo abaixo e salve em C:\Inetpub\wwwroot\firebird.js.asp:
<% @LANGUAGE = JavaScript %>
<%
var oConn, oRs, i
oConn = Server.CreateObject("ADODB.Connection");
oConn.Open("Driver=Firebird/InterBase(r) driver;Data Source=examples");
oRs = oConn.Execute("SELECT * FROM PHONE_LIST");
Response.Write("");
while (!oRs.eof) {
 Response.Write("");
 for (i = 0; i <= oRs.fields.count - 1; i++) {
  Response.Write("");
 }
 Response.Write("");
 oRs.MoveNext;
} 
Response.Write("
" + oRs(i) + "
"); oRs.close(); oConn.close(); %>
Digite o conteúdo abaixo e salve em C:\Inetpub\wwwroot\firebird.pl.asp:
<% @LANGUAGE = PerlScript %>
<%
use OLE;
$objConn = CreateObject OLE "ADODB.Connection";
$objConn->Open("Driver=Firebird/InterBase(r) driver;Data Source=examples");
$objRS = $objConn->Execute("SELECT * FROM PHONE_LIST;");
$Response->Write("\n");
while (!$objRS->EOF) {
 $Response->Write("\n");
 for ($i = 0; $i <= $objRS->Fields->Count - 1; $i++) {
  $Response->Write("\n");
 }
 $Response->Write("\n");
 $objRS->MoveNext;
}
$objConn->Close;
$objRS->Close;
$Response->Write("
" . $objRS->Fields($i)->value . "
"); %>
Os códigos acima instanciam o ADO, criam uma conexão com o ODBC, executam o comando e preenchem o resultado na tela. São utilizados um objeto Connection e um RecordSet para isso.
Abra seu navegador web e nele abra três guias. Na 1ª digite: http://localhost/firebird.vbs.asp; na 2ª http://localhost/firebird.js.asp e na 3ª http://localhost/firebird.pl.asp. Você verá o resultado sendo preenchido nas respectivas páginas.
Caso queira confirmar, utilize o FlameRobin para acessar a View e comparar o resultado. Apesar de ser um exemplo simples, ele ilustra o problema.

sábado, 11 de junho de 2011

Comandos básicos SQL (inserir / alterar / deletar)


Crie uma tabela com o nome de teste.db, e coloque os seguintes campos:
COD = auto_increment
NOME = alpha = 255 caracteres
Neste artigo irei mostrar de forma fácil e rápida, os comandos básicos para: (inserir,alterar,deletar).
Primeiramente vamos aos comandos:

Para inserir dados, com comandos SQL
('insert into tabela (nome_capo) values ('+''''+edit.Text+''''+');

Para selecionar dados, com comandos SQL
('select * from tablea where = campo "'+edit.Text+'"');

Para deletar dados, com comandos SQL
('delete from tabela where campo = '+''''+edit.Text+''''+'');

Para atualizar dados, com comandos SQL
('update tabela set campo = '+''''+edit.Text+''''+' where campo = '+''''+edit1.Text+''''+'');

Agora vamos passo a passo:
Primeiramenta crie um novo aplicativo em: File >New >Application

Após ter criado, coloque no form os componentes: 3 componentes "TButton", 1 componente "TEdit", 1 "TDBGrid", 1 "TDataSource", 1 "TSQLQuery".

No componente, TDataSource, na propriedade DataSet, coloque o valor "query1".
Pronto, as configurações dos componentes já foram feitas, agora vamos colocar os comandos no projeto.

Você colocou 3 componentes "TButton".
Faça as seguintes configurações nas propriedades do 3 "TButton".

Button1: Caption = Inserir
Name = btn_inserir
Button2: Caption = Alterar
Name = btn_alterar
Button3: Caption = Deletar
Name = btn_deletar

Agora de um duplo clique sobre o Botão "Inserir","btn_inserir".
Irá aparecer o editor do delphi, onde serão colocados os comandos.
Neste botão "Inserir", você coloca o seguinte comando:

query1.Active := False;
query1.SQL.Clear;
query1.SQL.Add('insert into teste (nome) values ('+''''+edit1.Text+''''+') ');
query1.ExecSQL;

Bom, estas linhas de comando acima irá inserir o dado em uma tabela.

Agora no botão "Alterar", você coloca as seguinte linhas de comandos:

query1.Active := False;
query1.SQL.Clear;
query1.SQL.Add('update teste set nome = '+''''+edit1.Text+''''+' where = COD');
query1.ExecSQL;

As linhas de comandos acima irão fazer com que altere um certo dado, este é o comando básico.

Agora no botão "Deletar", você coloca as seguintes linhas de comandos:

if MessageDlg('AVISO: Confirma Exclusão?', mtInformation, [mbYES, mbNO], 0) = mrYES then
begin
query1.Active := False;
query1.SQL.Clear;
query1.SQL.Add('delete from teste where COD = '+''''+edit1.Text+''''+'');
query1.ExecSQL;
end

Bom ai está, como inserir, aletrar e deletar dados de uma tabela, com comandos básicos. 

Objetos Distribuídos


Um dos maiores paradigmas da indústria de informática, nos dias de hoje, é o novo conceito de processamento cliente/servidor, onde existe...
uma mudança das aplicações codificadas em segmentos, partes ou componentes. Estas aplicações são separadas logicamente em três camadas: usuário, regras de negócio e dados.

A aplicação está dividida ao longo de linhas locais/remotas de dados, o que torna a infra-estrutura de redes das empresas um dos grandes fatores críticos de sucesso no desenvolvimento e implantação de um sistema. O cliente, tipicamente um PC, fornece a interface gráfica enquanto os servidores fornecem um conjunto de serviços.


Esses componentes, conhecidos como objetos, são distribuídos nas redes gerando um novo paradigma dentro de um já existente: a revolução do cliente/servidor. O resultado final é a quebra das aplicações em componentes, onde a reutilização e o baixo custo de implementação são os grandes benefícios obtidos.


Um objeto é essencialmente um componente com inteligência que opera entre sistemas operacionais heterogêneos, desenvolvido em várias linguagens de programação. Na área de desenvolvimento de sistemas, o conceito de objetos está alterando totalmente a arquitetura, desenvolvimento, empacotamento, distribuição e manutenção de software.


Então, qual a diferença entre um objeto clássico e um objeto distribuído? Um objeto clássico possui propriedades e métodos e é gerado através de uma linguagem de programação como Delphi, C++, VB, entre outras.


Esses objetos fornecem reusabilidade de código através de herança, encapsulamento e polimorfismo, propriedades fundamentais da teoria orientada a objetos. Contudo, esses objetos só vivem dentro de um programa; apenas o compilador que os criou conhece a sua existência.


O mundo externo os desconhece e não tem formas de acessá-los. Um objeto distribuído também é uma classe que pode publicar (tornar disponível) tanto suas propriedades quanto seus métodos, mas a linguagem e o compilador usados para criar objetos distribuídos são totalmente transparentes para a implementação desses. Esses objetos têm uma interface definida onde os compiladores geram um código a mais para serem acessados por outros objetos de forma totalmente transparente, isto é, o invocador desconhece o local do objeto invocado, o sistema operacional que esse executa, podendo estar fisicamente na mesma máquina (processo) ou em alguma máquina remota.


Um dos fatores críticos para a implementação de um sistema com componentes distribuídos é a transparência da sua localização física, podendo operar num processador local, num processo diferente ou num processador remoto. Porém, um componente não pode operar no vácuo, e por isso precisa de uma base denominada "barramento" de objetos distribuídos (ORB - Object Request Broker). Esse barramento oferece serviços que permitem a interligação entre os diversos componentes nas diferentes plataformas. É necessário utilizar esse serviço porque a interação entre componentes é requisito básico para a construção de uma aplicação de negócio. Os componentes estão sempre adicionando novos serviços, que são herdados durante sua compilação ou execução e alcançam altos níveis de colaboração entre si.


Nos dias de hoje, existem na indústria dois grandes padrões para desenvolvimento de objetos distribuídos que separam a interface de um objeto de sua implementação: DCOM (Distributed Component Object Model) e CORBA (Common Object Request Broker Architecture).


Os elementos principais da especificação CORBA são a linguagem de definição das interfaces dos objetos que serão criados e colocados à disposição na rede (IDL - Interface Definition Language) e um repositório (IR - Interface Repository) que representa as interfaces (ou classes) de todos os objetos disponíveis no sistema distribuído.


Como criarmos objetos para CORBA e/ou DCOM? Ambos têm o objetivo de fornecer uma transparência de localização de objetos e sua implementação, o que exige definição de interface entre os componentes. Essa interface deve ser publicada (tornada pública) e serve como mecanismo de ligação e acionamento entre esses componentes. A interface dos componentes é especificada em IDL, uma linguagem puramente declarativa que não define nada sobre a implementação desses componentes.

DCOM, além de separar a interface de um objeto de sua implementação, é uma extensão de COM (Component Object Model), parte da família Windows de sistemas operacionais, baseada na infra-estrutura de OLE e Active X. COM/DCOM é um framework baseado na construção de objetos para desenvolvimento que usa uma variedade de linguagens e ferramentas totalmente independentes de linguagem de programação, sendo parte implícita dos sistemas operacionais da Microsoft Windws NT e Windows 95.

Os fatores para uma comparação entre DCOM e CORBA são suporte para plataforma e linguagem, custo e integração.


Com relação à integração é importante a construção de "pontes" entre CORBA e DCOM, que permitirá distribuir objetos entre servidores e estações na Internet/intranet. O OMG definiu os mapeamentos entre COM e CORBA de tal forma que objetos COM podem invocar objetos CORBA e objetos CORBA invocam objetos COM.

segunda-feira, 30 de maio de 2011

Obter caminho de qualquer aplicação Delphi


Saudações, caros delphianos! Quando estamos desenvolvendo uma aplicação executável (.EXE) e necessitamos obter o caminho completo da mesma, costumamos utilizar o método ExtractFilePath, da biblioteca SysUtils, passando por parâmetro o nome do executável de nossa aplicação, como segue

  strPath := ExtractFilePath(Application.ExeName);

Pois bem, mas e se precisarmos fazer o mesmo em uma aplicação ISAPI (.DLL), como IntraWeb ou WebBroker?

Na biblioteca SwSystem, podemos encontrar a variável gsAppPath que contém o caminho da DLL da aplicação. O melhor disso tudo é que podemos utilizar esta variável em qualquer tipo de aplicação, inclusive executáveis!

IBX & Firebird - Out of Memory em relatório com muitos registros


Olá amigos! Certo dia me deparei com um belo "Out of Memory" em uma máquina de 4GB de RAM e uma base de 500MB. O erro aparecia quando o cliente tentava tirar um relatório de vendas de 01/01/2009 à 31/12/2009. Cheguei a pensar que pudesser ser configuração do FB, mas fiz os testes por fora do sistema e não tive problemas com o select. Sendo assim, o problema estava no programa em trazer muitos registros pra ele.

Pensei: se é um relatório, uma vez impresso o registro, pra que armazena-lo em memória? Então fiz o teste com a propriedade "Unidirectional = True" no IBQuery e adivinha?! "Adios" out ouf memory!

Essa semana um amigo me procurou para dizer que teve o mesmo problema e encontrou a dica no site da lista de discussão da firebase, onde a postei originalmente. Então decidi publica-la aqui também para que possa ajudar mais pessoas com este problema.

terça-feira, 24 de maio de 2011

CRM - Compreendendo o assunto


Ouve-se muito falar em CRM. Mas, o que é CRM? Uma técnologia? Um conceito? Uma ferramenta? Veja neste material e esclareça suas dúvidas!
Prezados amigos desenvolvedores, já faz um tempo desde o primeiro artigo, fiquei muito atarefado com a implantação do projeto 2.0 da NF-e.
Um amigo me perguntou um dia desses: “Bruno, ouço falar tanto de CRM, como faço para integrar essa tecnologia nos meus sistemas?”

Primeiro vamos entender o cenário:
O mundo passou por profundas e importantes transformações, sobretudo nos últimos anos, impulsionadas pelo crescimento da Internet. Ao ganhar mais um poderoso canal de comercialização e de comunicação, o setor corporativo precisou rever conceitos e se reestruturar.
Na era digital, tudo é muito rápido. O concorrente está a um simples clique no mouse. Não basta mais oferecer somente um produto ou um serviço de qualidade.
O Customer Relationship Management (CRM), que em Português significa Gerenciamento da Relação com o Cliente, é um sistema integrado de gestão da interação com o cliente, constituído por um conjunto de procedimentos e de processos organizados e integrados a BPM (Business Process Management, ou modelo de gestão de negócios). “Lembrando que quando falo em sistema não necessariamente quero me referir a softwares”.
Os processos e os sistemas de gestão de relacionamento com o cliente permitem que se tenha controle e conhecimento de todas as suas informações de maneira integrada, principalmente com o acompanhamento e registro de todas as interações com a empresa, que ficam disponíveis a todos os setores que necessitem dessa informação. O produto final irá guiar as tomadas de decisões.
A gestão do relacionamento com o cliente permite o registro em tempo real de todos os contatos realizados por ele com a companhia, de forma centralizada. Esses registros independem do canal de comunicação usado (voz, fax, e-mail, chat, SMS, MMS, entre outros) e servem para reunir informações úteis e catalogáveis. Qualquer informação relevante para as tomadas de decisões pode ser registrada e analisada periodicamente, para que sejam produzidos relatórios gerenciais dos mais diversos interesses.

CRM não é tecnologia
Como a implementação de sistemas de CRM requer o emprego de tecnologias, o mercado, no primeiro momento, passou a interpretar o CRM como se fosse uma. Desde que o conceito ganhou as atenções da mídia, o segmento tecnológico de soluções especializadas movimentou-se com força e rapidamente. Atualmente, existe uma infinidade de pacotes vendidos como CRM, mas que, na verdade, contemplam apenas uma parte dele. CRM é muito mais do que um conjunto de software. É um processo contínuo que compreende, além do uso da tecnologia, uma estratégia de negócios e uma mudança de cultura dentro da organização. Pela complexidade, não se implementa CRM de uma única vez e nem de forma padronizada. Assim como os clientes são diferentes, também cada empresa difere das demais.
Um exemplo do uso do CRM bem aplicado aconteceu comigo no dia 21 do mês passado (data do meu aniversário). Recebi um e-mail da Americanas.com contendo um cartão virtual me parabenizando e me dando R$ 15,00 de desconto no total de qualquer compra naquele dia. Resultado: acabei comprando... rsrs
Em resumo, nós podemos desenvolver e integrar nossas soluções, baseadas no conceito CRM, porém precisamos do envolvimento das empresas no que diz respeito a alimentação e gerenciamento das informações.