处理PostgreSQL异常的优雅方式?

时间:2015-02-10 16:37:31

标签: sql postgresql exception-handling plpgsql dynamic-sql

在PostgreSQL中,我想创建一个安全包装机制,如果发生异常则返回空结果。请考虑以下事项:

SELECT * FROM myschema.mytable;

我可以在客户端应用程序中进行安全包装:

try {
    result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
    result = []
}

但是我可以直接在SQL中做这样的事情吗?我想让下面的代码工作,但似乎应该放入DO $$ ... $$块,这里我迷路了。

BEGIN
    SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
    SELECT unnest(ARRAY[]::TEXT[])
END

2 个答案:

答案 0 :(得分:12)

PL / pgSQL中的异常处理

通常,plpgsql代码始终包含在BEGIN .. END块中。这可以在DO语句或函数的主体内部。块可以嵌套在内部 - 但它们不能存在于外部,不要将它与普通SQL混淆。

每个BEGIN块可以选择包含用于处理异常的EXCEPTION子句,但是需要捕获异常的函数要贵得多,因此最好先避免异常。< / p>

更多信息:

如何在示例中避免例外

DO语句无法返回任何内容。 Create a function将表和模式名称作为参数并返回您想要的任何内容:

CREATE OR REPLACE FUNCTION f_tbl_value(_tbl text, _schema text = 'public')
  RETURNS TABLE (value text) AS
$func$
DECLARE
   _t regclass := to_regclass(_schema || '.' || _tbl);
BEGIN
   IF _t IS NULL THEN
      value := ''; RETURN NEXT;    -- return single empty string
   ELSE
      RETURN QUERY EXECUTE
      'SELECT value FROM ' || _t;  -- return set of values
   END
$func$ LANGUAGE plpgsql;

致电:

SELECT * FROM f_tbl_value('my_table');

或者:

SELECT * FROM f_tbl_value('my_table', 'my_schema');
  • 假设您想要一组具有单个text列的行,或者如果该表不存在则需要空字符串。

  • 如果给定的表存在,还假设存在列value。你也可以测试一下,但是你并没有要求它。

  • 这两个参数均为区分大小写 text值。这与identifiers in SQL statements are handled的方式略有不同。如果你从不重复引用标识符,请传递小写名称,你没事。

  • 在我的示例中,架构名称默认为'public'。适应您的需求。您甚至可以完全忽略架构,默认为当前search_path

  • to_regclass()是Postgres 9.4 的新功能。对于旧版本替代:

    IF EXISTS (
       SELECT 1
       FROM   information_schema.tables 
       WHERE  table_schema = _schema
       AND    table_name = _tbl
    );
    

    这实际上是更准确,因为它可以准确测试您的需求。 更多选项和详细解释:

  • 使用动态SQL时始终防御SQL注入!演员到regclass就可以了。更多细节:

答案 1 :(得分:0)

如果您只选择一列,那么COALESCE()函数应该能够为您做到这一点

SELECT COALESCE( value, '{}'::text[] ) FROM myschema.mytable

如果您需要更多行,则可能需要创建具有类型的函数。