Как исправить сообщение об ошибке «число или значение»? - PullRequest
0 голосов
/ 14 ноября 2011

Я застрял с этим вопросом все утро. Я действительно видел этот код здесь и решил использовать его для наших целей здесь.

Проблема, с которой я сталкиваюсь, заключается в том, что когда мы выполняем код, иногда он записывает файл из db в папку.

В других случаях мы получаем «ошибку числа или значения»

Может ли какой-нибудь эксперт помочь мне исправить это?

Вот код, который я использую:

create or replace
PROCEDURE getfile(pfname   VARCHAR2, display_name IN VARCHAR2)
IS
  vblob      BLOB;
  vstart     NUMBER := 1;
  bytelen    NUMBER := 32000;
  len        NUMBER;
  my_vr      RAW(32000);
  x          NUMBER;
  v_name     VARCHAR2(32760);
  lv_str_len NUMBER;
  l_output   utl_file.file_type;
BEGIN
  -- define output directory
  --lv_str_len := Length(pfname);

  --v_name := display_name||upper(substr(pfname,lv_str_len-3,lv_str_len));
  v_name := display_name;

  l_output := utl_file.Fopen('My_DIR', v_name, 'w', 32760);

  -- get length of blob
  SELECT dbms_lob.Getlength(FILENAME)
  INTO   len
  FROM   GENERAL.GUBFILE
  WHERE  gubfile_name = pfname;

  -- dbms_output.put_line('Length: '||len);
  -- save blob length
  x := len;

  -- select blob into variable
  SELECT BLOBVALUE
  INTO   vblob
  FROM   FILES
  WHERE  filename = pfname;

  -- if small enough for a single write
  IF len < 32760 THEN
    -- dbms_output.put_line('Single write ');
    utl_file.Put_raw(l_output, vblob);

    utl_file.Fflush(l_output);
  ELSE -- write in pieces
    -- dbms_output.put_line('multi write '||vstart);
    vstart := 1;

    WHILE vstart < len LOOP
        dbms_lob.READ(vblob, bytelen, vstart, my_vr);

        utl_file.Put_raw(l_output, my_vr);

        utl_file.Fflush(l_output);

        -- set the start position for the next cut
        vstart := vstart + bytelen;

        -- set the end position if less than 32000 bytes
        x := x - bytelen;

        IF x < 32000 THEN
          bytelen := x;
        END IF;
    END LOOP;
  END IF;

  dbms_output.Put_line('End');

  utl_file.Fclose(l_output);
END getfile;

Точная ошибка:

ORA-06502: PL / SQL: ошибка числа или значения ORA-06512: в «USER.GETFILE», строка 40 ORA-06512: в строке 8

1 Ответ

2 голосов
/ 14 ноября 2011

Ошибка исходит от utl_file.put_raw. Максимальный размер параметра буфера составляет 32767 байт.

Вы проверяете на IF len < 32760 THEN, однако я не вижу гарантии в вашем коде, что переменная len фактически содержит длину переменной vblob, которая является буфером в вызове put_raw.

Так что я предполагаю, что фактическая длина переменной vblob больше 32767, и это является причиной ошибки.

Поэтому я предлагаю удалить этот кусок кода:

  IF len < 32760 THEN
    -- dbms_output.put_line('Single write ');
    utl_file.Put_raw(l_output, vblob);

    utl_file.Fflush(l_output);
  ELSE

также, конечно, END IF;, и всегда используйте ветку «писать по частям».

Теперь я вижу, вы сделали это на основе примера Бурлсона, который хорош http://www.dba -oracle.com / t_writing_blob_clob_os_file.htm

но вы видите, в отличие от вас, Бурлесон получает переменную len и переменную vblob из той же таблицы и того же поля.

-- get length of blob
SELECT dbms_lob.getlength(productblob)
INTO len
FROM products
WHERE id = product_id;

-- save blob length
x := len;

-- select blob into variable
SELECT product_blob
INTO vblob
FROM products
WHERE id = product_id;

РЕДАКТИРОВАТЬ

Так что другой вариант - исправить выбор для получения длины. Это означает, что вам придется заменить этот выбор:

  -- get length of blob
  SELECT dbms_lob.Getlength(FILENAME)
  INTO   len
  FROM   GENERAL.GUBFILE
  WHERE  gubfile_name = pfname;

с этим:

  -- get length of blob
  SELECT dbms_lob.Getlength(BLOBVALUE)
  INTO   len
  FROM   FILES
  WHERE  filename = pfname;
...