Artigo "Novidades do Firebird 2.5": Expressões, literais e funções
Na parte de expressões SQL, o Firebird 2.5 acrescenta melhorias e novidades. A função agregada LIST (presente desde a versão 2.1) agora aceita qualquer expressão em seu segundo parâmetro, onde o desenvolvedor pode especificar a string de separação dos elementos retornados. Até a versão 2.1.3 era possível apenas o uso de strings constantes nesse parâmetro. Nota: a versão 2.1.4 também deve ser liberada com esta novidade. A listagem 10 mostra a utilidade deste parâmetro, principalmente no desenvolvimento de relatórios, agrupando várias mensagens referentes a um documento em um mesmo registro e mostrando cada mensagem em uma linha.
Listagem 10. Usando a função LIST com expressões no segundo parâmetro.
SELECT LIST(MENSAGEM, ASCII_CHAR(13) || ASCII_CHAR(10))
FROM MENSAGENS_DOCUMENTO WHERE DOCUMENTO = 10;
Referente a parâmetros de comandos SQL, o Firebird suporta apenas o uso de parâmetros anônimos com o símbolo “?” (ponto de interrogação). Algumas bibliotecas (inclusive de Delphi) aceitam o uso de parâmetros nomeados usando “:” (dois pontos). Quando o desenvolvedor tentava escrever queries usando o padrão [WHERE :CODIGO IS NULL OR CODIGO = :CODIGO] para trazer todos os registros quando o parâmetro não fosse informado, o Firebird retornava um erro. Isto porque este comando é traduzido pelas bibliotecas para [WHERE ? IS NULL OR CODIGO = ?] e o Firebird não aceitava o uso de parâmetro com o predicado IS NULL, pois o tipo do parâmetro era considerado como desconhecido. Na versão 2.5 foi adicionado à API o tipo SQL_NULL. As bibliotecas de acesso precisam entender este novo tipo e apenas passar se o valor do parâmetro é ou não NULL, permitindo assim o uso deste padrão de comando.
Outra novidade referente a expressões é o novo predicado SIMILAR TO. Esta expressão é usada para fazer comparações usando expressões regulares de acordo com o padrão SQL. A listagem 11 mostra uma verificação de números de telefones cadastrados fora do padrão (NN) NNNN-NNNN. O caractere de escape funciona exatamente como no comando LIKE, considerando o próximo caractere como um valor literal, ao invés de usá-lo como um operador.
Listagem 11. Verificando números de telefones cadastrados fora do padrão.
SELECT * FROM PESSOAS
WHERE TELEFONE NOT SIMILAR TO
'([0-9]{2}) [0-9]{4}-[0-9]{4}' escape ''
Operador | Descrição |
X{2} | Duas ocorrências de X. |
X{2,} | Duas ou mais ocorrências de X. |
X{4,6} | De quatro a seis ocorrências de X. |
X? | Zero ou uma ocorrência de X. |
X* | Zero ou mais ocorrências de X. |
X+ | Uma ou mais ocorrências de X. |
X|Y | X ou Y. |
_ | Qualquer caractere - como no LIKE. |
% | Qualquer sequência de caracteres - como no LIKE. |
(X) | Agrupa X para ser tratado pelo operador subsequente. |
[XYZ] | Qualquer caractere igual a X, Y ou Z. |
[^XYZ] | Qualquer caractere diferente de X, Y ou Z. |
[X-Z] | Qualquer caractere entre X e Z. |
[[:CLASSE:]] | Qualquer caractere de uma certa classe, conforme tabela 2. |
Tabela 1. Operadores de expressões regulares.
Tabela 2. Classes de caracteres para expressões regulares.Classe | Descrição |
ALPHA | Qualquer caractere entre A e Z. |
UPPER | Qualquer caractere maiúsculo. |
LOWER | Qualquer caractere minúsculo. |
DIGIT | Dígitos de 0 a 9. |
SPACE | Espaço: caractere (ASCII_CHAR) 32. |
WHITESPACE | Todo tipo de espaço: caracteres 9, 10, 11, 12, 13 e 32. |
O Firebird 2.5 também suporta novos formatos de valores literais (constantes) para números e strings. Agora é possível escrever números inteiros no formato hexadecimal, usando o prefixo 0x. Quando o número possuir até 8 dígitos hexadecimais após o 0x, como em 0xFFFFFFFF, o número adquire o tipo INTEGER (32 bits com sinal). Quando possuir mais de 8 dígitos, como em 0x0FFFFFFFF, o tipo adquirido é o BIGINT (64 bits com sinal). Desta forma, estas duas constantes retornam valores diferentes, pois os números negativos são armazenados na notação complemento de dois [1].
Além de números, também é possível a criação de strings binárias (character set OCTETS) usando a notação hexadecimal x''. Em ambos os casos a letra X pode ser escrita em maiúscula ou minúscula. A listagem 12 mostra o uso destes novos tipos de valores literais. Note que cada par de caracteres hexadecimais se transforma em um byte na string resultante.
Listagem 12. Novos formatos de expressões literais.
SELECT 0xDEADBEEF, x'DEADBEEF' FROM RDB$DATABASE;
SELECT OCTET_LENGTH(x'DEADBEEF') FROM RDB$DATABASE;
-- Resultado de OCTET_LENGTH: 4, e não 8
A nova função BIN_NOT se junta ao grupo de funções binárias adicionadas na versão 2.1, BIN_AND e BIN_OR. Junto com as constantes hexadecimais, essa família de funções facilita o uso de máscaras de valores binários gravados em um único campo, técnica comumente utilizada em aplicações e agora facilitada no banco de dados. A listagem 13 mostra o uso da função BIN_NOT, que inverte todos os bits de um valor inteiro.
Listagem 13. Exemplo de uso da função BIN_NOT.
SELECT BIN_NOT(0xFFFFFFFF) FROM RDB$DATABASE; -– Resultado: 0
Listagem 14. Exemplo de uso das funções UUID_TO_CHAR e CHAR_TO_UUID.
SELECT UUID_TO_CHAR(UUID), DESCRICAO FROM OBJETOS
WHERE UUID = CHAR_TO_UUID(?);
Notas
[1] - Complemento de dois é a notação mais comum usada para representar números inteiros com sinal em sistemas computacionais. Nesta notação o bit mais significativo de um número positivo ou do número zero é representado como 0. Os números negativos são representados com os bits invertidos e somado o valor 1. Desta forma, em um número de 32 bits o 1 é representado com trinta e um bits 0 seguido por um bit 1, enquanto que o número -1 é representado por trinta e dois bits 1.
[2] - UUID (Universally Unique Identifier) é uma sequência aleatória de 16 bytes que, independente do local e momento que seja gerada, é única. Uma das utilidades dos UUIDs é criar chaves em sistemas distribuídos, como filiais de uma empresa com bancos de dados separados e que tenham os dados agregados em um banco principal através de replicação.