处理异常¶
在 Snowflake Scripting 块中,如果发生错误,可以引发异常。您还可以处理 Snowflake Scripting 代码中发生的异常。
简介¶
如果在执行语句时发生错误(例如,如果语句尝试对不存在的表进行 DROP 操作),则 Snowflake Scripting 会引发异常。异常会阻止下一行代码的执行。
在 Snowflake Scripting 块中,您可以编写异常处理程序,捕获该块和嵌套在该块中的块中已声明的特定类型的异常。
此外,对于代码中可能发生的错误,您可以定义自己的异常,以便在发生错误时引发这些异常。
当 Snowflake Scripting 块中引发异常时(由代码或无法执行的语句引发),Snowflake Scripting 会尝试查找该异常的处理程序:
如果发生异常的块具有该异常的处理程序,则在该异常处理程序的开头恢复执行。
如果该块没有自己的异常处理程序,则封闭块可以捕获该异常。
如果异常发生的深度超过一层,则系统每次将异常向上发送一层,直到出现以下任一情况:
具有适当异常处理程序的层可以处理该异常。
到达最外层,在这种情况下会发生错误。
如果当前块或任何封闭块中没有异常处理程序,则块的执行将停止,提交块以供执行的客户端(例如 Web 界面、SnowSQL 等)会将其报告为 Snowflake 错误。
异常处理程序可以包含自己的异常处理程序,以防在处理其他异常时发生异常。
声明异常¶
您可以在块的 DECLARE 部分中声明自己的异常。请使用 异常声明语法 中描述的语法。例如:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
引发已声明的异常¶
要引发异常,请执行 RAISE 命令。例如:
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;
注意:如果您在 Python Connector 代码中使用 SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
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;
$$
;
引发异常后,执行随即停止。(在本例中,counter
从不递增和返回。)
提交此块以供执行的客户端(例如 Snowsight)将报告错误,并指示未捕获异常:
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
如果要添加代码来处理引发的任何异常(以及语句无法执行时引发的异常),可以编写异常处理程序。请参阅 处理异常。
备注
在异常处理程序中,如果需要再次引发相同的异常,请参阅 在异常处理程序中再次引发相同的异常。
处理异常¶
您可以使用 EXCEPTION 子句捕获异常来显式处理异常,也可以允许块将异常传递给封闭块。
在 EXCEPTION 子句中,请使用 WHEN 子句按名称处理异常。您可以处理您声明的异常以及内置异常。目前,Snowflake 提供以下内置异常:
STATEMENT_ERROR:此异常表示执行语句时出错。例如,如果尝试弃用不存在的表,则会引发此异常。
EXPRESSION_ERROR:此异常表示与表达式相关的错误。例如,如果创建了一个计算结果为 VARCHAR 的表达式,并尝试将该表达式的值赋给 FLOAT,则会引发此错误。
发生异常时,可以通过读取以下三个内置变量,获取有关异常的信息:
SQLCODE:这是一个 5 位的带符号整数。对于用户定义的异常,这是 用于声明异常的语法 中显示的
exception_number
。SQLERRM:这是一条错误消息。对于用户定义的异常,这是 用于声明异常的语法 中显示的
exception_message
。SQLSTATE:这是一个基于 ANSI SQL 标准 SQLSTATE (link removed) 的 5 字符代码。除 ANSI SQL 标准中的值外,Snowflake 还使用了其他值。
若要处理不含 WHEN 子句的所有其他异常,请使用 WHEN OTHER THEN 子句。
例如:
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;
注意:如果您在 Python Connector 代码中使用 SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
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;
$$
;
此示例通过调用 OBJECT_CONSTRUCT 构造并返回一个包含异常详细信息的对象,从而处理每种类型的异常。此示例生成以下输出:
+--------------------------------------+
| anonymous block |
|--------------------------------------|
| { |
| "Error type": "MY_EXCEPTION", |
| "SQLCODE": -20002, |
| "SQLERRM": "Raised MY_EXCEPTION.", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------------+
在极少数情况下,您可能希望不执行任何操作来显式处理异常。这使您可以在发生异常时继续,而不是中止。有关更多信息,请参阅 NULL 命令。
如果没有为异常设置处理程序,则提交块以供执行的客户端(例如 Web 界面)将报告错误(如 引发已声明的异常 中所述)。
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
备注
如果需要再次引发相同的异常,请参阅 在异常处理程序中再次引发相同的异常。
在异常处理程序中再次引发相同的异常¶
在某些情况下,您可能需要引发在异常处理程序中捕获的相同异常。在这些情况下,请执行 RAISE 命令,且不指定任何实参。
例如,假设在异常处理期间,您需要先获取有关异常的一些详细信息,然后再引发相同的异常。获取详细信息后,请执行 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;
注意:如果您在 Python Connector 代码中使用 SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
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;
$$;