Traitement des exceptions

Dans un bloc Exécution de scripts Snowflake, vous pouvez soulever une exception si une erreur se produit. Vous pouvez également gérer les exceptions qui se produisent dans votre code Exécution de scripts Snowflake.

Introduction à la gestion des exceptions dans Exécution de scripts Snowflake

Snowflake Scripting raises an exception if an error occurs while executing a statement. For example, if a statement attempts to drop a table that doesn’t exist, Snowflake Scripting raises an exception.

In a Snowflake Scripting block, you can write exception handlers that catch specific types of exceptions declared in that block and in blocks nested inside that block. In addition, for errors that can occur in your code, you can define your own exceptions that you can raise when errors occur.

Une fois les instructions du gestionnaire exécutées, vous pouvez choisir de quitter le bloc ou de continuer à exécuter les instructions du bloc. Pour plus d’informations, voir Handling an exception in Snowflake Scripting.

When an exception is raised in a Snowflake Scripting block, either by your code or by a statement that fails to execute, Snowflake Scripting attempts to find a handler for that exception:

  • Si le bloc dans lequel l’exception s’est produite possède un gestionnaire pour cette exception, l’exécution reprend au début de ce gestionnaire d’exceptions.

  • If the block doesn’t have its own exception handler, then the exception can be caught by the enclosing block.

    Si l’exception se produit à plus d’une couche de profondeur, alors l’exception est envoyée vers le haut, une couche à la fois, jusqu’à ce que l’une des deux conditions suivantes soit remplie :

    • Une couche avec un gestionnaire d’exceptions approprié gère l’exception.

    • La couche la plus externe est atteinte, auquel cas une erreur se produit.

  • S’il n’y a pas de gestionnaire d’exception dans le bloc en cours ou dans les blocs environnants, l’exécution du bloc s’arrête et le client qui soumet le bloc à l’exécution (par exemple, Snowsight, SnowSQL, etc.) signale l’erreur comme étant une erreur Snowflake.

Un gestionnaire d’exception peut contenir son propre gestionnaire d’exception au cas où une exception se produirait pendant le traitement d’une autre exception.

Declaring an exception in Snowflake Scripting

Vous pouvez déclarer votre propre exception dans la section DECLARE du bloc. Utilisez la syntaxe décrite dans Syntaxe de déclaration des exceptions. Par exemple :

DECLARE
  my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Copy

Raising a declared exception in Snowflake Scripting

Pour soulever une exception, exécutez la commande RAISE. Par exemple :

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

If there is no handler, execution stops at the point when the exception is raised. In the example, counter is never incremented and isn’t returned.

The client that submits this block for execution — for example, Snowsight — reports an error and indicates that the exception was not caught:

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

Si vous souhaitez ajouter du code pour gérer les exceptions que vous soulevez (ainsi que les exceptions soulevées lorsque les instructions ne s’exécutent pas), vous pouvez écrire des gestionnaires d’exceptions. Voir Handling an exception in Snowflake Scripting.

Note

Dans un gestionnaire d’exception, si vous devez soulever à nouveau la même exception, consultez Raising the same exception again in an exception handler in Snowflake Scripting.

Handling an exception in Snowflake Scripting

Vous pouvez traiter explicitement une exception en la détectant par une clause EXCEPTION ou vous pouvez permettre au bloc de transmettre l’exception au bloc englobant.

Dans la clause EXCEPTION, utilisez une clause WHEN pour traiter une exception par son nom. Vous pouvez traiter les exceptions que vous déclarez ainsi que les exceptions intégrées. Actuellement, Snowflake fournit les exceptions intégrées suivantes :

  • STATEMENT_ERROR : cette exception indique une erreur lors de l’exécution d’une instruction. Par exemple, si vous tentez de supprimer une table qui n’existe pas, cette exception est levée.

  • EXPRESSION_ERROR : cette exception indique une erreur liée à une expression. Par exemple, si vous créez une expression qui donne une valeur VARCHAR et que vous tentez d’affecter la valeur de l’expression à un FLOAT, cette erreur est signalée.

Chaque clause WHEN d’un bloc d’exception 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 l’instruction qui a causé l’erreur, 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 bloc d’exception et continue avec l’instruction suivant immédiatement celle qui a causé l’erreur.

    Un gestionnaire CONTINUE peut détecter et traiter les exceptions sans terminer le bloc d’instructions qui a soulevé l’exception. Avec le gestionnaire EXIT par défaut, lorsqu’une erreur se produit dans un bloc, le flux est interrompu et l’erreur est renvoyée à l” appelant. Cependant, vous pouvez utiliser un gestionnaire CONTINUE lorsque la condition d’erreur n’est pas suffisamment grave pour garantir l’interruption du flux.

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

Lorsqu’une exception se produit, vous pouvez obtenir des informations sur cette exception en lisant les trois variables intégrées suivantes :

  • SQLCODE : il s’agit d’un nombre entier signé de 5 chiffres. Pour les exceptions définies par l’utilisateur, il s’agit du exception_number indiqué dans la syntaxe de déclaration d’une exception.

  • SQLERRM : il s’agit d’un message d’erreur. Pour les exceptions définies par l’utilisateur, il s’agit du exception_message indiqué dans la syntaxe de déclaration d’une exception.

  • SQLSTATE : il s’agit d’un code à 5 caractères calqué sur la norme ANSI SQL SQLSTATE. Snowflake utilise des valeurs supplémentaires en plus de celles de la norme ANSI SQL.

Lorsque vous utilisez une clause WHEN de type CONTINUE, ces variables intégrées reflètent l’erreur qui a causé l’exception dans la clause WHEN. Une fois les instructions de la clause WHEN terminées et que l’exécution de l’instruction se poursuit dans le bloc, les valeurs de ces variables renvoient les valeurs qu’elles avaient avant que l’exception ne soit levée.

To handle all other exceptions that aren’t built-in or declared, use a WHEN OTHER THEN clause. The WHEN OTHER THEN clause can be of type EXIT or CONTINUE.

Supposons que vous disposiez de la table de journal des erreurs suivante pour suivre vos exceptions :

CREATE OR REPLACE TABLE test_error_log(
  error_type VARCHAR,
  error_code VARCHAR,
  error_message VARCHAR,
  error_state VARCHAR,
  error_timestamp TIMESTAMP);
Copy

Le bloc anonyme suivant insère des informations sur les exceptions dans la table et renvoie des informations sur celles-ci à l’utilisateur :

Astuce

L’exemple définit une exception dans la section DECLARE et traite ensuite cette exception. Pour un exemple qui traite une exception STATEMENT_ERROR, supprimez les commentaires (--) de cette ligne :

-- SELECT 1/0;
Copy

Pour un exemple qui traite d’autres erreurs, supprimez les commentaires de cette ligne :

-- LET var := 1/0;
Copy
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;
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 (-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;
$$
;
Copy

Pour la valeur renvoyée, cet exemple traite chaque type d’exception en appelant OBJECT_CONSTRUCT pour construire et renvoyer un objet contenant les détails de l’exception. L’exemple produit le résultat suivant :

+--------------------------------------+
| anonymous block                      |
|--------------------------------------|
| {                                    |
|   "Error type": "MY_EXCEPTION",      |
|   "SQLCODE": -20002,                 |
|   "SQLERRM": "Raised MY_EXCEPTION.", |
|   "SQLSTATE": "P0001"                |
| }                                    |
+--------------------------------------+

Vous pouvez interroger la table test_error_log pour confirmer que l’erreur a été enregistrée :

SELECT * FROM test_error_log;
Copy
+--------------+------------+----------------------+-------------+-------------------------+
| ERROR_TYPE   | ERROR_CODE | ERROR_MESSAGE        | ERROR_STATE | ERROR_TIMESTAMP         |
|--------------+------------+----------------------+-------------+-------------------------|
| MY_EXCEPTION | -20002     | Raised MY_EXCEPTION. | P0001       | 2025-09-05 12:15:00.068 |
+--------------+------------+----------------------+-------------+-------------------------+

L’exemple précédent utilisait les clauses WHEN du type par défaut (EXIT). Si l’une des clauses WHEN détecte une exception, elle exécute les instructions de la clause WHEN, puis se termine. Par conséquent, le code suivant n’est pas exécuté :

counter := counter + 1;
RETURN 'My counter value: ' || counter;
Copy

Si vous souhaitez gérer une exception, puis continuer à exécuter le code dans le bloc, spécifiez les clauses WHEN de type CONTINUE. L’exemple suivant est le même que l’exemple précédent, mais il spécifie les clauses WHEN de type CONTINUE et supprime l’instruction RETURN de chaque clause 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;
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 (-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;
$$
;
Copy
+---------------------+
| anonymous block     |
|---------------------|
| My counter value: 1 |
+---------------------+

La sortie montre que l’exemple a continué à exécuter le code suivant après que l’exception a été levée :

counter := counter + 1;
RETURN counter;
Copy

For more information about CONTINUE handlers, see EXCEPTION (Exécution de scripts Snowflake).

In rare cases, you might want to explicitly handle an exception by doing nothing. This enables you to continue, rather than terminate, when the exception occurs. For more information, see the NULL command.

Note

Si vous devez à nouveau soulever la même exception, consultez Raising the same exception again in an exception handler in Snowflake Scripting.

If you don’t set up a handler for an exception, the client that submits the block for execution; for example, Snowsight reports an error as explained in Raising a declared exception in Snowflake Scripting.

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

Raising the same exception again in an exception handler in Snowflake Scripting

Dans certains cas, vous pouvez avoir besoin de soulever la même exception que celle que vous avez détectée dans votre gestionnaire d’exception. Dans ces cas, exécutez la commande RAISE sans spécifier d’arguments.

Par exemple, supposons qu’au cours du traitement d’une exception, vous deviez capturer certains détails sur l’exception avant de soulever à nouveau la même exception. Après avoir capturé les détails, exécutez la commande 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;
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 $$
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;
$$;
Copy

Passing variables to an exception handler in Snowflake Scripting

Vous pouvez transmettre des variables à un gestionnaire d’exceptions. Le gestionnaire d’exceptions peut exécuter du code en fonction de la valeur de la variable, et la valeur de la variable peut être renvoyée dans des messages d’erreur.

Pour qu’une variable soit transmise à un gestionnaire dans la section EXCEPTION, la variable doit être déclarée dans la section DECLARE. Si une variable est déclarée dans la section BEGIN … END du bloc, elle n’est pas accessible dans la section EXCEPTION.

De plus, si vous écrivez une procédure stockée Snowflake Scripting qui accepte des arguments, vous pouvez utiliser ces arguments dans un gestionnaire d’exceptions.

Par exemple, le bloc anonyme suivant transmet la valeur de la variable counter_val au gestionnaire d’exceptions :

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

Le bloc renvoie le message d’erreur suivant :

+---------------------------------------------------------+
| anonymous block                                         |
|---------------------------------------------------------|
| Error -20002: Counter value 11 exceeds the limit of 10. |
+---------------------------------------------------------+

Voici un exemple de procédure stockée Snowflake Scripting qui transmet un argument. L’exemple montre comment vous pouvez utiliser l’argument dans un gestionnaire d’exceptions :

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

Les appels suivants à la procédure stockée affichent le résultat attendu :

CALL exception_test_vars(7);
Copy
+------------------------------+
| EXCEPTION_TEST_VARS          |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
Copy
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS                                                   |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
Copy
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS                                                  |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+