try_cast
Erwin为 postgres制作了一个很棒的通用函数(复制如下)。我有兴趣将它用于 EAV 模式,其中属性与类型字段一起存储。我可以使用类似的函数(返回布尔值)作为触发器,测试值字符串是否可以转换为相应的数据类型以添加一些类型安全性。
CREATE OR REPLACE FUNCTION try_cast(_in text, INOUT _out ANYELEMENT) AS
$func$
BEGIN
EXECUTE format('SELECT %L::%s', $1, pg_typeof(_out))
INTO _out;
EXCEPTION WHEN others THEN
-- do nothing: _out already carries default
END
$func$ LANGUAGE plpgsql;
但是在测试它时(在 PG11 中),我发现如果将十进制数字字符串转换为整数类型(smallint、int 和 bigint),它会失败 - try_cast('50.0', NULL::int)
。我猜这是因为 postgres 在转换为整数之前不能将字符串转换为数字/十进制类型(这是有道理的)。try_cast('50.0', NULL::numeric)
确实有效,所以我可能会称之为足够好。
但是,我玩了这条线:
EXECUTE format('SELECT %L::%s', $1, pg_typeof(_out))
并将其更改%L
为%s
:
EXECUTE format('SELECT %s::%s', $1, pg_typeof(_out))
并且try_cast('50.0', NULL::<integer-type>)
没有问题。缺点是其他类型,例如macaddr/cidr
,在它们之前工作时无法转换
try_cast('192.168'::text, NULL::cidr) -- returns null
-- but 'SELECT '192.168'::cidr' works
我真的很好奇为什么%s
修复了数字类型转换并破坏了其他类型,以及是否有任何方法可以改进函数以满足这种极端情况。如果没有,我可以忍受numeric
,但我担心其他人将来使用这个功能而不了解它的局限性。
感谢您的任何帮助或想法!