Tratamento de exceções¶
Em um bloco do Script Snowflake, você pode gerar uma exceção se ocorrer um erro. Você também pode tratar exceções que ocorrem em seu código do Script Snowflake.
Introdução ao tratamento de exceções no Script Snowflake¶
O Script Snowflake gera uma exceção se um erro ocorrer durante a execução de uma instrução. Por exemplo, se uma instrução tentar remover uma tabela que não existe, o Script Snowflake gera uma exceção.
Em um bloco do Script Snowflake, você pode escrever manipuladores de exceções que capturem tipos específicos de exceções declaradas nesse bloco e em blocos aninhados dentro dele. Além disso, para erros que podem ocorrer em seu código, você pode definir suas próprias exceções que você pode gerar quando erros ocorrerem.
Depois que as instruções no manipulador forem executadas, você poderá optar por sair do bloco ou continuar executando as instruções no bloco. Para obter mais informações, consulte Tratamento de exceções no Script Snowflake.
Quando uma exceção é gerada em um bloco do Script Snowflake, seja por seu código ou por uma instrução cuja execução falhar, o Script Snowflake tenta encontrar um manipulador para essa exceção:
Se o bloco no qual a exceção ocorreu tiver um manipulador para essa exceção, a execução será retomada no início desse manipulador de exceções.
Se o bloco não tiver seu próprio manipulador de exceções, a exceção poderá ser capturada pelo bloco superior.
Se a exceção ocorrer a mais de uma camada de profundidade, a exceção será enviada para cima, uma camada de cada vez, até que:
Uma camada com um manipulador de exceções adequado trate a exceção.
A camada mais externa seja atingida; nesse caso, ocorrerá um erro.
Se não houver um manipulador para a exceção no bloco atual ou em qualquer bloco adjacente, a execução do bloco será interrompida e o cliente que enviar o bloco para execução (por exemplo, Snowsight, SnowSQL e assim por diante) relatará isso como um erro do Snowflake.
Um manipulador de exceções pode conter seu próprio manipulador de exceções, caso uma exceção ocorra enquanto ele trata outra exceção.
Como declarar uma exceção no Script Snowflake¶
Você pode declarar sua própria exceção na seção DECLARE do bloco. Use a sintaxe descrita em Sintaxe da instrução de exceção. Por exemplo:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Como gerar uma exceção declarada no Script Snowflake¶
Para gerar uma exceção, execute o comando RAISE. Por exemplo:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
$$
;
Se não houver um manipulador, a execução será interrompida no ponto em que a exceção for gerada. No exemplo, counter nunca é incrementado e retornado.
O cliente que envia esse bloco para execução, por exemplo, Snowsight, relata um erro e indica que a exceção não foi capturada:
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Se você quiser adicionar código para tratar quaisquer exceções que você gerar (assim como exceções geradas quando as instruções não forem executadas), você pode escrever manipuladores de exceções. Consulte Tratamento de exceções no Script Snowflake.
Nota
Em um manipulador de exceções, se você precisar levantar a mesma exceção novamente, veja Gerar novamente a mesma exceção em um manipulador de exceções no Script Snowflake.
Tratamento de exceções no Script Snowflake¶
Você pode tratar uma exceção explicitamente capturando-a com uma cláusula EXCEPTION, ou você pode permitir que o bloco passe a exceção para o bloco superior.
Dentro da cláusula EXCEPTION, use uma cláusula WHEN para tratar uma exceção pelo nome. Você pode tratar tanto as exceções que você declara quanto as exceções internas. Atualmente, o Snowflake oferece as seguintes exceções internas:
STATEMENT_ERROR: Essa exceção indica um erro durante a execução de uma instrução. Por exemplo, se você tentar remover uma tabela que não existe, essa exceção é gerada.
EXPRESSION_ERROR: Essa exceção indica um erro relacionado a uma expressão. Por exemplo, se você criar uma expressão que é avaliada como um VARCHAR e tentar atribuir o valor da expressão a um FLOAT, esse erro será gerado.
Cada cláusula WHEN em um bloco de exceção pode ser de um dos seguintes tipos:
EXIT: o bloco executa as instruções no manipulador e depois sai do bloco atual. Se o bloco executar uma exceção desse tipo e o bloco contiver instruções após a instrução que causou o erro, essas instruções não serão executadas.
Se o bloco for um bloco interno e o manipulador de exceção não contiver uma instrução RETURN, a execução sairá do bloco interno e continuará com o código no bloco externo.
EXIT é o padrão.
CONTINUE: o bloco executa as instruções no bloco de exceção e continua com a instrução imediatamente após a que causou o erro.
Um manipulador CONTINUE pode capturar e manipular exceções sem encerrar o bloco de instruções que gerou a exceção. Com o manipulador padrão EXIT, quando ocorre um erro em um bloco, o fluxo é interrompido e o erro é retornado ao autor da chamada. No entanto, você pode usar um manipulador CONTINUE quando a condição de erro não é grave o suficiente para justificar a interrupção do fluxo.
Uma cláusula EXCEPTION pode ter cláusulas WHEN de ambos os tipos: EXIT e CONTINUE.
Quando ocorre uma exceção, você pode obter informações sobre a exceção lendo as três variáveis internas a seguir:
SQLCODE: Esse é um integer assinado de 5 dígitos. Para exceções definidas pelo usuário, essa é a
exception_numbermostrada na sintaxe para declarar uma exceção.SQLERRM: Essa é uma mensagem de erro. Para exceções definidas pelo usuário, essa é a
exception_messagemostrada na sintaxe para declarar uma exceção.SQLSTATE: Este é um código de 5 caracteres modelado no padrão ANSI SQL SQLSTATE. O Snowflake usa valores adicionais além daqueles do padrão ANSI SQL.
Quando você usa uma cláusula WHEN do tipo CONTINUE, essas variáveis internas refletem o erro que causou a exceção na cláusula WHEN. Depois que as instruções na cláusula WHEN forem concluídas e a execução da instrução continuar no bloco, os valores dessas variáveis retornarão os valores que tinham antes da exceção ter sido gerada.
Para tratar todas as outras exceções que não estão integradas ou declaradas, use uma cláusula WHEN OTHER THEN. A cláusula WHEN OTHER THEN pode ser do tipo EXIT ou CONTINUE.
Por exemplo, suponha que você tenha a seguinte tabela de log de erros para rastrear suas exceções:
CREATE OR REPLACE TABLE test_error_log(
error_type VARCHAR,
error_code VARCHAR,
error_message VARCHAR,
error_state VARCHAR,
error_timestamp TIMESTAMP);
O bloco anônimo a seguir insere informações sobre as exceções na tabela e retorna informações sobre elas para o usuário:
Dica
O exemplo define uma exceção na seção DECLARE e, em seguida, trata essa exceção. Para um exemplo que lida com uma exceção STATEMENT_ERROR, remova os comentários (--) dessa linha:
-- SELECT 1/0;
Para um exemplo que lida com outros erros, remova os comentários dessa linha:
-- LET var := 1/0;
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
$$
;
Para o valor retornado, este exemplo trata cada tipo de exceção chamando OBJECT_CONSTRUCT para construir e retornar um objeto que contém os detalhes sobre a exceção. O exemplo produz a seguinte saída:
+--------------------------------------+
| anonymous block |
|--------------------------------------|
| { |
| "Error type": "MY_EXCEPTION", |
| "SQLCODE": -20002, |
| "SQLERRM": "Raised MY_EXCEPTION.", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------------+
Você pode consultar o test_error_log tabela para confirmar que o erro foi registrado:
SELECT * FROM test_error_log;
+--------------+------------+----------------------+-------------+-------------------------+
| ERROR_TYPE | ERROR_CODE | ERROR_MESSAGE | ERROR_STATE | ERROR_TIMESTAMP |
|--------------+------------+----------------------+-------------+-------------------------|
| MY_EXCEPTION | -20002 | Raised MY_EXCEPTION. | P0001 | 2025-09-05 12:15:00.068 |
+--------------+------------+----------------------+-------------+-------------------------+
O exemplo anterior usou cláusulas WHEN do tipo padrão (EXIT). Se uma das cláusulas WHEN capturar uma exceção, ela executará as instruções na cláusula WHEN e depois sairá. Portanto, o código a seguir não é executado:
counter := counter + 1;
RETURN 'My counter value: ' || counter;
Se você quiser tratar uma exceção e depois continuar executando o código no bloco, especifique cláusulas WHEN do tipo CONTINUE. O exemplo a seguir é o mesmo que o exemplo anterior, mas especifica cláusulas WHEN do tipo CONTINUE e remove a instrução RETURN de cada cláusula WHEN:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR CONTINUE THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN my_exception CONTINUE THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN OTHER CONTINUE THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR CONTINUE THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN my_exception CONTINUE THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN OTHER CONTINUE THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
END;
$$
;
+---------------------+
| anonymous block |
|---------------------|
| My counter value: 1 |
+---------------------+
A saída mostra que o exemplo continuava executando o seguinte código depois que a exceção foi gerada:
counter := counter + 1;
RETURN counter;
Para mais informações sobre manipuladores CONTINUE, consulte EXCEPTION (Script Snowflake).
Em casos raros, você pode querer lidar explicitamente com uma exceção, não fazendo nada. Isto permite que você continue, em vez de encerrar, quando a exceção ocorre. Para obter mais informações, consulte o comando NULL.
Nota
Se você precisar gerar a mesma exceção novamente, veja Gerar novamente a mesma exceção em um manipulador de exceções no Script Snowflake.
Se você não configurar um manipulador para uma exceção, o cliente que envia o bloco para execução (por exemplo, a Snowsight) relatará um erro como explicado em Como gerar uma exceção declarada no Script Snowflake.
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Gerar novamente a mesma exceção em um manipulador de exceções no Script Snowflake¶
Em alguns casos, você pode precisar gerar a mesma exceção que você capturou em seu manipulador de exceções. Nesses casos, execute o comando RAISE sem especificar nenhum argumento.
Por exemplo, suponha que durante o tratamento de exceções, você precise capturar alguns detalhes sobre a exceção antes de gerar a mesma exceção novamente. Depois de capturar os detalhes, execute o comando RAISE:
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
EXECUTE IMMEDIATE $$
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
$$;
Como passar variáveis para um manipulador de exceção no Snowflake Scripting¶
É possível passar variáveis para um manipulador de exceção. O manipulador de exceção pode executar código com base no valor da variável, e o valor da variável pode ser retornado em mensagens de erro.
Para que uma variável seja passada para um manipulador na seção EXCEPTION, a variável deve ser declarada na seção DECLARE. Se uma variável for declarada na seção BEGIN … END do bloco, ela não poderá ser acessada na seção EXCEPTION.
Além disso, se você estiver escrevendo um procedimento armazenado do Snowflake Scripting que aceita argumentos, é possível usar esses argumentos em um manipulador de exceção.
Por exemplo, o seguinte bloco anônimo passa o valor da variável counter_val para o manipulador de exceção:
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
$$
;
O bloco retorna a seguinte mensagem de erro:
+---------------------------------------------------------+
| anonymous block |
|---------------------------------------------------------|
| Error -20002: Counter value 11 exceeds the limit of 10. |
+---------------------------------------------------------+
A seguir está um exemplo de um procedimento armazenado do Snowflake Scripting que passa um argumento. O exemplo demonstra como você pode usar o argumento em um manipulador de exceção:
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
Observação: se você usar o Snowflake CLI, SnowSQL, o Classic Console, ou o método execute_stream ou execute_string no código Python Connector, use este exemplo (consulte Usar o Snowflake Scripting no Snowflake CLI, SnowSQL, Classic Console e Python Connector):
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
$$
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
$$
;
As seguintes chamadas para o procedimento armazenado mostram a saída esperada:
CALL exception_test_vars(7);
+------------------------------+
| EXCEPTION_TEST_VARS |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+