EXCEPTION (Exécution de scripts Snowflake)

Spécifie comment traiter les exceptions soulevées dans le bloc Exécution de scripts Snowflake.

Pour plus d’informations sur les exceptions, voir Traitement des exceptions.

Voir aussi:

RAISE

Syntaxe

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

Où :

exception_name

Un nom d’exception défini dans la partie DECLARE du bloc actuel, ou dans un bloc englobant.

statement

Une instruction peut être l’un des éléments suivants :

  • Une seule instruction SQL (y compris CALL).

  • Une instruction de flux de contrôle (par exemple, une instruction de bouclage ou de branchement).

  • Un bloc imbriqué.

Notes sur l’utilisation

  • Chaque bloc peut avoir son propre gestionnaire d’exception.

  • Snowflake ne prend pas en charge plus d’un gestionnaire d’exception par bloc. Cependant, ce gestionnaire peut détecter plusieurs types d’exceptions en ayant plus d’une clause WHEN.

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

  • Un gestionnaire d’exceptions s’applique aux instructions situées entre les sections BEGIN et EXCEPTION du bloc dans lequel il est déclaré. Il ne s’applique pas à la section DECLARE du bloc.

  • Un gestionnaire d’exception ne peut traiter une exception spécifiée que si cette exception spécifiée se trouve dans le scope.

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

  • Pour utiliser une variable dans un gestionnaire d’exceptions, la variable doit être déclarée dans la section DECLARE ou passée en argument à une procédure stockée. Elle ne peut pas être déclarée dans la section BEGIN. .. END. Pour plus d’informations, voir Passing variables to an exception handler in Snowflake Scripting.

  • Lorsqu’une exception se produit, les conditions du gestionnaire sont vérifiées dans l’ordre et la première clause WHEN qui correspond est utilisée. L’ordre à l’intérieur d’un bloc est de haut en bas, et les blocs internes sont vérifiés avant les blocs externes. Il n’y a pas de préférence dans la correspondance des gestionnaires EXIT ou CONTINUE, le premier correspondant étant utilisé.

  • Un seul gestionnaire peut correspondre pour une instruction. Cependant, toute exception rencontrée à l’intérieur d’un corps de gestionnaire d’exceptions peut déclencher des gestionnaires d’exceptions de blocs externes.

  • Chaque clause WHEN d’un gestionnaire d’exceptions peut être l’un des types suivants :

    • EXIT - Le bloc exécute les instructions du gestionnaire, puis quitte le bloc actuel. Si le bloc exécute une exception de ce type et que le bloc contient des instructions après le gestionnaire d’exceptions, ces instructions ne sont pas exécutées.

      Si le bloc est un bloc interne et que le gestionnaire d’exceptions ne contient pas d’instruction RETURN, alors l’exécution quitte le bloc interne et continue avec le code du bloc externe.

      EXIT est défini par défaut.

    • CONTINUE - Le bloc exécute les instructions du gestionnaire et continue avec l’instruction qui suit immédiatement celle qui a causé l’erreur.

    Une clause EXCEPTION peut disposer de clauses WHEN des deux types — EXIT et CONTINUE.

    Pour une clause WHEN du type CONTINUE, les notes sur l’utilisation suivantes s’appliquent :

    • Si une erreur est détectée dans une construction branching, alors l’instruction suivante est l’instruction qui suit immédiatement la construction branching.

    • Si une erreur est détectée dans la condition d’une boucle, alors l’instruction suivante est l’instruction qui suit immédiatement la boucle.

    • Si une erreur est détectée dans le corps d’une boucle, alors l’instruction suivante est l’instruction de l’itération suivante de la boucle. Pour un exemple, voir Gérer une exception et continuer.

    • Si une erreur est détectée dans une instruction RETURN, alors l’instruction suivante est l’instruction qui suit immédiatement l’instruction RETURN.

    • Si une erreur est détectée dans une procédure stockée imbriquée et que l’erreur est traitée par la portée externe, alors l’instruction suivante est l’instruction qui suit immédiatement après l’appel de la procédure stockée.

    • Évitez d’inclure une instruction RETURN dans une clause WHEN de type CONTINUE. Si vous incluez une instruction RETURN, la procédure stockée renvoie sans continuer.

    Pour une clause WHEN``de type ``CONTINUE, les exemples suivants montrent quelle instruction est l’instruction qui suit immédiatement celle qui a causé l’erreur pour différents scénarios. Dans ces exemples, l’expression error_expression est l’expression qui a soulevé l’exception, et l’instruction continue_statement est l’instruction avec laquelle le code continue dans le bloc après les instructions CONTINUE du gestionnaire.

    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

Exemples

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

Traiter les exceptions de plusieurs types

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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

Gérer une exception et continuer

L’exemple suivant montre un gestionnaire d’exceptions avec une clause WHEN de type 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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

La sortie montre que le gestionnaire d’exceptions a décelé l’exception, exécuté une instruction qui a ajouté 1 au compteur, puis a exécuté l’instruction suivante après la capture de l’exception, qui a ajouté 10 au compteur :

+-------------------+
| anonymous block   |
|-------------------|
| Counter value: 11 |
+-------------------+

L’exemple suivant montre comment un gestionnaire d’exceptions avec une clause WHEN de type CONTINUE fonctionne lorsqu’une erreur est détectée dans une boucle. L’exemple signale une erreur lors de la première itération, car il essaie de diviser la valeur 10 par zéro. Le gestionnaire CONTINUE enregistre l’erreur dans la error_log_table, et le bloc continue avec l’itération suivante de la boucle, qui divise 10 par 1. La boucle continue d’itérer jusqu’à ce que 10 soit divisé par 5 et la boucle se termine. La sortie est 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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

Traiter les exceptions dans les blocs imbriqués

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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

Note

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

L’exemple fait cela pour illustrer le scope des noms d’exception. Les deux exceptions portant le nom e1 sont des exceptions différentes.

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

Gérer plusieurs exceptions dans la même clause et les mêmes exceptions non spécifiées

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

Gérer les exceptions à l’aide de variables intégrées

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

Remarque : Si vous utilisez Snowflake CLI, SnowSQL, Classic Console, ou la méthode execute_stream ou execute_string dans le code Connecteur Python, utilisez cet exemple à la place (voir Utilisation de Snowflake Scripting dans Snowflake CLI, SnowSQL, le Classic Console et le connecteur Python) :

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

L’exécution de cet exemple produit le résultat suivant :

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