Sabe todos aquelas linhas de código para incluir um item no menu “by code”…

  • inicializa o item de menu;
  • adiciona os parametros;
  • cria o método para o evento OnClick…
  • atribui o evento;
  • adiciona o item à lista;

Exemplo VCL para incluir um item de menu usando código:

[code]
procedure TForm40.ClickMenuItem(sender:TObject);
begin
showMessage(‘menu sem anonimous’);
end;
procedure TForm40.FormCreate(Sender: TObject);
var it:TMenuItem;
begin
it := TMenuItem.Create(MainMenu1);
it.caption := ‘Teste de um menu sem anonimous’;
it.OnClick := ClickMenuItem;
MainMenu1.Items.Add(it);
end;
[/code]

Métodos “anonimous” é uma poderosa ferramenta presente no Delphi na era XE, que encurta caminhos complexos. Ao reduzir código ao mesmo tempo aumentamos qualidade (com menor ocorrência de bugs) bem como menor tempo de implementação. Se considerar que o maior tempo se gasta em testes e correções de defeitos, então o ganho é exponencial.

Exemplo usando “Anonimous Method”:

[code]
uses VCL.Menus.Helpers;
procedure TForm40.FormCreate(Sender: TObject);
begin
MainMenu1.Items.CreateAnonimous(‘Teste menu com anonimous’,
procedure begin
showmessage(‘ok…’);
end);
end;
[/code]

Fontes: https://github.com/amarildolacerda/helpers

Por padrão o FireDAC mantem ativo (true) a propriedade SilentMode. Nesta condição o FireDAC mantem o ciclo de mensagem com o windows para apresentar a ampulheta de processando. Evidentemente, informar o usuário sobre o andamento do processamento pode ser um ponto importante para não ficar com a impressão que tudo travou, no entanto, isto tem um custo no tempo de resposta da operação.

A questão pode se mostrar bastante crítica quando aninha chamada ao banco durante a navegação do usuário em um GRID com os dados… Imagina fazendo um select a cada vez que muda um linha no GRID. Desligar o SilentMode pode ter impacto positivo considerável no resultado… não ficará com aquela ampulheta gastando tempo durante a navegação… tenta ainda teclar varias vez a tecla para baixo em um GRID onde a cada pressionar de tecla chama um SELECT no banco de dados… notará o quanto é significativo o recurso.

No FireDAC há varias formas de acessar esta propriedade, desde acesso mais global como o que ocorre com o componente  TFDManager até acesso mais localizado como em um TFDQuery…

Toda rotina que não precisa informar o usuário, deveria ser desligado para melhorar a resposta e liberar o firedac de ficar despachando mensagem para o Windows.

[code]query1.ResourceOptions.SilentMode := True;[/code]

RDB$DB_KEY é uma coluna existente em todas as tabelas do banco de dados, mas que encontra-se escondida visível somente se for indicada literalmente no SELECT.

A coluna recebe um número sequencial de linhas na tabela e pode ser utilizada para fazer UPDATE para as linhas. Como um coluna nativa do FIREBIRD, que representa o endereço da linha, não requer índice individualizado para ela, já otimizada internamente ao banco de dados.

O RDB$DB_KEY é alterado toda vez que faz  BACKUP/RESTORE, então não é possível utiliza-lo para fazer relacionamento com outras tabelas, já que não é fixo ao longo do tempo.

O uso do RDB$DB_KEY é mais rápido seu uso se comparado a chave primária, já que internamente o índice aponta o endereço do registro para o RDB$DB_KEY.

É particularmente útil quando existem linhas repetidas em uma tabela que não possui chave primária por indicar a única diferença entre as linhas (repetidas).

 

Pesquisar: RDB$DB_KEY

Fonte: Firebird FAQ

How to delete duplicate records (when table doesn’t have a primary key column)?

 

You can use the ‘secret’ RDB$DB_KEY feature of Firebird. RDB$DB_KEY is a ‘hidden’ record that identifies rows in each SQL statement. For example, if you have a table TABLE1 without primary key and have columns COL1 and COL2 which are the same, you can delete the extra rows with the following statement:

DELETE FROM TABLE1 t1
WHERE EXISTS (
SELECT 1 FROM TABLE1 t2
WHERE t1.COL1 = t2.COL1 and t1.COL2 = t2.COL2
AND t1.RDB$DB_KEY < t2.RDB$DB_KEY
);

You can control whether the record is considered duplicate by including the relevant table columns in the WHERE clause (in most cases, you will want to include all columns).

The above code assumes that columns are NOT NULL or you want to treat rows with NULLs as different. If you want to remove duplicate rows that include NULLs in same columns, you can use the following code:

DELETE FROM TABLE1 t1
WHERE EXISTS (
SELECT 1 FROM TABLE1 t2
WHERE t1.COL1 IS NOT DISTINCT FROM t2.COL1
AND t1.COL2 IS NOT DISTINCT FROM t2.COL2
AND t1.RDB$DB_KEY < t2.RDB$DB_KEY
);

The IS NOT DISTINCT FROM operator is available since Firebird 2.0.

Considerando isoladamente a extração de dados OVER é uma o mais interessante recurso incluído ao Firebird.

Há uma possibilidade grande de combinações onde OVER se aplica – não vamos conseguir cobrir tudo somente neste POST, então vamos nos concentrar a um texto já tratando neste blog em relação a versão 2.5, que é apresentação de RANK, ou seja, mostrar a posição que se encontra o dado dentro da lista..

Ex: Qual a posição do vendedor XXX no RANK de vendas;

A implementação segue um padrão de estrutura tratado como “analytical functions”, ou seja, funções analíticas ou de análise de dados.

A ideia é usar um SELECT para separar uma janela de dados em paralelo do mesmo dado e montar um relacionamento dos dados do SELECT com os dados da JANELA para efetuar algum cálculo… no caso, calcular o RANK.
Tomando o exemplo da documentação emprestado

[code language=”sql”]select id, salary,
dense_rank() over (order by salary),
rank() over (order by salary),
row_number() over (order by salary),
sum(1) over (order by salary)
from employee
order by salary;

The result set:
id salary dense_rank rank row_number sum
— —— ———- —- ———- —
3 8.00 1 1 1 1
4 9.00 2 2 2 2
1 10.00 3 3 3 4
5 10.00 3 3 4 4
2 12.00 4 5 5 5

[/code]

Fazendo uma leitura do exemplo, em primeiro passo o engine monta o SELECT – quando encontra o comando OVER, ele separa uma janela em paralelo com os dados do mesmo SELECT (agora tem 1 cópia do mesmo dado do SELECT)… o que vem depois do OVER (….) é a forma em que o dado será organizado – no exemplo ORDER BY Salary; Sobre a janela de dados aplica a função indicada – o RANK();

Pegando carona no exemplo:

Há uma diferença entre RANK() e DENSE_RANK(),  em relação a forma de sequencia montada quando existe repetição do dado… enquanto RANK() continua a contagem quando encontra repetições, no DENSE_RANK() o número é mantido e segue a mesma sequencia do número anterior.

ROW_NUMBER() é uma contagem simples de linhas sem diferenciar dados repetidos como faz o RANK();

 

 

 

Quando uma transação no banco de dados exigir uma avaliação de registros já existentes no banco para decidir se o que precisa fazer é um UPDATE ou um INSERT em geral exige no mínimo duas chamadas para o banco de dados… uma para fazer o SELECT (toma decisão sobre o comando a aplicar) e então envia outra chamada com um UPDATE ou com um INSERT;

Para otimizar estes passos é possível utilizar “MERGE” ou “UPDATE OR INSERT”. Quando o desejo é passar os dados de uma tabela para outro o MERGE pode ser o mais adequado para a operação, mas se deseja atualizar os dados com entradas de parâmetros, sem vincular a uma tabela, o mais adequado será usar o comando “UPDATE OR INSERT”.

 

  1. Usando MERGE para fazer INSERT OR UPDATE com um único comando com base em uma tabela

O comando MERGE permite submeter uma única chamada para o banco de dados, quando as condições “where” coinciderem executa um UPDATE se não coincidirem executa um INSERT;

Exemplo da documentação:

[code language=”sql”]
MERGE INTO customers c 
USING    (SELECT * FROM customers_delta WHERE id &gt; 10) cd    
ON (c.id = cd.id) 
WHEN MATCHED THEN   
UPDATE SET name = cd.name 
WHEN NOT MATCHED THEN   
INSERT (id, name)    VALUES (cd.id, cd.name)
[/code]
No Firebird3, é possível utilizar DELETE também – ou seja, agora é possível utilizar UPDATE,INSERT ou DELETE;

No exemplo, para que funcione, há uma premissa básica que faz parte do MERGE… é obrigatório que “customers_delta” tenha pelo menos 1 linha… Se o resultado de “customers_delta” for nenhuma linha, NADA será feito (nem UPDATE nem INSERT)…
De outro lado, existindo pelo menos 1 linha em customers_delta, ocorrerá a comparação ON (c.id = cd.id)…  em encontrando o mesmo código “WHEN MATCHED” será executado o UPDATE… caso não encontre o código será efetuado o INSERT (WHEN NOT MATCHED)…

 

Avançando um pouco mais… digamos que queremos avaliar uma única tabela… assim:   procurar se no cadastro de produto existe um determinado código…. caso exista UPDATE, caso não exista INSERT…

Para que funcione, lembra da premissa básica – o SELECT de USING, é obrigatório retornar pelo menos 1 linha. Quando o código procurado existir, o UPDATE será executado com sucesso, mas…..   se não existir o código, o USING SELECT  quebra a premissa básica (não existe a linha) – com isto o INSERT não funciona.

Vamos fazer uma adaptação para que o MERGE funcione usando RDB$DATABASE (o que o deixa igual ao UPDATE OR INSERT)

Exemplo:
[code language=”sql”]
MERGE INTO fb_prod c
USING
(SELECT ‘999999’ codigo, ‘nome do produto’ nome FROM rdb$database) cd
ON (c.codigo = cd.codigo)
WHEN MATCHED THEN
UPDATE SET nome = cd.nome
WHEN NOT MATCHED THEN
INSERT (codigo, nome,id) VALUES (cd.codigo, cd.nome,1)
[/code]

2. Usando UPDATE OR INSERT :

Ao usar UPDATE OR INSERT não é necessário vincular o comando a uma tabela associada o que torna o comando mais flexível em relação ao MERGE… veja um exemplo de como fazer:
[code language=”sql”]
UPDATE OR INSERT INTO fb_prod (codigo, nome, id)
values (‘999998’, ‘nome usando update or insert’, 2)
MATCHING (codigo)

[/code]

Em resumo, cada situação há várias formas de fazer a mesma coisa… escolha a que for mais eficiente

No Firebird 3 passou a ser possível criar exception com parâmetros que adicionam texto à mensagem retornada para o usuário.

create exception e_invalid_val ‘Valor invalido @1  para a coluna @2’;


if (val < 1000) then
thing = val;
else

exception e_invalid_val using (val, ‘thing’);
end

 

Este recurso na prática não adiciona nenhum ganho, já que no 2.5 era possível adicionar um texto à exceção..

Exception erro ‘Valor invalido ‘||val||’ para a coluna xxxx’;

 

 

Quando um arquivo é gravado no disco, mesmo tendo 1 único byte, o disco aloca um espaço mínimo de 1 cluster ( o mais comum é 1 cluster = 4096 bytes);

Existem HDs que gravam número de bytes diferente para 1 cluster, dependendo do modelo e fabricante; Para saber qual o tamanho de 1 cluster no disco basta escrever uma arquivo TXT com 1 byte de conteúdo, ir na propriedade do arquivo (via explorer) e checar qual o tamanho em disco……

O que fazer com esta informação ?

O banco de dados firebird usa gravar os dados em páginas; Cada página tem uma quantidade de bytes que é gravado juntamento com o FDB conhecido como “Page size”. Se uma pagina for de 8192, por exemplo, e 1 cluster no HD for de 4096, significa que para cada página que o banco for gravar ele vai precisar de 2 clusters físicos no disco.  Mesmo quando 1 página tiver um número muito pequeno de bytes a serem gravados, mesmo assim, o HD vai utilizar 2 cluster.

Não é difícil imaginar que o FDB vai ficar bem grande, com muitos buracos vazios. Para adequar este comportamento, o tamanho do “Page Size” deve ser o mesmo tamanho de 1 cluster no HD, destar forma o comportamento do banco de dados será o mesmo que aquele que o HD que esta instalado.

Para alterar o “Page size” é necessário alterar o parâmetro durante o RESTORE do banco de dados incluindo a opção: F:4096 ( quando o HD usar cluster de 4096 );

Exemplo:

gbak -rep -F 4096 meubackup.fbk meubanco.fdb -user sysdba -pass masterkey

 

 

Depois de fazer uma leitura rápida da documentação do novo RC – partindo para instalação.

Instalei a versão WIN64 em uma máquina que já tinha tanto 3.0 RC1 quanto 2.5 rodando na 3051 (3) e o outro na 3050 (2.5).

No primeiro passo o instalador reclamou que já tinha uma instalação. Parei o serviço, apaguei a pasta do 3.0 para fazer uma instalação limpa. Ele reclama que já existe a pasta do 2.5, mas não há risco em continuar pois instala em uma sub-pasta diferente do 2.5

Durante o processo ele deixa escolher como vai rodar – se serviço ou app, bem como o tipo de instalação – escolhi SuperClassic (novo modo de funcionamento); No passo seguinte pergunta qual será o usuário administrador e senha – importante neste ponto, já que ao contrário do 2.5 ele não vem com o admin configurado e precisa fazer isto na instalação – neste momento informei o admin que todos já conhecem, em produção seria interessante definir um outro admin para fugir do padão conhecido por todos.

Concluído a instalação com tranquilidade, abri o “firebird.conf” para configurar a porta, já que vou continuar usando o 2.5 junto com o 3.0 – editei e alterei:  RemoteServicePort = 3051

No passo seguinte subi o serviço e vamos abrir um banco que já tinha rodando com 3.0 – primeiro instante não consegui logar, depois de alguns testes notei que agora o nome do usuário é sensível a maiúsculo e minúsculo, depois disto… foi… (revisão: o comportamento ocorreu usando o IBExpert (2016.12) – só aceitou maiúsculo – configurando direto no aplicativo delphi, funcionou tanto minúsculo como maúsculo – mensagem enviada pelo Cantú pelo facebook/firebird)

Caso escolha rodar como aplicativo (não serviço) 
é possível iniciar usando o comando:
<strong>       firebird -m -a</strong>

Como passar o 2.5 para 3.0:

Nas compilações anteriores foi preciso fazer backup do banco de produção usando o 2.5 e depois restaurar com o 3.0; Esta ação esta ligado a mudança de estrutura do banco assumindo nova versão no 3.0, creio que não será possível copiar direto;

Antes não era possível fazer backup usando o 3.0 de um banco do 2.5, não refiz o teste para verificar se esta restrição continua. Então naquela ocasião foi obrigatório fazer o backup do banco no 2.5  antes de instalar o 3.0;

Vamos para o IBExpert:

Aqui passei pelo necessidade de reconfigurar a FBClient.dll que no 3.0 não é compatível com a do 2.5, ou seja, precisei indicar para o IBExpert qual a DLL iria utilizar – usei a que vem na pasta WOW64 – não funcionou, ainda não chequei porque… peguei a FBClient.dll que já tinha da RC1 – foi… (revisando: fiz novos teste e a FBClient que esta no disco de instalação do RC2, funcionou)

Na RC1 não era possível usar a FBClient.dll da 3.0 para acessar a 2.5 – o contrário também não era possível… (revisão: novos testes mostraram que a FBClient que vem no disco da RC2 agora é compatível com 2.5 também, ou seja, pode utilizar a mesma DLL tanto para acesso ao 3.0 quanto para o 2.5)

 

Entramos, agora RC2 rodando.

 

O Firebird 3 mudou algumas coisas em relação a forma de funcionamento do servidor;

Agora temos as seguintes possibilidades de instalação:

  1. Server – funciona com um único processo e compartilha “page cache” interno ao processo. (instalação padrão);
  2. SuperClassic – funciona em thread por conexão rodando com um único processo. As threads são iniciadas no processo principal e cada thread tem seu próprio “page cache”;
  3. Classic – MultiProcess, cada conexão é executada em um processo separado. Cada processo seu próprio controle “page cache”;

O modo Classic e Server possuem características paralelo ao que já tínhamos no 2.5x,  a novidade é o SuperClassic que mescla os dois outros processos, ou seja, funcionam em Thread compartilhadas e cada um mantem o seu “page cache” isolado;

Ná prática este novo modelo poderá se mostrar mais eficiente para isolamento e otimização de hardware, vamos aos teste para ver o resultado.