Deu erro por incompatibilidade de tipos de dados. E agora?
Veja o que fazer quando, ao criar um procedimento armazenado, dá erro por incompatibilidade de tipos de dados.
Dia destes eu estava criando um procedimento armazenado e, como sempre, focando minha atenção nas coisas que eu considerava mais importantes:
- A lógica de negócios;
- A estrutura adequada das declarações SQL para fazer uso dos índices de cada tabela;
- Tratamento de erros e controle da transação.
Depois de algum trabalho, meu procedimento estava pronto. Foi criado usando o Command Line Processor (CLP) para rodar no DB2 em LINUX 64-bits. A sintaxe desta rotina é mostrada no código ao final do artigo.
Salvei este código no arquivo meuscript.db2 e executei o comando para criação da rotina. Para quem não conhece DB2 CLP, o parâmetro “-td” especifica o caractér de identificação de instruções dentro de um procedimento armazenado.
db2 -td@ -vf meuscript.db2
A rotina foi criada com sucesso. Em seguida, fui testá-la:
db2 "CALL meuesquema.procedimento1 ('2013-01-22 00:00:00', '2013-03-30 00:00:00')"
Foi aqui que tive uma surpresa, porque observei que minha transação nunca se completava (ROLLBACK). Rodando passo a passo as instruções da lógica de negócios, identifiquei uma mensagem de erro de SQL informando “tipos de dados incompatíveis”.
Examinando meu código com mais atenção, encontrei o problema. Observe que na instrução de INSERT eu especifiquei o uso da função COALESCE:
COALESCE(T.END_TIMESTAMP, '00:00:00')
Isso quer dizer o seguinte: se o campo END_TIMESTAMP for não nulo, use o seu valor. Do contrário, use o valor “00:00:00”.
Note que o horário “00:00:00” parece um TIMESTAMP, mas não é. No DB2, o tipo de dados TIMESTAMP aceita valores entre 0001-01-01-00.00.00.000000000 e 9999-12-31-24.00.00.000000000.
Sendo assim, o correto seria alterar o valor da função COALESCE para usar o menor TIMESTAMP reconhecido:
COALESCE(T.END_TIMESTAMP, '0001-01-01-00:00:00')
Depois de recriar a rotina e repetir o teste, vemos que tudo passa a funcionar adequadamente. Até parece piada o tempo que perdemos depurando erros elementares, mas isso tem a haver com a nossa falta de atenção com os detalhes. Nos preocupamos muito com o que nos parece complexo: lógicas de negócio, processos, etc. Mas não costumamos dar a devida atenção aos detalhes, como sintaxes ou tipos de dados.
Então fica a dica: cuidado com os erros bobos. Isso pode comprometer sua produtividade.
-- script DDL (criatabelas.ddl)
-- criacao de tabelas
CREATE TABLE meuesquema.tabela1 (nome VARCHAR(50), userid VARCHAR(50), start_timestamp TIMESTAMP , end_timestamp TIMESTAMP );
INSERT INTO meuesquema.tabela1 VALUES ('wagner', 'wcrivelini', '2013-03-01 0:00:00', null);
CREATE TABLE meuesquema.tabela2 (campo1 VARCHAR(50), campo2 VARCHAR(50), campo3 TIMESTAMP );
-- script da rotina (meuscript.db2)
--procedimento armazenado em questão
CREATE PROCEDURE meuesquema.procedimento1 (
startDate TIMESTAMP,
endDate TIMESTAMP)
LANGUAGE SQL
DYNAMIC RESULT SETS 1
BEGIN
--===============================================
--error handling
--===============================================
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE l_error CHAR(5) DEFAULT '00000';
DECLARE intError INT;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET l_error = '00000';
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING
BEGIN
SET l_error = SQLSTATE;
IF SUBSTR(l_error, 1, 1) >= '5' AND SUBSTR(l_error, 1, 1) <= '9' THEN
RESIGNAL;
END IF;
END;
--===============================================
-- business logic
--===============================================
INSERT INTO meuesquema.tabela2 (campo1, campo2, campo3)
SELECT
UPPER(T.NOME) AS CAMPO1,
T.USERID AS CAMPO2,
COALESCE(T.END_TIMESTAMP, '00:00:00') AS CAMPO3
FROM meuesquema.tabela1 T
WHERE T.START_TIMESTAMP BETWEEN startDate AND endDate;
SET l_error = SQLSTATE ;
IF LEFT(l_error, 2 ) > '02' THEN
SET intError = intError + 1 ;
END IF;
--===============================================
-- finishing transaction
===============================================
IF intError > 0 THEN
ROLLBACK;
RETURN intError ;
END IF;
COMMIT;
END
@







