Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Clob  [new]
-=Koba=-
Member

Откуда: Минск
Сообщений: 1972
Есть функция
function BlobToClobUTF8(Src blob) return clob is            
      Result    clob;
      iLen      integer:=DBMS_LOB.lobmaxsize;
      iSrcOffs  integer:=1;
      iDstOffs  integer:=1;
      iCSID     integer:=873;--nls_charset_id('UTF16');
      iLang     integer:=DBMS_LOB.default_lang_ctx;
      iWarn     integer;
begin 
 if not((Src is NULL) or (DBMS_LOB.GetLength(Src)=0)) then
    DBMS_LOB.CreateTemporary(Result,true);
    DBMS_LOB.ConvertToClob(Result,Src,iLen,iSrcOffs,iDstOffs,iCSID,iLang,iWarn);
 else Result:=null; end if;
 return(Result);
end BlobToClobUTF8;

Надо ли здесь освобождать Clob???
DBMS_LOB.FREETEMPORARY(Result);
28 июл 10, 14:48    [9171702]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
Proteus
Member

Откуда:
Сообщений: 1348
По идее после выхода из блока переменная должна освободиться.
28 июл 10, 14:53    [9171736]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5928
-=Koba=-,

естественно. Когда LOB перестанет быть нужным, его придётся удалить явным образом.

Proteus,

:) и вернуть несуществующий LOB?
28 июл 10, 15:01    [9171815]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
Proteus
Member

Откуда:
Сообщений: 1348
mcureenab,

Мне кажется, что вернется не тот блоб который создался в функции а его копия которая будет присвоена переменной в основном блоке. И я надеюсь что если на блоб больше нет указателей он будет освобожден. В доке не нашел точного поведения блоба в этом случае. Если знаешь покажи куда смотреть.
28 июл 10, 15:29    [9172127]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5928
Proteus,

оракл оперирует не самим LOB'ом, а локатором на LOB. return вернёт копию локатора. Но копии LOB'а, ИМХО, не будет. Затем локатор Result будет удалён, но поскольку на LOB будет ссылаться другой локатор, то сам LOB сохранится.

автор
The temporary LOB
instance will exist in your application until it goes out of scope, your session
terminates, or you explicitly free the instance.


Так что если временный LOB не покидает пределы сервера, то он должен удалиться.

Здесь так и происходит.

declare
lob1 CLOB;
BEGIN
DBMS_LOB.CREATETEMPORARY(lob1,TRUE, DBMS_LOB.SESSION);
lob1 := 'SSSS';
-- :lob1 := lob1;
end;
/


Но у TC имеет место return и куда уйдёт этот LOB не ясно.

Интересная ситуация возникает, когда LOB локатор уходит на хост, где оракл не может проследить его scope.

var lob1 clob
declare
lob1 CLOB;
BEGIN
DBMS_LOB.CREATETEMPORARY(lob1,TRUE, DBMS_LOB.CALL);
lob1 := 'SSSS';
:lob1 := lob1;
end;
/
select * from v$temporary_lobs;

Выполняя этот скриптик многократно, видим что в

       SID CACHE_LOBS NOCACHE_LOBS ABSTRACT_LOBS
---------- ---------- ------------ -------------
...
1565 9 0 0
...

число CACHE_LOBS прирастает с каждым разом.

Т.е. в данном случае имеет место утечка памяти.

Только завершение сессии или

exec DBMS_LOB.FREETEMPORARY(:lob1);

удаляет временный LOB на сервере.

Тут я смог удалить последний из созданных LOB'ов.

SQL> select * from v$temporary_lobs;

       SID CACHE_LOBS NOCACHE_LOBS ABSTRACT_LOBS
---------- ---------- ------------ -------------
...
      1565          8            0             0
...

Локаторы остальных были утрачены.


SQL> exec DBMS_LOB.FREETEMPORARY(:lob1);
BEGIN DBMS_LOB.FREETEMPORARY(:lob1); END;

*
ERROR at line 1:
ORA-22275: invalid LOB locator specified
ORA-06512: at "SYS.DBMS_LOB", line 533
ORA-06512: at line 1


Аналогичная ситуация наблюдается и при сохранении LOB в глобальной переменной пакета.

DBMS_LOB.CREATETEMPORARY просто перезаписывает эту переменную не заботясь о том, что она ссылается на какой то временный LOB.
28 июл 10, 16:21    [9172659]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
Proteus
Member

Откуда:
Сообщений: 1348
DECLARE
  lob1 CLOB;
  PROCEDURE print(ptxt VARCHAR2) IS
    v_str VARCHAR2(255);
  BEGIN
    SELECT 'ABSTRACT_LOBS:'||t.ABSTRACT_LOBS || ', CACHE_LOBS:' || t.CACHE_LOBS || ', NOCACHE_LOBS:' ||
           t.NOCACHE_LOBS
      INTO v_str
      FROM v$temporary_lobs t
     WHERE t.SID = sys_context('USERENV', 'SID');
    dbms_output.put_line(ptxt || ' =>' || v_str);
  EXCEPTION
    WHEN no_data_found THEN
      dbms_output.put_line('нет');
  END;
  PROCEDURE test(p1 IN OUT CLOB) IS
  BEGIN
      p1:='copy';
      print('stage 2.5');
  END;
BEGIN
  print('stage 1  ');
  dbms_lob.createtemporary(lob1, TRUE);
  print('stage 2  ');
  test(lob1);
  print('stage 4  ');
  dbms_lob.freetemporary(lob1);
  print('stage 5  ');
END;

Вот такой скрипт. А вот его результат.

stage 1 =>ABSTRACT_LOBS:0, CACHE_LOBS:0, NOCACHE_LOBS:0
stage 2 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 2.5 =>ABSTRACT_LOBS:0, CACHE_LOBS:2, NOCACHE_LOBS:0
stage 4 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 5 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0

Можно заметить что на шаге 2.5 образовалось 2 лоба но на шаге 4 остался только 1 при этом никаких освобождений не вызывалось. А на шаге 5 хоть и было вызвано освобождение лоба тем не менее он остался до завершения.
DECLARE
  lob1 CLOB;
  PROCEDURE print(ptxt VARCHAR2) IS
    v_str VARCHAR2(255);
  BEGIN
    SELECT 'ABSTRACT_LOBS:'||t.ABSTRACT_LOBS || ', CACHE_LOBS:' || t.CACHE_LOBS || ', NOCACHE_LOBS:' ||
           t.NOCACHE_LOBS
      INTO v_str
      FROM v$temporary_lobs t
     WHERE t.SID = sys_context('USERENV', 'SID');
    dbms_output.put_line(ptxt || ' =>' || v_str);
  EXCEPTION
    WHEN no_data_found THEN
      dbms_output.put_line('нет');
  END;
  FUNCTION test RETURN CLOB IS
    RESULT CLOB;
  BEGIN
      dbms_lob.createtemporary(RESULT, TRUE);
      print('stage 2  ');
      RESULT:='++++';
      print('stage 3  ');
      RETURN(RESULT);
  END;
BEGIN
  print('stage 1  ');
  lob1:= test;
  print('stage 4  ');
  dbms_lob.freetemporary(lob1);
  print('stage 5  ');
END;
stage 1   =>ABSTRACT_LOBS:0, CACHE_LOBS:0, NOCACHE_LOBS:0
stage 2 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 3 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 4 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 5 =>ABSTRACT_LOBS:0, CACHE_LOBS:0, NOCACHE_LOBS:0

Справедливости ради стоит отметить, что если смоделировать ситуацию ТС, то создание блоба в функции с последующим возвратом ее в основной блок и освобождением точно соответствует поведению описанному mcureenab.

Странно но если изменить чуть тест на вот такой.
DECLARE
  lob1 CLOB;
  PROCEDURE print(ptxt VARCHAR2) IS
    v_str VARCHAR2(255);
  BEGIN
    SELECT 'ABSTRACT_LOBS:'||t.ABSTRACT_LOBS || ', CACHE_LOBS:' || t.CACHE_LOBS || ', NOCACHE_LOBS:' ||
           t.NOCACHE_LOBS
      INTO v_str
      FROM v$temporary_lobs t
     WHERE t.SID = sys_context('USERENV', 'SID');
    dbms_output.put_line(ptxt || ' =>' || v_str);
  EXCEPTION
    WHEN no_data_found THEN
      dbms_output.put_line('нет');
  END;
  FUNCTION test RETURN CLOB IS
    RESULT CLOB;
  BEGIN
      dbms_lob.createtemporary(RESULT, TRUE);
      print('stage 2  ');
      RESULT:='++++';
      print('stage 3  ');
      RETURN(RESULT);
  END;
BEGIN
  dbms_lob.createtemporary(lob1, TRUE);
  print('stage 1  ');
  lob1:= test;
  print('stage 4  ');
  dbms_lob.freetemporary(lob1);
  print('stage 5  ');
END;
stage 1   =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 2 =>ABSTRACT_LOBS:0, CACHE_LOBS:2, NOCACHE_LOBS:0
stage 3 =>ABSTRACT_LOBS:0, CACHE_LOBS:2, NOCACHE_LOBS:0
stage 4 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 5 =>ABSTRACT_LOBS:0, CACHE_LOBS:0, NOCACHE_LOBS:0

То на интервале от 3 до 4 шага один из лобов пропал. хоть его и никто не освобождал.
28 июл 10, 18:51    [9173723]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5928
Proteus,

автор
stage 1 =>ABSTRACT_LOBS:0, CACHE_LOBS:0, NOCACHE_LOBS:0
stage 2 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 2.5 =>ABSTRACT_LOBS:0, CACHE_LOBS:2, NOCACHE_LOBS:0
stage 4 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0
stage 5 =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0


появление "лишнего" LOB после

p1:='copy';

это проявление документированной фичи. Таким способом PL/SQL машина реализует семантику передачи LOB параметра по значению (без NOCOPY). Т.е. пока мы только читаем LOB, мы имеем дело с исходным объектом, но как только пытаемся изменить его, PL/SQL машина создаёт копию LOB и вносит изменения в эту копию.

Если процедура завершается успешно, IN LOB удаляется, и в вызывающий блок возвращается OUT локатор его изменённой копии. ИМХО.

Если сделать так

PROCEDURE test(p1 IN OUT NOCOPY CLOB) IS

лишний лоб не появляется. Т.е. имеем семантику передачи параметра по ссылке.

А вот это

stage 5   =>ABSTRACT_LOBS:0, CACHE_LOBS:1, NOCACHE_LOBS:0

смахивает на баг. Хотя повторное выполнение PL/SQL блока показывает, что зависший LOB был удалён.


Код

lob1:= test;

демонстрирует корректное удаление LOB, при замещении его локатора на локатор другого LOB.

С другой стороны dbms_lob.createtemporary просто записывает в переменную новый локатор не заботясь о корректном удалении предыдущего локатора и его LOB.

Т.е. после

  dbms_lob.createtemporary(lob1, TRUE);
  dbms_lob.createtemporary(lob1, TRUE);
  dbms_lob.createtemporary(lob1, TRUE);

мы получим не один новый LOB, а три!

Утечку памяти можно исключить, если перед вызовом dbms_lob.createtemporary обнулять переменную:

   lob1 := null; dbms_lob.createtemporary(lob1, TRUE);
   lob1 := null; dbms_lob.createtemporary(lob1, TRUE);
   lob1 := null; dbms_lob.createtemporary(lob1, TRUE);

Тут мы в итоге получаем только один новый LOB.
28 июл 10, 19:35    [9173889]     Ответить | Цитировать Сообщить модератору
 Re: Clob  [new]
Proteus
Member

Откуда:
Сообщений: 1348
Да ты прав.
По поводу остатков.
Количество оставшихся блобов равно максимальному количеству in out без nocopy параметров типа блоб в вызванных процедурах.
Похоже на временную структуру для передачи параметров.
28 июл 10, 20:10    [9174083]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить