EXCEPTION (Script Snowflake)¶
Especifica como lidar com exceções geradas no bloco do Script Snowflake.
Para obter mais informações sobre exceções, consulte Tratamento de exceções.
- Consulte também:
Sintaxe¶
EXCEPTION
WHEN <exception_name> [ OR <exception_name> ... ] [ { EXIT | CONTINUE } ] THEN
<statement>;
[ <statement>; ... ]
[ WHEN ... ]
[ WHEN OTHER [ { EXIT | CONTINUE } ] THEN ]
<statement>;
[ <statement>; ... ]
Onde:
exception_nameUm nome de exceção definido na parte DECLARE do bloco atual ou em um bloco delimitador.
statementUma instrução pode ser qualquer uma das seguintes opções:
Uma única instrução SQL (incluindo CALL).
Uma instrução de fluxo de controle (por exemplo, uma instrução de loop ou ramificação).
Um bloco aninhado.
Notas de uso¶
Cada bloco pode ter seu próprio manipulador de exceção.
O Snowflake não oferece suporte a mais do que um manipulador de exceção por bloco. Entretanto, esse manipulador pode pegar mais de um tipo de exceção por ter mais de uma cláusula
WHEN.A cláusula
WHEN OTHER [ { EXIT | CONTINUE } ] THENcaptura qualquer exceção ainda não especificada.Um manipulador de exceção se aplica a instruções entre BEGIN e EXCEPTION Seções do bloco no qual é declarado. Ele não se aplica ao DECLARE Seção do bloco.
Um manipulador de exceção só pode lidar com uma exceção especificada se essa exceção especificada estiver no escopo.
Se um procedimento armazenado se destina a retornar um valor, ele deve retornar um valor de cada caminho de saída possível, incluindo cada cláusula
WHENdo tipoEXITno manipulador de exceções.Para usar uma variável em um manipulador de exceção, a variável deve ser declarada na seção DECLARE ou passada como um argumento para um procedimento armazenado. Não pode ser declarada na seção BEGIN … END. Para obter mais informações, consulte Como passar variáveis para um manipulador de exceção no Snowflake Scripting.
Quando ocorre uma exceção, as condições do manipulador são verificadas em ordem e o primeiro
WHENA cláusula que corresponde é usada. A ordem dentro de um bloco é de cima para baixo, e os blocos internos são verificados antes dos blocos externos. Não há preferência na correspondênciaEXITouCONTINUEmanipuladores, o que corresponder primeiro será usado.Apenas um manipulador pode ser correspondido para uma instrução. No entanto, qualquer exceção encontrada dentro de um corpo do manipulador de exceções pode acionar manipuladores de exceções de bloco externo.
Cada
WHENA cláusula em um manipulador de exceção pode ser de um dos seguintes tipos:EXITo 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 o manipulador de exceção, essas instruções não serão executadas.Se o bloco for um bloco interno e o manipulador de exceção não contiver um
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 manipulador e continua com a instrução imediatamente após a que causou o erro.
Uma cláusula
EXCEPTIONpode ter cláusulasWHENde ambos os tipos:EXITeCONTINUE.Para uma cláusula
WHENdo tipoCONTINUE, as seguintes notas de uso são aplicadas:Se um erro for levantado em um construção de ramificação, a instrução contínua será a instrução imediatamente após a construção da ramificação.
Se um erro for gerado na condição de um Loop, a instrução contínua é a instrução imediatamente após o loop.
Se um erro for levantado no corpo de um loop, então a instrução contínua é a instrução na próxima iteração do loop. Para obter um exemplo, consulte Tratamento de uma exceção e continuação.
Se um erro for levantado em uma instrução RETURN, então a instrução que continua é a instrução imediatamente após a instrução
RETURN.Se um erro for levantado em um procedimento armazenado aninhado e o erro é tratado pelo escopo externo, então a instrução contínua é a instrução imediatamente após a chamada do procedimento armazenado.
Evite incluir uma instrução
RETURNem uma cláusulaWHENdo tipoCONTINUE. Se você incluir uma instruçãoRETURN, então o procedimento armazenado retorna sem continuar.
Para uma cláusula
WHENdo tipoCONTINUE, os exemplos a seguir mostram qual instrução é a instrução imediatamente após a que causou o erro para diferentes cenários. Nesses exemplos, oerror_expressioné a expressão que gerou a exceção, e ocontinue_statementé a instrução com a qual o código continua no bloco após as instruções do manipuladorCONTINUE.DECLARE ... BEGIN ... LET a := <error_expression>; <continue_statement>; ... EXCEPTION WHEN <exception_name> CONTINUE THEN ... END;
LET x := <valid_expression>; x := <error_expression>; <continue_statement>
SELECT <statement> INTO <error_expression>; <continue_statement>;
IF (<error_expression>) THEN <statement> ELSEIF (<valid_expression>) THEN <statement> ELSE <statement> END IF; <continue_statement>;
CASE (<error_expression>) WHEN (<valid_expression>) THEN <statement> ELSE <statement> END CASE; <continue_statement>
CASE (<valid_expression>) WHEN (<error_expression>) THEN <statement> WHEN (<valid_expression>) THEN <statement> ELSE <statement> END CASE; <continue_statement>
FOR i IN <valid_expression> TO <error_expression> DO <statement> END FOR <continue_statement>
WHILE <error_expression> DO <statement> END WHILE; <continue_statement>
REPEAT <statement> UNTIL <error_expression>; <continue_statement>
RETURN <error_expression>; <continue_statement>
DECLARE x int := 0; myproc PROCEDURE() RETURNS STRING AS BEGIN x := <error_expression>; <statement> END; BEGIN CALL myproc(); <continue_statement> ... END;
Exemplos¶
Os exemplos a seguir declaram e geram exceções e tratam as exceções com manipuladores de exceção:
Tratamento de exceções de mais de um tipo¶
O exemplo a seguir mostra um manipulador de exceções projetado para lidar com mais de um tipo de exceção:
DECLARE
result VARCHAR;
exception_1 EXCEPTION (-20001, 'I caught the expected exception.');
exception_2 EXCEPTION (-20002, 'Not the expected exception!');
BEGIN
result := 'If you see this, I did not catch any exception.';
IF (TRUE) THEN
RAISE exception_1;
END IF;
RETURN result;
EXCEPTION
WHEN exception_2 THEN
RETURN SQLERRM;
WHEN exception_1 THEN
RETURN SQLERRM;
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
result VARCHAR;
exception_1 EXCEPTION (-20001, 'I caught the expected exception.');
exception_2 EXCEPTION (-20002, 'Not the expected exception!');
BEGIN
result := 'If you see this, I did not catch any exception.';
IF (TRUE) THEN
RAISE exception_1;
END IF;
RETURN result;
EXCEPTION
WHEN exception_2 THEN
RETURN SQLERRM;
WHEN exception_1 THEN
RETURN SQLERRM;
END;
$$;
A saída mostra que o manipulador de exceção pegou a exceção.
+----------------------------------+
| anonymous block |
|----------------------------------|
| I caught the expected exception. |
+----------------------------------+
Tratamento de uma exceção e continuação¶
O exemplo a seguir mostra um manipulador de exceção com uma cláusula WHEN do tipo CONTINUE:
DECLARE
exception_1 EXCEPTION (-20001, 'Catch and continue');
BEGIN
LET counter := 0;
IF (TRUE) THEN
RAISE exception_1;
END IF;
counter := counter + 10;
RETURN 'Counter value: ' || counter;
EXCEPTION
WHEN exception_1 CONTINUE THEN
counter := counter +1;
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
exception_1 EXCEPTION (-20001, 'Catch and continue');
BEGIN
LET counter := 0;
IF (TRUE) THEN
RAISE exception_1;
END IF;
counter := counter + 10;
RETURN 'Counter value: ' || counter;
EXCEPTION
WHEN exception_1 CONTINUE THEN
counter := counter +1;
END;
$$;
A saída mostra que o manipulador de exceção pegou a exceção, executou uma instrução que adicionou 1 ao contador, e então executava a instrução seguinte depois que a exceção foi capturada, o que adicionou 10 para o contador:
+-------------------+
| anonymous block |
|-------------------|
| Counter value: 11 |
+-------------------+
O exemplo a seguir mostra como um manipulador de exceção com uma cláusula WHEN do tipo CONTINUE funciona quando um erro é gerado em um loop. O exemplo gera um erro na primeira iteração porque tenta dividir o valor 10 por zero. O CONTINUE o manipulador registra o erro na error_log_table, e o bloco continua com a próxima iteração do loop, que divide 10 por 1. O loop continua a iterar até 10 é dividido por 5 e o loop termina. A saída é 2:
CREATE TABLE error_log_table (handler_type VARCHAR, error_message VARCHAR);
DECLARE
x INT := 0;
BEGIN
FOR i IN 0 TO 5 DO
x := 10/i;
END FOR;
RETURN x;
EXCEPTION
WHEN EXPRESSION_ERROR CONTINUE THEN
INSERT INTO error_log_table SELECT 'continue_type', :SQLERRM;
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 TABLE error_log_table (handler_type VARCHAR, error_message VARCHAR);
EXECUTE IMMEDIATE $$
DECLARE
x INT := 0;
BEGIN
FOR i IN 0 TO 5 DO
x := 10/i;
END FOR;
RETURN x;
EXCEPTION
WHEN EXPRESSION_ERROR CONTINUE THEN
INSERT INTO error_log_table SELECT 'continue_type', :SQLERRM;
END;
$$;
+-----------------+
| anonymous block |
|-----------------|
| 2 |
+-----------------+
Tratar exceções em blocos aninhados¶
Este exemplo a seguir demonstra blocos aninhados e mostra que um bloco interno pode gerar uma exceção declarada tanto no bloco interno quanto no externo:
DECLARE
e1 EXCEPTION (-20001, 'Exception e1');
BEGIN
-- Inner block.
DECLARE
e2 EXCEPTION (-20002, 'Exception e2');
selector BOOLEAN DEFAULT TRUE;
BEGIN
IF (selector) THEN
RAISE e1;
ELSE
RAISE e2;
END IF;
END;
EXCEPTION
WHEN e1 THEN
RETURN SQLERRM || ' caught in outer block.';
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
e1 EXCEPTION (-20001, 'Exception e1');
BEGIN
-- Inner block.
DECLARE
e2 EXCEPTION (-20002, 'Exception e2');
selector BOOLEAN DEFAULT TRUE;
BEGIN
IF (selector) THEN
RAISE e1;
ELSE
RAISE e2;
END IF;
END;
EXCEPTION
WHEN e1 THEN
RETURN SQLERRM || ' caught in outer block.';
END;
$$;
A saída mostra que o manipulador de exceção pegou a exceção.
+-------------------------------------+
| anonymous block |
|-------------------------------------|
| Exception e1 caught in outer block. |
+-------------------------------------+
Este exemplo seguinte é semelhante ao exemplo anterior, mas demonstra blocos aninhados, cada um dos quais com seu próprio manipulador de exceção:
DECLARE
result VARCHAR;
e1 EXCEPTION (-20001, 'Outer exception e1');
BEGIN
result := 'No error so far (but there will be).';
DECLARE
e1 EXCEPTION (-20101, 'Inner exception e1');
BEGIN
RAISE e1;
EXCEPTION
WHEN e1 THEN
result := 'Inner exception raised.';
RETURN result;
END;
RETURN result;
EXCEPTION
WHEN e1 THEN
result := 'Outer exception raised.';
RETURN result;
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
result VARCHAR;
e1 EXCEPTION (-20001, 'Outer exception e1');
BEGIN
result := 'No error so far (but there will be).';
DECLARE
e1 EXCEPTION (-20101, 'Inner exception e1');
BEGIN
RAISE e1;
EXCEPTION
WHEN e1 THEN
result := 'Inner exception raised.';
RETURN result;
END;
RETURN result;
EXCEPTION
WHEN e1 THEN
result := 'Outer exception raised.';
RETURN result;
END;
$$;
Nota
Este exemplo usa o mesmo nome de exceção (e1) nos blocos externo e interno, o que não é recomendado.
O exemplo faz isso para ilustrar o escopo dos nomes de exceção. As duas exceções com o nome e1 são exceções diferentes.
O manipulador e1 no bloco externo não lida com a exceção e1 que é declarada e gerada no bloco interno.
A saída mostra que o manipulador de exceção interno funcionou:
+-------------------------+
| anonymous block |
|-------------------------|
| Inner exception raised. |
+-------------------------+
Tratamento de exceções múltiplas na mesma cláusula e exceções não especificadas¶
O fragmento de exemplo a seguir mostra como executar duas tarefas:
Capture mais de uma exceção na mesma cláusula usando
OR.Capture exceções não especificadas usando
WHEN OTHER THEN.
EXCEPTION
WHEN MY_FIRST_EXCEPTION OR MY_SECOND_EXCEPTION OR MY_THIRD_EXCEPTION THEN
RETURN 123;
WHEN MY_FOURTH_EXCEPTION THEN
RETURN 4;
WHEN OTHER THEN
RETURN 99;
Tratamento de exceções usando variáveis internas¶
O exemplo a seguir mostra como retornar SQLCODE, SQLERRM (SQL mensagem de erro) e SQLSTATE valores de variáveis internas ao capturar uma exceção:
DECLARE
MY_EXCEPTION EXCEPTION (-20001, 'Sample message');
BEGIN
RAISE MY_EXCEPTION;
EXCEPTION
WHEN STATEMENT_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN EXPRESSION_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'EXPRESSION_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN OTHER THEN
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 (-20001, 'Sample message');
BEGIN
RAISE MY_EXCEPTION;
EXCEPTION
WHEN STATEMENT_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN EXPRESSION_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'EXPRESSION_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
END;
$$;
A execução deste exemplo produz os seguintes resultados:
+--------------------------------+
| anonymous block |
|--------------------------------|
| { |
| "Error type": "Other error", |
| "SQLCODE": -20001, |
| "SQLERRM": "Sample message", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------+