Uma das reclamações das pessoas que começam a utilizar o FireBird é a falta do auto-incremento como é contrados em sistemas como SQL Server e MySQL. Ainda não vamos discutir os prós e contras de se utilizar generators(Sequences), mas criei um código para me auxiliar na tarefa de preparar o banco de dados para rotinas de replicação e que serve para solucionar este problema.
A rotina abaixo busca por tabelas no banco de dados que contenha chaves primárias de apenas um campo, caso encontre, cria o GENERATOR (SEQUENCE), e a TRIGGER correspondente para gerar o auto-incremento destas tabelas.
create or alter procedure prc_list_unique_fields_of_table(tablename varchar(32))
returns(fieldname varchar(32))
as
begin
for Select distinct s.rdb$field_name from rdb$indices i inner join
rdb$index_segments s on s.rdb$index_name = i.rdb$index_name
where upper(i.rdb$relation_name) = upper(:tablename) and rdb$unique_flag = 1
into :fieldname do
begin
suspend;
end
end
create or alter procedure prc_generate_auto_inc
as
declare variable sql varchar(8000);
declare variable table_name varchar(32);
declare variable key_count integer;
declare variable key_name varchar(32);
declare variable GENERATOR_OR_TRIGGER_EXISTS INTEGER;
declare variable i integer;
declare variable SERVER_COUNT INTEGER; --INDICA A QUANTIDADE DE SERVIDORES
--PARA O CADO DE REPLICAÇÃO DO BANCO
declare variable GENERATOR_NAME VARCHAR(32);
begin
i = 0;
SERVER_COUNT = 1;
for Select TRIM(r.rdb$relation_name) from rdb$relations r
where r.rdb$relation_type = 0 and r.rdb$flags = 1 into :table_name do
begin
sql = '';
i = 0;
for Select * from prc_list_unique_fields_of_table(:table_name) into :key_NAME do
begin
-- Utiliza a procedure criada anteriormente
-- foi utilizado o loop, porque se existir apenas uma chave, o valor ja estara
-- atribuido
i = i + 1;
end --for
GENERATOR_NAME = 'GEN_' || :TABLE_NAME || '_ID';
GENERATOR_OR_TRIGGER_EXISTS = NULL;
EXECUTE statement 'SELECT 1 FROM RDB$GENERATORS ' ||
' WHERE RDB$GENERATOR_NAME = ''GEN_' || :TABLE_NAME ||
'_ID'' ' INTO :generator_or_trigger_exists;
if (GENERATOR_OR_TRIGGER_EXISTS IS NULL ) then
if (i = 1) then
begin
execute statement 'create generator GEN_' || :TABLE_NAME || '_ID';
EXECUTE STATEMENT 'CREATE TRIGGER ' || :TABLE_NAME || '_BI FOR ' ||
:TABLE_NAME || ' ACTIVE BEFORE INSERT POSITION 0 AS begin ' ||
' IF(NEW.' || :KEY_NAME || ' IS NULL) THEN new.' || :KEY_NAME ||
' = GEN_ID(GEN_' || :TABLE_NAME || '_ID,' ||
CAST(:SERVER_COUNT AS VARCHAR(5)) || '); END';
end--if
end--FOR
end
Recursos utilizados nestes scripts:
TRIM: retorna o texto informado no parâmetro sem os espaços a esquerda e direita.
EXECUTE STATEMENT: Execute um comando contido na string, muito útil para criação de consultas
dinamicamente.
RDB$RELATIONS: Tabela do sistema que contem todas as tabelas e views do banco de dados.
UPPER: Retorna o parâmetro informado em caixa alta (todas as letras maiúsculas )
CAST: Converte um valor para um determinado tipo de dados. No nosso exemplo foi convertido um valor inteiro para texto ( varchar(5) ).