How to solved problem with Oracle DBMS_LOB

痴心易碎 提交于 2021-02-10 05:52:16

问题


I am trying to save the information of an XML file in a database table and I am using this procedure:

create or replace PROCEDURE P_FILEUPLOAD_XML (P_CMTT_CODE IN NUMBER DEFAULT 15, P_TEXT IN VARCHAR2, P_TEXT_NAR IN VARCHAR2, P_PATH IN VARCHAR2, P_FILENAME IN VARCHAR2, P_RET_VAL OUT NUMBER) IS

GRUPO       VARCHAR2(20);
l_dir       CONSTANT VARCHAR2(35) := P_PATH;
l_fil       CONSTANT VARCHAR2(30) := P_FILENAME; 
l_loc       BFILE; -- Pointer to the BFILE
l_ret       BOOLEAN := FALSE; -- Return value
l_pos       NUMBER := 1; -- Current position in the file (file begins at position 1)
l_sum       number default 8000; -- Amount of characters have been read
l_buf       VARCHAR2(32767); -- Read Buffer
l_sen       CONSTANT RAW(100) := UTL_RAW.CAST_TO_RAW(CHR(10)); -- Character at the end of the file is NEWLINE (ascii = 10)
l_end       NUMBER; -- End of the current word which will be read
l_counter NUMBER := 0; -- Counter for line sequence
l_line      VARCHAR2(32767); -- Contains the info line by line for insert

BEGIN

SELECT TEXTO INTO GRUPO FROM gzvcatg
         UNPIVOT ((codigo, texto) FOR gzvcatg_external_code IN (
            (gzvcatg_external_code1, gzvcatg_desc1) AS '1')
         WHERE GZVCATG_GROUP = 'TIT_ELEC'
            AND CODIGO = 'PATH';

     -- Mapping the physical file with the pointer to the BFILE
        l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');

    -- Open the file in READ_ONLY mode
       DBMS_LOB.OPEN(l_loc,DBMS_LOB.LOB_READONLY);
       LOOP
          l_counter := l_counter + 1; -- Counter for sequence
          -- Calculate the end of the current word
          l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);

          -- Process end-of-file
          IF (l_end = 0) THEN
            l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);
            l_sum := l_end - l_pos - 1;
            EXIT;
          END IF;

          -- Read until end-of-file
          l_sum := l_end - l_pos;
          DBMS_LOB.READ(l_loc,l_sum,l_pos,l_buf);
          l_line := UTL_RAW.CAST_TO_VARCHAR2(l_buf);

        BEGIN 
            INSERT INTO SPRCMNT (
                         SPRCMNT_CMTT_CODE,
                         SPRCMNT_TEXT,
                         SPRCMNT_TEXT_NAR)
                                VALUES(P_CMTT_CODE,
                                       P_TEXT,
                                       P_TEXT_NAR);    
             EXCEPTION WHEN OTHERS THEN 
             ROLLBACK;           
        END;
    END LOOP;    
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line('Error:' || SQLERRM);
        DBMS_LOB.CLOSE(l_loc);
        P_RET_VAL := 3;
        dbms_output.put_line('P_RET_VAL:' || P_RET_VAL);    
END;

But when I execute the procedure I get the following error:

Error:ORA-22285: non-existent directory or file FILEOPEN operation

I do not understand why the path C:\XMLS\ does exist if my XML file exists .

I get the route with the result of the Query.

This result of the Query was assigned to a variable called GRUPO, which is what I declare at the beginning of the procedure, and then I place this variable as a parameter in the function BFILENAME, which originally contains the directory y filename. You can see documentation BFILENAME here

l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');

In addition to this I have created a directory in Oracle as follows:

CREATE OR REPLACE DIRECTORY DIR_XML as 'C:\XMLS\';

I also gave permissions to the directory

GRANT ALL ON DIRECTORY DIR_XML TO PUBLIC;

I've been wasting a lot of time with this problem and I can't find any solution. Any help will be appreciated.


回答1:


From the documentation you linked to:

  • 'directory' is a database object that serves as an alias for a full path name on the server file system where the files are actually located.

so GRUPO should evaluate to 'DIR_XML' rather than 'C:\XMLS'. That is shown in the example in that documentation. (There was an old pre-directory-object mechanism based on a path stored as a database parameter, but that was less secure...)

If all you have is the path you can look up the directory name:

select directory_name from all_directories where directory_path = 'C:\XMLS'

bearing in mind that directory paths don't have to be unique, so you may have to deal with duplicates.

But as @Matthew already explained, and as the documentation says (emphasis added):

A directory object specifies an alias for a directory on the server file system where ...

The database can only see files on its own filesystem - local or shared - and not those on client filesystems. If you are running the DB locally as well then there is no difference (though directory and file permissions still matter). If you are accessing a remote DB then it cannot see your client C: drive, and if you give the directory object name you'll still get something like:

ORA-22288: file or LOB operation FILEOPEN failed
No such file or directory

You have to put your XML files in a directory on the DB server that the operating system account has access to, and create a directory object that points to that location on the server; and then refer to the directory object name, not the underlying filesystem path.




回答2:


Error:ORA-22285: non-existent directory or file for fileopen operation

I do not understand why the path C:\XMLS\ does exist if my XML file exists .

The reason is the the XML file exists on your local hard drive, but PL/SQL runs on the database server. You need to put the file there, on the database server, if you want to access it via DBMS_LOB.




回答3:


Try following:

  1. Make DIR_XML folder as shared folder with read/write permissions to everyone
  2. Use directory path '\\192.168.2.100\dir_xml' instead of 'C:\DIR_XML'

Replace 192.168.2.100 with the IP address or machine name where C:\DIR_XML exists




回答4:


Don't use c:\ path. Use a network path.Make sure \123.3.3.3\xml\ folder is accessible from your sql client machine as well as from Oracle server . If you check your Ora tnsnames.ora file you can find out your database server name. Check that server make a shared folder and then use it. 192.168.1.0\xml\ Tnsnames.ora example

ORA11 =
 (DESCRIPTION = 
   (ADDRESS_LIST =
     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.0)(PORT = 1521))
   )
 (CONNECT_DATA =
   (SERVICE_NAME = ORA12)
 )
)


来源:https://stackoverflow.com/questions/60457929/how-to-solved-problem-with-oracle-dbms-lob

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!