Как решить проблему с Oracle DBMS_LOB - PullRequest
2 голосов
/ 28 февраля 2020

Я пытаюсь сохранить информацию о файле XML в таблице базы данных, и я использую эту процедуру:

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;

Но когда я выполняю процедуру, я получаю следующая ошибка:

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

Я не понимаю, почему путь C:\XMLS\ существует, если существует мой файл XML.

Я получаю маршрут с результатом запроса.

enter image description here

Этот результат запроса был присвоен переменной с именем GRUPO, которую я объявляю в начале процедуры, а затем Я помещаю эту переменную в качестве параметра в функцию BFILENAME, которая изначально содержит directory y filename. Вы можете просмотреть документацию BFILENAME здесь

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

В дополнение к этому я создал каталог в Oracle следующим образом:

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

Я также дал разрешения на каталог

GRANT ALL ON DIRECTORY DIR_XML TO PUBLIC;

Я тратил много времени на эту проблему и не могу найти решение. Любая помощь будет оценена.

Ответы [ 4 ]

5 голосов
/ 03 марта 2020

Из документации, которую вы связали с :

  • 'directory' - это объект базы данных, который служит псевдонимом для полного пути имя в файловой системе сервера, где файлы фактически находятся.

, поэтому GRUPO должно быть равно 'DIR_XML', а не 'C:\XMLS'. Это показано в примере в этой документации. (Существовал старый механизм pre-directory-object, основанный на пути, сохраненном в качестве параметра базы данных, но он был менее безопасным ...)

Если у вас есть только путь, вы можете найти имя каталога :

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

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

Но, как уже объяснил @Matthew, и как сказано в документации (выделение добавлено):

Объект каталога указывает псевдоним для каталога в файловой системе сервера где ...

База данных может видеть файлы только в собственной файловой системе - локальной или общей - но не в клиентских файловых системах. Если вы работаете с БД локально, то нет никакой разницы (хотя права доступа к каталогу и файлу по-прежнему имеют значение). Если вы обращаетесь к удаленной БД, она не может увидеть ваш клиентский диск C: и если вы дадите имя объекту каталога, вы все равно получите что-то вроде:

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

Вы должны поставить свой XML файлы в каталоге на сервере БД, к которому имеет доступ учетная запись операционной системы, и создание объекта каталога, который указывает на это местоположение на сервере; и затем обратитесь к имени объекта каталога, а не к пути базовой файловой системы.

5 голосов
/ 29 февраля 2020

Ошибка: ORA-22285: несуществующий каталог или файл для операции открытия файла

Я не понимаю, почему путь C: \ XMLS \ существует, если существует мой файл XML.

Причина в том, что файл XML существует на локальном жестком диске, но PL / SQL работает на сервере базы данных. Вам нужно поместить файл туда, на сервер базы данных, если вы хотите получить к нему доступ через DBMS_LOB.

0 голосов
/ 09 марта 2020

Не используйте c: \ path. Используйте сетевой путь. Убедитесь, что папка \ 123.3.3.3 \ xml \ доступна с вашего клиентского компьютера sql, а также с сервера Oracle. Если вы проверите свой файл Ora tnsnames.ora, вы можете узнать имя сервера базы данных. Проверьте, что сервер создает общую папку, а затем используйте ее. 192.168.1.0 \ xml \ Tnsnames.ora пример

ORA11 =
 (DESCRIPTION = 
   (ADDRESS_LIST =
     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.0)(PORT = 1521))
   )
 (CONNECT_DATA =
   (SERVICE_NAME = ORA12)
 )
)
0 голосов
/ 09 марта 2020

Попробуйте следующее:

  1. Сделать папку DIR_ XML общей папкой с правами на чтение и запись для всех
  2. Использовать путь к каталогу '\\ 192.168.2.100 \ dir_ xml 'вместо' C: \ DIR_ XML '

Заменить 192.168.2.100 на IP-адрес или имя машины, где C: \ DIR_ XML существует

...