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¶
Exécution de scripts Snowflake lève une exception si une erreur survient lors de l’exécution d’une instruction. Par exemple, si une instruction tente de supprimer une table qui n’existe pas, Exécution de scripts Snowflake lève une exception.
Dans un bloc Exécution de scripts Snowflake, vous pouvez écrire des gestionnaires d’exceptions qui détectent des types spécifiques d’exceptions déclarées dans ce bloc et dans les blocs imbriqués dans ce bloc. En outre, pour les erreurs qui peuvent se produire dans votre code, vous pouvez définir vos propres exceptions que vous pouvez soulever lorsque des erreurs se produisent.
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 Traitement d’une exception dans Exécution de scripts Snowflake.
Lorsqu’une exception est soulevée dans un bloc Exécution de scripts Snowflake, soit par votre code, soit par une instruction qui ne s’exécute pas, Snowflake Scripting tente de trouver un gestionnaire pour cette 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.
Si le bloc ne possède pas son propre gestionnaire d’exceptions, l’exception peut être récupérée par le bloc qui le délimite.
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.
Déclaration d’une exception dans Exécution de scripts Snowflake¶
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.');
Levée d’une exception déclarée dans Exécution de scripts Snowflake¶
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;
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;
$$
;
S’il n’y a pas de gestionnaire, l’exécution s’arrête au moment où l’exception est levée. Dans l’exemple, counter n’est jamais incrémenté et n’est pas renvoyé.
Le client qui soumet ce bloc à exécution — par exemple, l’Snowsight — signale une erreur et indique que l’exception n’a pas été détectée :
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
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 Traitement d’une exception dans Exécution de scripts Snowflake.
Note
Dans un gestionnaire d’exception, si vous devez soulever à nouveau la même exception, consultez Levée de la même exception à nouveau dans un gestionnaire d’exceptions dans Exécution de scripts Snowflake.
Traitement d’une exception dans Exécution de scripts Snowflake¶
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_numberindiqué 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_messageindiqué 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.
Pour traiter toutes les autres exceptions qui ne sont pas intégrées ou déclarées, utilisez une clause WHEN OTHER THEN. La clause WHEN OTHER THEN peut être de type EXIT ou 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);
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;
Pour un exemple qui traite d’autres erreurs, supprimez les commentaires de cette ligne :
-- LET var := 1/0;
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;
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;
$$
;
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;
+--------------+------------+----------------------+-------------+-------------------------+
| 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;
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;
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;
$$
;
+---------------------+
| 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;
Pour plus d’informations sur les gestionnaires CONTINUE, voir EXCEPTION (Exécution de scripts Snowflake).
Dans de rares cas, vous pourriez vouloir gérer explicitement une exception en ne faisant rien. Cela vous permet de continuer, plutôt que d’arrêter, lorsque l’exception se produit. Pour plus d’informations, voir la commande NULL.
Note
Si vous devez à nouveau soulever la même exception, consultez Levée de la même exception à nouveau dans un gestionnaire d’exceptions dans Exécution de scripts Snowflake.
Si vous ne configurez pas de gestionnaire d’exception, le client soumet le bloc à exécution ; par exemple, Snowsight signale une erreur comme expliqué dans Levée d’une exception déclarée dans Exécution de scripts Snowflake.
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Levée de la même exception à nouveau dans un gestionnaire d’exceptions dans Exécution de scripts Snowflake¶
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;
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;
$$;
Transmission de variables à un gestionnaire d’exceptions dans Exécution de scripts Snowflake¶
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;
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;
$$
;
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;
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;
$$
;
Les appels suivants à la procédure stockée affichent le résultat attendu :
CALL exception_test_vars(7);
+------------------------------+
| EXCEPTION_TEST_VARS |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+