(Parte 4 de 13)

O campo RDB$TRIGGER_TYPE (relação RDB$TRIGGERS) foi estendido para permitir estas operações de triggers complexas. Se desejar obter mais detalhes, leia o documento readme.universal_triggers.txt no diretório /doc/sql.extensions na árvore CVS do Firebird. Nota (s): 1. Triggers de apenas uma ação são totalmente compatíveis ao nível de ODS com o FB 1.0. 2. O tipo de RDB$TRIGGER_TYPE depende da sua ordem, i.e., BEFORE INSERT OR UPDATE e BEFORE

UPDATE OR INSERT serão codificados de forma diferente, embora compartilhem a mesma semântica e sejam executados exatamente da mesma forma. 3. As variáveis de contexto OLD e NEW estão disponíveis em triggers de múltipla ação. Se a operação que disparar o trigger for incompatível com o seu uso (por exemplo, OLD numa operação de INSERT), todos os campos nesse contexto serão tratados como NULL. A tentativa de atribuir um valor a uma variável num contexto inválido irá provocar uma exceção. 4. Foram criadas novas variáveis de contexto - INSERTING/UPDATING/DELETING – que podem ser utilizadas para verificar a operação em tempo de execução. (Veja mais adiante)

Exatamente o mesmo que CREATE VIEW se a view ainda não existir. Se ela já existir, RECREATE VIEW irá tentar destrui-la antes de criar um novo objeto. RECREATE VIEW irá falhar se o objeto estiver em uso. Utiliza a mesma sintaxe que CREATE VIEW.

(1.5) CREATE OR ALTER {TRIGGER | PROCEDURE }

Esta declaração irá criar um novo trigger ou procedure (se ainda não existirem) ou alterá-lo (caso eles já existam) e voltar a recompilá-lo. A sintaxe CREATE OR ALTER preserva as dependências e permissões existentes.

A sintaxe é a mesma de CREATE TRIGGER | CREATE PROCEDURE, respectivamente, exceto a declaração “OR ALTER”.

(1.5) NULLs em “unique constraints” e índices Dmitry Yemanov

Agora é possível aplicar uma “constraint” UNIQUE ou um índice UNIQUE a colunas que não possuam a “constraint” NOT NULL, em acordo com o SQL-9. Tenha cuidado com a utilização desta nova funcionalidade se planeja reverter a sua base de dados para Firebird 1.0.x ou qualquer versão do Interbase.

< definição de constraint ou definição de índice > ::= < especificação única > ( < lista de colunas únicas - LCU > )

< especificação única > ::= {{[constraint-name]UNIQUE | UNIQUE INDEX nome-índice]} | [constraint-name] PRIMARY KEY} v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 12

Onde < lista de colunas únicas > pode conter uma ou mais colunas sem o atributo NOT NULL se a < especificação única > utilizada for UNIQUE OR UNIQUE INDEX. Note que todas as colunas que participem de uma chave primária ainda precisam ser declaradas como NOT NULL.

A constraint permite a existência somente daquelas linhas que retornem como verdadeiras as condições de procura (i) or (i) , seguindo a seguinte lógica :

i) Se a < especificação única > for PRIMARY KEY, então a condição de procura deverá ser : UNIQUE ( SELECT LCU FROM TN ) AND ( LCU ) IS NOT NULL i) De outra forma, a < condição de procura > deverá ser : UNIQUE ( SELECT LCU FROM TN )

Neste caso, a condição única não será verdadeira se ( SELECT LCU FROM TN ) retornar duas linhas em que os correspondentes segmentos não nulos sejam iguais.

A “constraint“ permite a existência somente das linhas onde a já mencionada < condição de procura > seja avaliada como verdadeira. Em um < UNIQUE INDEX > ou sobre uma constraint UNIQUE, dois conjuntos de valores de colunas será considerado distinto, e assim legítimos se : a) Ambos os conjuntos contém apenas nulos, ou b) Há pelo menos um par de valores onde um dos valores correspondentes é diferente de nulo e o outro é ou nulo ou um valor não nulo diferente.

Exemplos UNIQUE constraint: CREATE TABLE t (a INTEGER, b INTEGER, CONSTRAINT pk UNIQUE (a, b)); ou UNIQUE index: CREATE TABLE t (a INTEGER, b INTEGER); COMMIT; CREATE UNIQUE INDEX uqx ON t(a, b); COMMIT; INSERT INTO t VALUES (NULL, NULL); /* ok, nulos permitidos */ INSERT INTO t VALUES (1, 2); /* assim como não nulos */ INSERT INTO t VALUES (1, NULL); /* e combinações */ INSERT INTO t VALUES (NULL, NULL); /* ok, pares nulos são consideredos distintos */ mas INSERT INTO t VALUES (1, NULL); /* incorreto porque os segmentos não nulos correspondentes são iguais */

Ou seja, uma constraint PRIMARY KEY não permite nulos enquanto uma constraint UNIQUE ou um UNIQUE INDEX permite quantidades arbitrárias de nulos. Para resultados multi-colunados de ( SELECT UCL FROM TN ), as regras comuns de nulo se aplicam , i.e. (1, NULL) é distinto de (NULL, 1) e um (NULL, NULL) é distinto de qualquer outro (NULL, NULL).

v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 13

(1.5) Expressões e variáveis como argumentos de procedure Dmitry Yemanov

Chamadas a EXECUTE PROCEDURE ProcName(<Lista-De-Argumentos >) e SELECT <lista-Do-Output> FROM ProcName(<Lista-De-Argumentos >) agora permitem como argumentos variáveis locais (em PSQL) e expressões (em DSQL e PSQL).

(1.5) Novas construções para Expressões Condicionais Arno Brinkman

Permite que o resultado de uma coluna seja determinado com base na avaliação de um conjunto de condições exclusivas.

Sintaxe <expressão case> ::=

<abreviatura de case> | <especificação case>
NULLIF <parent. esquerdo> <expressão ou valor> <vírgula> <expressão ou valor> <parent. direito>
| COALESCE <parent. esquerdo> <expressão ou valor> {<vírgula> <expressão ou valor>}...<parent.

<abreviatura de case> ::= direito>

<case simples> | <case com condição>

<especificação case> ::=

CASE <expressão ou valor> <cláusula when simples>...
[ <cláusula else> ]
END

<case simples> ::=

CASE <cláusula when condicional>...
[ <cláusula else> ]
END

<case> ::=

<cláusula when simples> ::= WHEN <operador de when> THEN <resultado> <cláusula when condicional > ::= WHEN <condição de procura> THEN <resultado>

<operador de when> ::= <expressão ou valor>

<cláusula else> ::= ELSE <resultado>

<resultado> ::= <expressão resultado> | NULL

<expressão resultado> ::= <expressão ou valor>

Exemplos i) simples v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 14

o.ID,
o.Description,
CASE o.Status
WHEN 1 THEN 'Confirmado'
WHEN 2 THEN 'Em produção'
WHEN 3 THEN 'Disponível'
WHEN 4 THEN 'Enviado'
ELSE 'Status Desconhecido: ''' || o.Status || ''''
END

SELECT FROM Orders o; i) condicional

o.ID,
o.Description,
CASE
WHEN (o.Status IS NULL) THEN 'Novo'
WHEN (o.Status = 1) THEN 'Confirmado'
WHEN (o.Status = 3) THEN 'Em produção'
WHEN (o.Status = 4) THEN 'Disponivel'
WHEN (o.Status = 5) THEN 'Enviado'
ELSE 'Status Desconhecido: ''' || o.Status || ''''
END

SELECT FROM Orders o; b) COALESCE

Permite que o valor de uma coluna seja definido por um série de expressões, onde a primeira destas expressões que resulte em um valor não nulo (NOT NULL) será o valor retornado.

| COALESCE <parent. esquerdo> <expressão ou valor> { <vírgula> <expressão ou valor> }... <parent.

Formato <abreviatura de case> ::= direito>

i) COALESCE (V1, V2) equivale à seguinte expressão <case >:
CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END
i) COALESCE (V1, V2,..., Vn), para n >= 3, é equivalente a um <case>:
CASE WHEN V1 IS NOT NULL THEN V1 ELSE COALESCE (V2,...,Vn) END

Regras de Sintaxe

Exemplos

PROJ_NAME AS NomeDoProjeto,
COALESCE(e.FULL_NAME,'[> Não Atribuído <]') AS Funcionario
PROJET p
LEFT JOIN EMPLOYEE e ON (e.EMP_NO = p.TEAM_LEADER);
COALESCE(Phone,MobilePhone,'Desconhecido') AS Telefone

SELECT FROM Relations v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 15

Retorna NULL para uma expressão se ela resultar no valor especificado, caso contrário retorna o próprio valor da expressão.

NULLIF <parent. esquerdo> <expressão ou valor> <vírgula> <expressão ou valor> <parent. direito>

Formato <abreviatura de case> ::=

CASE WHEN V1 = V2 THEN NULL ELSE V1 END

Regras de Sintaxe NULLIF (V1, V2) é equivalente ao <case >:

Exemplo

SET STOCK = NULLIF(STOCK,0)

(1.5) “SAVEPOINTs” compatíveis com SQL99 Nickolay Samofatov

SAVEPOINTs definidos pelo usuário (também conhecidos como “nested transactions”) disponibilizam um método conveniente para tratar erros de lógica sem a necessidade de fazer um rollback da transação como um todo. Disponível apenas em DSQL.

Utilize uma declaração SAVEPOINT para identificar um ponto de transação, ao qual será possível retornar através de um “Rollback” parcial.

SAVEPOINT <identificador>;

<identificador> especifica o nome do SAVEPOINT que será estabelecido. Depois de criado um SAVEPOINT você pode continuar o processamento, executar um commit ou um rollback de toda a transação, ou ainda um rollback até o SAVEPOINT.

Os nomes dos SAVEPOINT devem que ser únicos no contexto de uma transação. Se um segundo SAVEPOINT for estabelecido com o mesmo identificador, o primeiro será sobreposto.

(Parte 4 de 13)

Comentários