如何修复“数字或值错误”信息?

发布于 2024-12-15 10:40:09 字数 1957 浏览 3 评论 0原文

我整个早上都被这个问题困扰了。我实际上在这里看到了这段代码,并决定将其用于我们的目的。

我遇到的问题是,当我们执行代码时,有时它会将文件从 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: numeric or value error ORA-06512: 在“USER.GETFILE”,第 40 行 ORA-06512: 在第 8 行

I have been stuck with this issue now all morning. I actually saw this code here and decide to use it for our purpose here.

The issue that I am running into is that when we execute the code, sometimes it writes a file from db to the folder.

Other times, we get "numeric or value error"

Can any expert please help me fix it?

Here is the code I am using:

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;

The exact error is:

ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "USER.GETFILE", line 40
ORA-06512: at line 8

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

画▽骨i 2024-12-22 10:40:09

该错误来自 utl_file.put_raw
缓冲区参数的最大大小为 32767 字节。

您检查 IF len < 32760 THEN,但是,我在您的代码中看不到保证 len 变量实际上保存 vblob 变量的长度,该变量是 vblob 中的缓冲区code>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;,并且始终选择“分段写入”分支。

我现在明白了,您已经根据 Burleson 示例完成了此操作,该示例很好 http://www. dba-oracle.com/t_writing_blob_clob_os_file.htm

但你看,与你不同的是,Burleson 从同一个变量中获取 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;

编辑

因此,另一个选择是修复选择以获得长度。这意味着您必须将此 select: 替换

  -- 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;

The error comes from utl_file.put_raw.
The maximum size of the buffer parameter is 32767 bytes.

You check for IF len < 32760 THEN, however, I see no guarantee in your code, that the len variable actually holds the length of the vblob variable that is the buffer in the put_raw call.

So I suppose the vblob variable's actual length is longer then 32767 and that is the reason for the error.

Hence I suggest to delete this piece of code:

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

    utl_file.Fflush(l_output);
  ELSE

also the END IF; of course, and always go for the 'write in pieces' branch.

I see now, you've done this based on the Burleson example which is good http://www.dba-oracle.com/t_writing_blob_clob_os_file.htm

but you see, unlike you, Burleson gets the len variable and the vblob variable from the same table and the same field.

-- 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;

EDIT

So an other option would be to fix the select for getting length. This means you'll have to replace this select:

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

with this:

  -- get length of blob
  SELECT dbms_lob.Getlength(BLOBVALUE)
  INTO   len
  FROM   FILES
  WHERE  filename = pfname;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文