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.

  • A cláusula WHEN OTHER [ { EXIT | CONTINUE } ] THEN captura 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 WHEN do tipo EXIT no 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 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

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

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

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

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

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

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;
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"          |
| }                              |
+--------------------------------+