Как проверить все атрибуты объекта на NULL?

Переменная объектного типа может быть NULL. Выловить эту ситуацию очень просто строкой:

if v_obj is null then ...

Но что, если сама переменная инициализирована, но при этом абсолютно каждый атрибут содержит значение NULL? С массивами всё просто. Мы можем отловить этот момент:

if v_arr is null or v_arr is empty then ...

Есть ли подобный способ понять, что все атрибуты объекта содержат пустое значение?

Например:

create or replace type t_obj as object (
        a number,
        b number,
        c number,
        constructor function t_obj return self as result);
/
create or replace type body t_obj as
constructor function t_obj return self as result is
    begin
        return;
    end;
end;
/
declare
  v_obj t_obj;
begin

  if v_obj is null /* or ??? */  
    then dbms_output.put_line('v_obj is null'); 
    else dbms_output.put_line('v_obj is not null'); 
  end if;

  v_obj := t_obj();
  if v_obj is null /* or ??? */ 
    then dbms_output.put_line('v_obj is null'); 
    else dbms_output.put_line('v_obj is not null'); 
  end if;

  v_obj.a := 5;
  if v_obj is null /* or ??? */  
    then dbms_output.put_line('v_obj is null'); 
    else dbms_output.put_line('v_obj is not null');
  end if;

end;

В результате, в консоли мы увидим:

v_obj is null
v_obj is not null
v_obj is not null

А хотелось бы увидеть (после замены ??? и раскрытия комментариев)

v_obj is null
v_obj is null
v_obj is not null

Как вариант вижу: добавить MAP MEMBER FUNCTION в тело типа объекта и if v_obj = t_obj(). Но, к сожалению, отсутствует доступ к коду типа (поставляется генератором).


Ответы (1 шт):

Автор решения: 0xdb

Встроенной функции, которая проверяет все атрибуты на NULL, нет.

Если добaвить свою функцию в тип не представляется возможным, то самое простое, добавить логику проверки явно в код:

if obj is null or (obj.a is null and obj.b is null and obj.c is null) then [...] 

Можно коненчно сделать более комфортно динамическим запросом, но за счёт потери производительности. Создайте для каждого типа перегруженую функцию:

create or replace function isempty (o t_obj) return boolean is
    expr varchar2 (32000);
    res boolean;
begin 
    for r in (select attr_name from user_type_attrs where type_name='T_OBJ') loop
        expr := expr||'o.'||r.attr_name||' is null and ';
    end loop;
    execute immediate 'declare o t_obj := :o; 
        begin :r := ('||rtrim (expr, ' and ')||'); 
        end;' using o, out res; 
    return res;
end;
/

Пример блока из вопроса вернёт ожидаемый результат:

declare
    obj t_obj;
begin
    if obj is null or isempty (obj)  
        then dbms_output.put_line ('obj is null or empty'); 
        else dbms_output.put_line ('obj is not null'); 
    end if;
    obj := t_obj();
    if obj is null or isempty (obj)
        then dbms_output.put_line('obj is null or empty'); 
        else dbms_output.put_line('obj is not null'); 
    end if;
    obj.a := 5;
    if obj is null or isempty (obj)
        then dbms_output.put_line('obj is null or empty'); 
        else dbms_output.put_line('obj is not null');
    end if;
end;
/
obj is null or empty
obj is null or empty
obj is not null
→ Ссылка