ОРА-06502 с ОРА-06512

У меня есть процедура, в которой я пытаюсь написать исходный код (1290 строк) в dbms_output следующим образом:

dbms_output.put_line(DBMS_METADATA.GET_DDL('FUNCTION', 'name', 'owner')); --MYPROC, line 6

Я получаю :

ORA-06502: PL/SQL: numeric or value error
ORA-06512: in "MYPROC", line 6

. Эта ошибка возникает в toad. Я могу выполнить на вкладке редактора жабы:

SELECT DBMS_METADATA.GET_DDL('FUNCTION', 'name', 'owner') FROM DUAL;

Я имею в виду, что получаю исходный код в «Сетке данных».

То же самое происходит, когда я пытаюсь сохранить код в переменной CLOB:

src CLOB;
...
src := DBMS_METADATA.GET_DDL('FUNCTION', 'name', 'owner') ; --MYPROC, line 6

Любая подсказка?

🤔 А знаете ли вы, что...
Oracle Database поддерживает различные модели данных, включая реляционные, объектные и XML-данные.


50
2

Ответы:

То, что вы говорите, не может быть правдой. DBMS_OUTPUT.PUT_LINE нельзя использовать на уровне SQL, он относится к PL/SQL.

  • Что такое MYPROC и что он содержит в строке №6?
  • Какой «редактор» «я могу выполнить в редакторе»?

Ошибка числа или значения обычно связана с тем, что вы пытаетесь сохранить «большие» значения в «маленькой» переменной:

SQL> declare
  2    l_var varchar2(2);
  3  begin
  4    l_var := 'ABC';
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4


SQL>

что, я полагаю, ты и сделал.


Другая причина - неправильно объявленная переменная, например.

SQL> declare
  2    l_var number;
  3  begin
  4    l_var := 'A';
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 4


SQL>

Я попытаюсь угадать, что вы можете делать:

SQL> set serveroutput on
SQL> DECLARE
  2     src  CLOB;
  3  BEGIN
  4     src := DBMS_METADATA.GET_DDL ('PACKAGE', 'MY_PKG', 'SCOTT');
  5     DBMS_OUTPUT.put_line ('len = ' || DBMS_LOB.getlength (src));
  6  END;
  7  /
len = 67239

PL/SQL procedure successfully completed.

SQL>

Как видите, у меня работает нормально. Пакет не такой уж и маленький (смотрите его длину), так что - не могу сказать, что вы сделали не так. Я предлагаю вам сделать то же самое, что и я: скопировать/вставить код, который я разместил выше (эти 7 строк), исправить информацию (функция, ее имя, владелец) и опубликовать результат, отредактировав исходный вопрос, а не как комментарий.


Решено

Из документации для dbms_output:

Максимальный размер строки составляет 32767 байт.

Это означает, что вы не можете передать больше за один вызов put_line. В настоящее время вы передаете весь свой CLOB, который при 1290 строках, вероятно, превысит этот предел. И ошибка, которую вы получаете, когда вы это делаете, это «ORA-06502: PL/SQL: ошибка числа или значения», как вы видите.

Вы можете разделить свой CLOB на более мелкие фрагменты, и, поскольку он уже состоит из нескольких строк, имеет смысл сделать каждый фрагмент отдельной строкой из DDL. Вы можете сделать это, ища символы новой строки, извлекая весь текст до следующего и печатая его. Вам нужно несколько переменных, чтобы отслеживать, где вы находитесь. Что-то вроде этого должно работать для вас:

declare
  src clob;
  src_length pls_integer;
  pos pls_integer := 1;
  buffer varchar2(32767);
  amount pls_integer := 32767;
begin
  src := dbms_metadata.get_ddl('FUNCTION', 'TEST_FUNCTION_1', user);
  src_length := dbms_lob.getlength(src);

  while pos < src_length loop
    -- read to next newline if there is one, rest of CLOB if not
    if dbms_lob.instr(src, chr(10), pos) > 0 then
      -- see how many charcaters there are until next newline
      amount := dbms_lob.instr(src, chr(10), pos) - pos;
      -- if there are any, read them into the buffer; otherwise clear it
      if amount > 0 then
        dbms_lob.read(src, amount, pos, buffer);
      else
        buffer := null;
      end if;
      pos := pos + amount + 1; -- skip newline character
    else
      -- no newline so read everything that is left
      amount := 32767;
      dbms_lob.read(src, amount, pos, buffer);
      pos := pos + amount;
    end if;

    dbms_output.put_line(buffer);
  end loop;
end;
/

Это не сработает, если у вас есть одна строка (без новой строки в конце или без нее), размер которой превышает 32 КБ, что, надеюсь, не будет проблемой с DDL. (Вы могли бы справиться с этим, но это привело бы к добавлению дополнительных строк новой строки, что тоже было бы нехорошо.)