使用Postgres 11.5,从昨天开始我一直在研究CREATE DOMAIN
,并想阐明它们如何/不能帮助函数参数。理想情况下,我想使用一个域轻松地筛选参数输入,但具有有用的错误响应。举例来说,我使用的是简单的第一种情况,即一个域,该域阻止null和空字符串:
CREATE DOMAIN text_not_empty AS
text
NOT NULL
CHECK (value <> '');
我尝试将其作为表的字段类型进行了尝试,这很棒。当我们不允许使用空字符串时,这似乎是一种在没有单独规则或触发器的情况下实现约束的简单方法。我希望在函数参数上获得类似的好处。但是,对于函数,我们确实需要明确的错误消息,因为调用者可能来自Node或其他环境。
作为示例,这是一个虚拟函数,它需要一个字符串,对输入进行显式检查:
CREATE OR REPLACE FUNCTION api.test_this_function(in_text text)
RETURNS int
LANGUAGE plpgsql
AS $function$
BEGIN
IF in_text = '' THEN
RAISE EXCEPTION USING
message = 'Input text must be supplied',
detail = 'Deets',
hint = 'Supply a search string',
errcode = 'KC123'; -- Custom code
END IF;
RETURN 1;
END;
$function$
这很好,但是我希望域可以简化这种情况。据我所知,域wont不能改善功能,因为该函数永远不会抓住错误。如果我已阅读文档并正确理解了我的实验,则只能RAISE
inin BEGIN...END
块。如果是这样,人们如何建议审核输入?我是否缺少域名的机会?
为了充实我基于印象的功能,以下功能确实使用了基于域的检查以及(愚蠢的)自定义检查:
CREATE OR REPLACE FUNCTION api.domain_test(in_text text_not_empty)
RETURNS timestamptz
AS $BODY$
BEGIN
IF in_text = 'foo' THEN
RAISE EXCEPTION USING
message = 'Invalid search string',
hint = 'Supply a search string other than ''foo''.',
errcode = 'KC123'; -- Custom code
END IF;
RETURN now();
END;
$BODY$
LANGUAGE plpgsql;
因此,它应该在没有参数,空参数,空字符串或'foo'字符串时失败。否则,它应该返回一个时间戳。我尝试了这五种情况,如下所示:
select * from domain_test(); -- 1 : Fails to reach the method.
select * from domain_test(null); -- 2 : Fails before entering method.
select * from domain_test(''); -- 3 : Fails before entering method.
select * from domain_test('foo'); -- 4 : Fails on custom exception.
select * from domain_test('a'); -- 5 : Succeeds.
我已经阐明了每个语句通过函数所能达到的程度。该图比代码还清晰,但是有时候我发现尝试制作一个图很有帮助,只是看看我是否掌握了所有内容。
我不是在问一个特定的代码问题,但是如果有人可以确认我的错误被捕获和处理的模型正确且完整,那将是一个很大的帮助。一旦我了解了Postgres如何“思考”这些东西,对我来说也将更容易进行推理。
null
和空字符串大小写永远不会到达BEGIN
块,因此似乎没有办法使用RAISE
自定义message
,hint
等。全局错误处理程序,还是我忽略的更广泛的catch
系统?
您的见解是准确的,是错误
select domain_test('');
ERROR: value for domain text_not_empty violates check constraint "text_not_empty_check"
是在解决函数参数类型的阶段提出的,因此该函数从不执行。如果您的目的是自定义错误消息,则自定义域无济于事。
没有全局错误处理程序。唯一的选择是在另一个代码块中调用该函数
do $$
begin
select domain_test('');
exception when others then
raise exception 'my error message';
end $$;
ERROR: my error message
CONTEXT: PL/pgSQL function inline_code_block line 5 at RAISE
尽管看来,您的原始方法没有自定义域会更有意义。