问题
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:
- Make DIR_XML folder as shared folder with read/write permissions to everyone
- 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