Behandeln von Ausnahmen¶
In einem Snowflake Scripting-Block können Sie bei Auftreten eines Fehlers eine Ausnahme auslösen. Sie können auch Ausnahmen behandeln, die in Ihrem Snowflake Scripting-Code auftreten.
Einführung¶
Snowflake Scripting löst eine Ausnahme aus, wenn bei der Ausführung einer Anweisung ein Fehler auftritt (z. B. wenn eine Anweisung versucht, eine Tabelle mit DROP zu löschen, die nicht existiert). Eine Ausnahme verhindert, dass die nächsten Codezeilen ausgeführt werden können.
In einem Snowflake Scripting-Block können Sie Programme zur Ausnahmebehandlung (sog. Ausnahme-Handler) schreiben, die bestimmte Arten von Ausnahmen abfangen, die in diesem Block und in Blöcken, die in diesem Block verschachtelt sind, deklariert sind.
Darüber hinaus können Sie für Fehler, die in Ihrem Code auftreten, eigene Ausnahmen definieren, die Sie beim Auftreten von Fehlern auslösen können.
Wenn in einem Snowflake Scripting-Block eine Ausnahme ausgelöst wird (entweder durch Ihren Code oder durch eine Anweisung, die nicht ausgeführt werden kann), versucht Snowflake Scripting, einen Handler für diese Ausnahme zu finden:
Wenn der Block, in dem die Ausnahme aufgetreten ist, einen Handler für diese Ausnahme hat, wird die Ausführung am Anfang dieses Handlers fortgesetzt.
Wenn der Block keinen eigenen Ausnahme-Handler hat, kann die Ausnahme durch den umschließenden Block abgefangen werden.
Tritt die Ausnahme mehr als eine Ebene tiefer auf, wird die Ausnahme ebenenweise nach oben gesendet, bis entweder:
Eine Ebene mit einem geeigneten Ausnahme-Handler die Ausnahme behandelt.
Die äußerste Ebene erreicht ist, in der ein Fehler auftritt.
Gibt es im aktuellen Block oder in umschließenden Blöcken keinen Handler für die Ausnahme, wird die Ausführung des Blocks angehalten, und der Client, der den Block zur Ausführung vorlegt (z. B. die Weboberfläche, SnowSQL usw.), meldet dies als Snowflake-Fehler.
Ein Ausnahme-Handler kann seinen eigenen Ausnahme-Handler enthalten, falls eine Ausnahme während der Behandlung einer anderen Ausnahme auftritt.
Deklarieren einer Ausnahme¶
Sie können Ihre eigene Ausnahme im DECLARE-Abschnitt des Blocks deklarieren. Verwenden Sie die unter Syntax der Ausnahmedeklaration beschriebene Syntax. Beispiel:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Auslösen einer deklarierten Ausnahme¶
Um eine Ausnahme auszulösen, führen Sie den Befehl RAISE aus. Beispiel:
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;
Hinweis: Wenn Sie SnowSQL, die Classic Console oder die execute_stream
- oder execute_string
-Methode im Python-Konnektor-Code verwenden, benutzen Sie stattdessen das folgende Beispiel (siehe Verwenden von Snowflake Scripting in SnowSQL, in der Classic Console und im Python-Konnektor):
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;
$$
;
Die Ausführung wird an dem Punkt angehalten, an dem die Ausnahme ausgelöst wird. (Im Beispiel wird counter
nie inkrementiert und zurückgegeben.)
Der Client, der diesen Block zur Ausführung vorlegt (z. B. Snowsight), meldet einen Fehler und gibt an, dass die Ausnahme nicht abgefangen wurde:
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Wenn Sie Code hinzufügen möchten, um von Ihnen ausgelöste Ausnahmen zu behandeln (sowie Ausnahmen, die ausgelöst werden, wenn Anweisungen nicht ausgeführt werden können), können Sie Ausnahme-Handler schreiben. Siehe Behandeln einer Ausnahme.
Bemerkung
Für den Fall, dass Sie in einen Ausnahme-Handler die gleiche Ausnahme erneut auslösen müssen, finden Sie entsprechende Informationen unter Erneutes Auslösen derselben Ausnahme in einem Ausnahme-Handler.
Behandeln einer Ausnahme¶
Sie können eine Ausnahme explizit behandeln, indem Sie sie mit einer EXCEPTION-Klausel abfangen, oder Sie können zulassen, dass der Block die Ausnahme an den umschließenden Block übergibt.
Verwenden Sie innerhalb der EXCEPTION-Klausel eine WHEN-Klausel, um eine Ausnahme nach Namen zu behandeln. Sie können sowohl von Ihnen deklarierte Ausnahmen als auch integrierte Ausnahmen verarbeiten. Derzeit bietet Snowflake die folgenden integrierten Ausnahmen:
STATEMENT_ERROR: Diese Ausnahme weist auf einen Fehler bei der Ausführung einer Anweisung hin. Wenn Sie zum Beispiel versuchen, eine Tabelle zu löschen, die nicht existiert, wird diese Ausnahme ausgelöst.
EXPRESSION_ERROR: Diese Ausnahme zeigt einen Fehler im Zusammenhang mit einem Ausdruck an. Wenn Sie z. B. einen Ausdruck erstellen, der als VARCHAR ausgewertet wird, und versuchen, den Wert des Ausdrucks einem FLOAT zuzuweisen, wird dieser Fehler ausgelöst.
Wenn eine Ausnahme auftritt, können Sie Informationen über die Ausnahme erhalten, indem Sie die folgenden drei integrierten Variablen auslesen:
SQLCODE: Dies ist eine 5-stellige, vorzeichenbehaftete Ganzzahl. Bei benutzerdefinierten Ausnahmen ist dies die
exception_number
(Ausnahmenummer), die in der Syntax zum Deklarieren von Ausnahmen angegeben ist.SQLERRM: Dies ist eine Fehlermeldung. Bei benutzerdefinierten Ausnahmen ist dies die
exception_message
(Ausnahmenummer), die in der Syntax zum Deklarieren von Ausnahmen angegeben ist.SQLSTATE: Dies ist ein 5-Zeichen-Code, der auf dem ANSI-SQL-Standard SQLSTATE basiert. Snowflake verwendet zusätzliche Werte, die über die Werte des ANSI-SQL-Standards hinausgehen.
Zur Behandlung aller anderen Ausnahmen, die keine WHEN-Klausel enthalten, verwenden Sie eine WHEN OTHER THEN-Klausel.
Beispiel:
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;
EXCEPTION
WHEN statement_error THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
Hinweis: Wenn Sie SnowSQL, die Classic Console oder die execute_stream
- oder execute_string
-Methode im Python-Konnektor-Code verwenden, benutzen Sie stattdessen das folgende Beispiel (siehe Verwenden von Snowflake Scripting in SnowSQL, in der Classic Console und im Python-Konnektor):
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;
EXCEPTION
WHEN statement_error THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
$$
;
Dieses Beispiel behandelt jede Art von Ausnahme, indem es OBJECT_CONSTRUCT aufruft, um ein Objekt zu erstellen und zurückzugeben, das die Details über die Ausnahme enthält. Das Beispiel ergibt die folgende Ausgabe:
+--------------------------------------+
| anonymous block |
|--------------------------------------|
| { |
| "Error type": "MY_EXCEPTION", |
| "SQLCODE": -20002, |
| "SQLERRM": "Raised MY_EXCEPTION.", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------------+
In seltenen Fällen kann die Behandlung einer Ausnahme explizit darin bestehen, nichts zu tut. Auf diese Weise können Sie bei Auftreten einer Ausnahme fortfahren, anstatt abzubrechen. Weitere Informationen dazu finden Sie unter dem Befehl NULL.
Wenn Sie keinen Handler für eine Ausnahme einrichten, meldet der Client, der den Block zur Ausführung vorlegt (z. B. die Weboberfläche), einen Fehler (wie unter Auslösen einer deklarierten Ausnahme erläutert).
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Bemerkung
Für den Fall, dass Sie denselben Ausnahme-Handler noch einmal auslösen müssen, finden Sie entsprechende Informationen unter Erneutes Auslösen derselben Ausnahme in einem Ausnahme-Handler.
Erneutes Auslösen derselben Ausnahme in einem Ausnahme-Handler¶
In manchen Fällen müssen Sie die gleiche Ausnahme auslösen, die Sie in Ihrem Ausnahme-Handler abgefangen haben. In diesen Fällen führen Sie den Befehl RAISE ohne Angabe von Argumenten aus.
Angenommen, dass Sie während der Ausnahmebehandlung einige Details über die Ausnahme erfassen müssen, bevor Sie die gleiche Ausnahme erneut auslösen. Nach der Erfassung der Details führen Sie den Befehl RAISE aus:
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;
Hinweis: Wenn Sie SnowSQL, die Classic Console oder die execute_stream
- oder execute_string
-Methode im Python-Konnektor-Code verwenden, benutzen Sie stattdessen das folgende Beispiel (siehe Verwenden von Snowflake Scripting in SnowSQL, in der Classic Console und im Python-Konnektor):
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;
$$;
Übergabe von Variablen an einen Ausnahme-Handler¶
Sie können Variablen an einen Ausnahme-Handler übergeben. Der Ausnahme-Handle kann Code auf der Grundlage des Wertes der Variable ausführen, und der Wert der Variable kann in Fehlermeldungen zurückgegeben werden.
Damit eine Variable an einen Handler im EXCEPTION-Abschnitt übergeben werden kann, muss die Variable im DECLARE-Abschnitt deklariert werden. Wenn eine Variable im BEGIN … END-Abschnitt des Blocks deklariert wird, kann im EXCEPTION-Abschnitt nicht auf sie zugegriffen werden.
Wenn Sie eine Snowflake Scripting gespeicherte Prozedur schreiben, die Argumente akzeptiert, können Sie diese Argumente auch in einem Ausnahme-Handler verwenden.
Der folgende anonyme Block übergibt zum Beispiel den Wert der counter_val
-Variable an den Handler der Ausnahme:
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;
Hinweis: Wenn Sie SnowSQL, die Classic Console oder die execute_stream
- oder execute_string
-Methode im Python-Konnektor-Code verwenden, benutzen Sie stattdessen das folgende Beispiel (siehe Verwenden von Snowflake Scripting in SnowSQL, in der Classic Console und im Python-Konnektor):
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;
$$
;
Der Block gibt die folgende Fehlermeldung zurück:
+---------------------------------------------------------+
| anonymous block |
|---------------------------------------------------------|
| Error -20002: Counter value 11 exceeds the limit of 10. |
+---------------------------------------------------------+
Im Folgenden finden Sie ein Beispiel für eine Snowflake Scripting gespeicherte Prozedur, die ein Argument übergibt. Das Beispiel zeigt, wie Sie das Argument in einem Ausnahme-Handler verwenden können:
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;
Hinweis: Wenn Sie SnowSQL, die Classic Console oder die execute_stream
- oder execute_string
-Methode im Python-Konnektor-Code verwenden, benutzen Sie stattdessen das folgende Beispiel (siehe Verwenden von Snowflake Scripting in SnowSQL, in der Classic Console und im Python-Konnektor):
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;
$$
;
Die folgenden Aufrufe der gespeicherten Prozedur zeigen die erwartete Ausgabe:
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). |
+----------------------------------------------------------------------+