错误和诊断

ASSERT

ASSERT 是一个调试功能,它可以检查某个条件是否为 true。如果条件为 false,则 ASSERT 引发 ASSERT_FAILURE 异常,并显示可选错误消息。

要转义 '(单引号)字符,请使用 ''。同样,要转义 "(双引号)字符,请使用 ""

ASSERT condition [ , message ];

例如,此过程检查 products 表中的行数,并使用 ASSERT 检查是否填充了该表。如果该表为空,则 Vertica 引发错误:


=> CREATE TABLE products(id UUID, name VARCHARE, price MONEY);
CREATE TABLE

=> SELECT * FROM products;
 id | name | price
----+------+-------
(0 rows)

DO $$
DECLARE
    prod_count INT;
BEGIN
    prod_count := SELECT count(*) FROM products;
    ASSERT prod_count > 0, 'products table is empty';
END;
$$;

ERROR 2005:  products table is empty

要让 Vertica 停止检查 ASSERT 语句,您可以设置布尔会话级别参数PLpgSQLCheckAsserts

RAISE

RAISE 可以引发错误或输出用户指定的下列错误消息之一:

RAISE [ level ] 'format' [, arg_expression [, ... ]] [ USING option = expression [, ... ] ];
RAISE [ level ] condition_name [ USING option = expression [, ... ] ];
RAISE [ level ] SQLSTATE 'sql-state' [ USING option = expression [, ... ] ];
RAISE [ level ] USING option = expression [, ... ];

此过程演示各种 RAISE 级别:

=> DO $$
DECLARE
    logfile varchar := 'vertica.log';
BEGIN
    RAISE LOG 'this message was sent to %', logfile;
    RAISE INFO 'info';
    RAISE NOTICE 'notice';
    RAISE WARNING 'warning';
    RAISE EXCEPTION 'exception';

    RAISE NOTICE 'exception changes control flow; this is not printed';
END;
$$;

INFO 2005:  info
NOTICE 2005:  notice
WARNING 2005:  warning
ERROR 2005:  exception

$ grep 'this message was sent to vertica.log' v_vmart_node0001_catalog/vertica.log
<LOG> @v_vmart_node0001: V0002/2005: this message is sent to vertica.log

异常

EXCEPTION 块使您可以捕获和处理从 statements 引发的异常

[ <<label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
EXCEPTION
    WHEN exception_condition [ OR exception_condition ... ] THEN
        handler_statements
    [ WHEN exception_condition [ OR exception_condition ... ] THEN
        handler_statements
      ... ]
END [ label ];

exception_condition 具有下列格式之一:

WHEN errcode_division_by_zero THEN ...
WHEN division_by_zero THEN ...
WHEN SQLSTATE '22012' THEN ...
WHEN OTHERS THEN ...

OTHERS 是特殊条件,它捕获除 QUERY_CANCELLEDASSERT_FAILUREFEATURE_NOT_SUPPORTED 之外的所有异常。

当引发异常时,Vertica 检查异常列表,从上到下查找匹配的 exception_condition。如果找到匹配,它将执行 handler_statements,然后离开异常块范围。

如果 Vertica 找不到匹配,则会将异常传播到下一个封闭块。您可以使用 RAISE 在异常处理程序中手动执行此操作:

RAISE;

例如,以下过程在 inner_block 中用 3 除以 0,这是一个非法操作,将引发 division_by_zero 异常(SQL 状态 22012)。Vertica 检查内部 EXCEPTION 块以查找匹配的条件:

  1. 第一个条件检查 SQL 状态 42501,因此 Vertica 移动到下一个条件。

  2. WHEN OTHERS THEN 捕获所有异常,因此它执行该块。

  3. 随后,基本 RAISE 将异常传播到 outer_block

  4. 外部 EXCEPTION 块成功捕获异常并输出消息。

=> DO $$
<<outer_block>>
BEGIN
    <<inner_block>>
    DECLARE
        x int;
    BEGIN
        x := 3 / 0; -- throws exception division_by_zero, SQLSTATE 22012
    EXCEPTION -- this block is checked first for matching exceptions
        WHEN SQLSTATE '42501' THEN
            RAISE NOTICE 'caught insufficient_privilege exception';
        WHEN OTHERS THEN -- catches all exceptions
            RAISE; -- manually propagate the exception to the next enclosing block
    END inner_block;
EXCEPTION -- exception is propagated to this block
    WHEN division_by_zero THEN
        RAISE NOTICE 'caught division_by_zero exception';
END outer_block;
$$;

NOTICE 2005:  caught division_by_zero exception

SQLSTATE 和 SQLERRM 变量

当处理异常时,您可以使用以下变量检索错误信息:

  • SQLSTATE 包含 SQL 状态

  • SQLERRM 包含错误消息

有关详细信息,请参阅SQL 状态列表

此过程通过尝试将 NULL 赋值给 NOT NULL 变量捕获引发的异常,并输出 SQL 状态和错误消息:

DO $$
DECLARE
    i int NOT NULL := 1;
BEGIN
    i := NULL; -- illegal, i was declared with NOT NULL
EXCEPTION
    WHEN OTHERS THEN
        RAISE WARNING 'SQL State: %', SQLSTATE;
        RAISE WARNING 'Error message: %', SQLERRM;
END;
$$;

WARNING 2005:  SQLSTATE: 42809
WARNING 2005:  SQLERRM: Cannot assign null into NOT NULL variable

检索异常信息

您可以使用 GET STACKED DIAGNOSTICS 在异常处理程序中检索有关异常的信息:

GET STACKED DIAGNOSTICS variable_name { = | := } item [, ... ];

其中 item 可以是以下任意一项:

例如,此过程有一个 EXCEPTION 块,它捕捉 division_by_zero 错误并输出 SQL 状态、错误消息和异常上下文:

=> DO $$
DECLARE
    message_1 varchar;
    message_2 varchar;
    message_3 varchar;
    x int;
BEGIN
    x := 5 / 0;
EXCEPTION
    WHEN OTHERS THEN -- OTHERS catches all exceptions
    GET STACKED DIAGNOSTICS message_1 = RETURNED_SQLSTATE,
                            message_2 = MESSAGE_TEXT,
                            message_3 = EXCEPTION_CONTEXT;

    RAISE INFO 'SQLSTATE: %', message_1;
    RAISE INFO 'MESSAGE: %', message_2;
    RAISE INFO 'EXCEPTION_CONTEXT: %', message_3;
END;
$$;

INFO 2005:  SQLSTATE: 22012
INFO 2005:  MESSAGE: Division by zero
INFO 2005:  EXCEPTION_CONTEXT: PL/vSQL procedure inline_code_block line 8 at static SQL