Postgresql 如何测试给定的文本列是否是有效的oid

Postgresql 如何测试给定的文本列是否是有效的oid,postgresql,plpgsql,typechecking,Postgresql,Plpgsql,Typechecking,在PL/pgSQL中,我有一个列可能包含也可能不包含oid。我需要检测它是否存在 目前我是这样做的: select oidtext from t into x where name = fname; if found then begin select x::oid into looid; exception when SQLSTATE '22P02' then -- invalid oid null; cr

在PL/pgSQL中,我有一个列可能包含也可能不包含oid。我需要检测它是否存在

目前我是这样做的:

  select oidtext from t into x where name = fname;
  if found then
    begin
        select x::oid into looid;
    exception
        when SQLSTATE '22P02' then -- invalid oid    
           null;
create or replace function oid_or_null(text)
returns oid language plpgsql immutable as $$
begin
    return $1::oid;
exception when invalid_text_representation then
    return null;
end $$;

select oid_or_null('123'), oid_or_null('abc');

 oid_or_null | oid_or_null 
-------------+-------------
         123 |            
(1 row) 

但这感觉有点不舒服。是否存在阳性测试,即此文本列是有效的x类型,还是有效的强制转换?

似乎唯一的方法是捕获异常,但您可以通过以下方便的函数执行此操作:

  select oidtext from t into x where name = fname;
  if found then
    begin
        select x::oid into looid;
    exception
        when SQLSTATE '22P02' then -- invalid oid    
           null;
create or replace function oid_or_null(text)
returns oid language plpgsql immutable as $$
begin
    return $1::oid;
exception when invalid_text_representation then
    return null;
end $$;

select oid_or_null('123'), oid_or_null('abc');

 oid_or_null | oid_or_null 
-------------+-------------
         123 |            
(1 row) 
您可以创建更通用的布尔函数:

create or replace function is_valid_cast(text, text)
returns boolean language plpgsql immutable as $$
begin
    execute format('select %L::%I', $1, $2);
    return true;
exception when others then
    return false;
end $$;

select 
    is_valid_cast('123', 'oid') as oid, is_valid_cast('abc', 'oid') as not_oid,
    is_valid_cast('2018-10-10', 'date') as date, is_valid_cast('2018-20-20', 'date') as not_date;

 oid | not_oid | date | not_date 
-----+---------+------+----------
 t   | f       | t    | f
(1 row)     

我的解决方案不需要捕获错误:

CREATE FUNCTION is_oid(text) RETURNS boolean
   LANGUAGE sql IMMUTABLE STRICT AS
$$SELECT CASE WHEN trim(leading '0' from $1) ~ '^\d{1,10}$'
              THEN $1::bigint BETWEEN 0 AND 4294967295
              ELSE FALSE
         END$$;

oid是一个4字节无符号整数,因此它必须由不超过10个数字组成,并且必须介于0和4294967295之间。

我考虑过类似的方法,但这种解析可能有点不准确,例如“01234567890”::oid是有效的。我没有想到这一点;问题是没有内置的通用trycast或istype函数。当$1~'^0*\d{1,10}$'时,我将坚持使用基于异常的方法,或者在这种情况下使用。。。然后$1::bigint<4294967296…通用oid或某种类型的对象标识符,如regclass、'regproc`等?@ErwinBrandstetter在我的例子中oid将是一个较大的对象oid。对于公共对象标识符有一些方便的函数:to_regclass、to_regproc等。请参阅:但不适用于大型对象ID。这个值是一个有效的OID是否足够,或者你真的想检查它是否是一个有效的PGY-LARGEAR对象?LID?我想测试它是否是一个有效的OID,我知道它是Lo-OID或者一个向导,我会考虑Laurenz的函数,因为带有异常子句的函数要昂贵得多。