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:

RAISE

Sintaxe

EXCEPTION
    WHEN <exception_name> [ OR <exception_name> ... ] [ { EXIT | CONTINUE } ] THEN
        <statement>;
        [ <statement>; ... ]
    [ WHEN ... ]
    [ WHEN OTHER [ { EXIT | CONTINUE } ] THEN ]
        <statement>;
        [ <statement>; ... ]
Copy

Onde:

exception_name

Um nome de exceção definido na parte DECLARE do bloco atual ou em um bloco delimitador.

statement

Uma 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.

  • The WHEN OTHER [ { EXIT | CONTINUE } ] THEN clause catches any exception not yet specified.

  • 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.

  • If a stored procedure is intended to return a value, then it should return a value from each possible exit path, including each WHEN clause of EXIT type in the exception handler.

  • 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 Passing variables to an exception handler in Snowflake Scripting.

  • Quando ocorre uma exceção, as condições do manipulador são verificadas em ordem e o primeiro WHEN A 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ência EXIT ou CONTINUE manipuladores, 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 WHEN A cláusula em um manipulador 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 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 EXCEPTION pode ter cláusulas WHEN de ambos os tipos: EXIT e CONTINUE.

    Para uma cláusula WHEN do tipo CONTINUE, 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 RETURN em uma cláusula WHEN do tipo CONTINUE. Se você incluir uma instrução RETURN, então o procedimento armazenado retorna sem continuar.

    Para uma cláusula WHEN do tipo CONTINUE, 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, o error_expression é a expressão que gerou a exceção, e o continue_statement é a instrução com a qual o código continua no bloco após as instruções do manipulador CONTINUE.

    DECLARE
      ...
    BEGIN
      ...
      LET a := <error_expression>;
      <continue_statement>;
      ...
    EXCEPTION
      WHEN <exception_name> CONTINUE THEN
        ...
    END;
    
    Copy
    LET x := <valid_expression>;
    x := <error_expression>;
    <continue_statement>
    
    Copy
    SELECT <statement> INTO <error_expression>;
    <continue_statement>;
    
    Copy
    IF (<error_expression>) THEN
      <statement>
    ELSEIF (<valid_expression>) THEN
      <statement>
    ELSE
      <statement>
    END IF;
    <continue_statement>;
    
    Copy
    CASE (<error_expression>)
      WHEN (<valid_expression>) THEN
        <statement>
      ELSE
        <statement>
    END CASE;
    <continue_statement>
    
    Copy
    CASE (<valid_expression>)
      WHEN (<error_expression>) THEN
        <statement>
      WHEN (<valid_expression>) THEN
        <statement>
      ELSE
        <statement>
    END CASE;
    <continue_statement>
    
    Copy
    FOR i IN <valid_expression> TO <error_expression> DO
      <statement>
    END FOR
    <continue_statement>
    
    Copy
    WHILE <error_expression> DO
      <statement>
    END WHILE;
    <continue_statement>
    
    Copy
    REPEAT
      <statement>
    UNTIL <error_expression>;
    <continue_statement>
    
    Copy
    RETURN <error_expression>;
    <continue_statement>
    
    Copy
    DECLARE
      x int := 0;
      myproc PROCEDURE()
        RETURNS STRING
        AS BEGIN
          x := <error_expression>;
          <statement>
        END;
    BEGIN
      CALL myproc();
      <continue_statement>
      ...
    END;
    
    Copy

Exemplos

The following examples declare and raise an exceptions, and handle the exceptions with exception handlers:

Tratamento de exceções de mais de um tipo

The following example shows an exception handler that is designed to handle more than one type of exception:

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;
Copy

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;
$$;
Copy

The output shows that the exception handler caught the exception:

+----------------------------------+
| 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;
Copy

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;
$$;
Copy

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;
Copy

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;
$$;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               2 |
+-----------------+

Tratar exceções em blocos aninhados

This following example demonstrates nested blocks, and shows that an inner block can raise an exception declared in either the inner block or in an outer block:

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;
Copy

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;
$$;
Copy

The output shows that the exception handler caught the exception:

+-------------------------------------+
| anonymous block                     |
|-------------------------------------|
| Exception e1 caught in outer block. |
+-------------------------------------+

This following example is similar to the previous example, but demonstrates nested blocks, each of which has its own exception handler:

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;
Copy

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;
$$;
Copy

Nota

This example uses the same exception name (e1) in the outer and inner blocks, which isn’t recommended.

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.

The e1 handler in the outer block doesn’t handle the exception e1 that is declared and raised in the inner block.

The output shows that the inner exception handler ran:

+-------------------------+
| anonymous block         |
|-------------------------|
| Inner exception raised. |
+-------------------------+

Tratamento de exceções múltiplas na mesma cláusula e exceções não especificadas

The following example fragment shows how to perform two tasks:

  • Catch more than one exception in the same clause by using OR.

  • Catch unspecified exceptions by using 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;
Copy

Tratamento de exceções usando variáveis internas

The following example shows how to return SQLCODE, SQLERRM (SQL error message), and SQLSTATE built-in variable values when catching an exception:

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;
Copy

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;
$$;
Copy

A execução deste exemplo produz os seguintes resultados:

+--------------------------------+
| anonymous block                |
|--------------------------------|
| {                              |
|   "Error type": "Other error", |
|   "SQLCODE": -20001,           |
|   "SQLERRM": "Sample message", |
|   "SQLSTATE": "P0001"          |
| }                              |
+--------------------------------+