Il y a quelques jour un client m'est revenu avec un problème au moment de créer un fichier avec UTL_FILE, ci-dessous vous pouvez voir le script utilisé pour le test et le message d'erreur obtenu.
Version de Bd, 11.2.0.3 sous Solaris 5.10.
Version de Bd, 11.2.0.3 sous Solaris 5.10.
CONNECT COMPTEORACLE@MYBD
set serveroutput on ;
declare
fich utl_file.file_type;
begin
fich := utl_file.fopen('REP_EVTA','monfichier.txt','W',32767);
utl_file.put_line (fich,'Test');
utl_file.fclose(fich);
dbms_output.put_line ('Terminé');
exception
when others then
dbms_output.put_line ('Erreur : ' || sqlcode);
dbms_output.put_line (substr(sqlerrm,1,200));
utl_file.fclose_all;
end;
/
Erreur : -29283
ORA-29283: opération non valide sur le fichier
ORA-06512: à "SYS.UTL_FILE", ligne 536
ORA-29283: opération non valide sur le fichier
En regardant, il faut commencer par valider que l'utilisateur a vraiment les privilèges pour exécuter le UTL_FILE ou qu'au moins ils n'ont pas été révoqués du PUBLIC.
SELECT TABLE_NAME, PRIVILEGE, GRANTEE
FROM DBA_TAB_PRIVS
WHERE TABLE_NAME ='UTL_FILE' ;
TABLE_NAME PRIVILEGE GRANTEE
--------------- -------------------------------- ----------------
TABLE_NAME PRIVILEGE GRANTEE
--------------- -------------------------------- ----------------
UTL_FILE EXECUTE PUBLIC
Jusqu'à ici tout est correct.
En suite, il faut valider que le compte "oracle" a les privilèges sur le répertoire "REP_EVTA"
SELECT TABLE_NAME, PRIVILEGE, GRANTEE
FROM DBA_TAB_PRIVS
WHERE GRANTEE= 'COMPTEORACLE' AND TABLE_NAME = 'EVTA' ;
TABLE_NAME PRIVILEGE GRANTEE
----------------- ------------------------- --------------
REP_EVTA EXECUTE COMPTEORACLE
REP_EVTA READ COMPTEORACLE
TABLE_NAME PRIVILEGE GRANTEE
----------------- ------------------------- --------------
REP_EVTA EXECUTE COMPTEORACLE
REP_EVTA READ COMPTEORACLE
REP_EVTA WRITE COMPTEORACLE
Maintenant, validez si le répertoire physique existe et il est bel et bien accessible. Une recherche sur DBA_DIRECTORIES vous permettra de connaître le chemin du répertoire.
SELECT DIRECTORY_PATH
FROM DBA_DIRECTORIES
WHERE DIRECTORY_NAME='REP_EVTA' ;
DIRECTORY_PATH
--------------------------------------------------------
/chemin/sur/serveur/unix/repertoire
SQL> host ls -l /chemin/sur/serveur/unix/repertoire
-rw-rw-r-- 1 2067 sql_group 13824 Oct 7 2014 fichier01.xls
-rw-rw-r-- 1 2067 sql_group 33871 Oct 2 2014 fichier02.csv
...
SQL> host touch /chemin/sur/serveur/unix/repertoire/myfile.txt
SQL> host ls -l /chemin/sur/serveur/unix/repertoire/myfile.txt
-rw-r--r-- 1 oracle oinstall 0 Apr 10 14:31 /chemin/.../repertoire/myfile.txt
SQL> host ls -l /chemin/sur/serveur/unix/repertoire/myfile.txt
-rw-r--r-- 1 oracle oinstall 0 Apr 10 14:31 /chemin/.../repertoire/myfile.txt
Juste pour m'assurer, j'ai répété le même essai avec le compte "sys" mais sans passer par le Listener, soit directement avec un "sqlplus / as sysdba" et ma création a bien réussi cette fois.
PL/SQL procedure successfully completed.
Pour vérifier, cette fois j'ai testé une autre fois avec "sys" mais en passant par le Listener, soit avec "sqlplus sys@MYDB as sysdba". Cette fois j'obtiens une autre fois l'erreur.
Erreur : -29283
ORA-29283: opération non valide sur le fichier
ORA-06512: à "SYS.UTL_FILE", ligne 536
ORA-29283: opération non valide sur le fichier
ORA-29283: opération non valide sur le fichier
ORA-06512: à "SYS.UTL_FILE", ligne 536
ORA-29283: opération non valide sur le fichier
C'est le moment d'aller regarder du côté OS et du "listener"
$ ps -ef | grep lsn | grep MYBD
grid 13777 1598 0 Jun 21 ? 190:23 /u01/.../bin/tnslsnr LSN_MYBD -inherit
Je vois qu'il a été reparti par le compte "grid", et cela peut expliquer le problème, pour vérifier, il faudrait regarder la définition du compte "grid"
$ id -a grid
uid=990(grid) gid=996(oinstall) groups=14(sysadmin),990(asmadmin),991(asmdba),992(asmoper),980(sql_group)
Si on remonte un niveau dans le répertoire
$ ls -l /chemin/sur/serveur/unix/
drwxrwx--- 2 2067 sql_group 32K Apr 14 14:42 repertoire
Le répertoire appartient au même groupe, mais le "owner" est un compte qui n'existe pas sur le serveur.
$ is -a oracle
$ is -a oracle
uid=991(oracle) gid=996(oinstall) groups=14(sysadmin)....980(sql_group)
Pour le compte "oracle"
$ umask
0022
Pour le compte "grid"
$ umask
0002
- J'ai vérifié la dernière date où le listener a été reparti et il date d'il y a 3 mois, donc, pour m'assurer je repars le listener afin que le compte "grid" prenne en compte les groupes auquel il a été assigné. je modifié le umask avant de le repartie, mais malgré cela, je relance le test et même erreur.
- En plus, j'ai pu constater que si je me connecte avec le compte "grid" et repars le listener avec "lsnrctl" et non pas avec "srvctl" -ce qu'on ne devrait pas faire mais qui a servi juste à mes tests-, le script est capable de créer le fichier.
- Donc, c'est clair que c'est un problème de privilèges.
À ce point-ci, on a deux possibles solutions :
- Assigner comme "owner" du répertoire au compte propriétaire du processus "oracle", soit le configurer comme -idée suggérée par un collègue-. Bien sûr avec un chmod 777 au rpertoire avait démontré que cela fonctionnait mais cela serait moins sécurisant.
- Suivre la note Oracle 1980622.1 qui demande un patch -qui existe seulement pour le moment pour Linux- et en plus de faire une modification au listener configuré auprès du srvctl
Dans mon cas je ne peux pas appliquer ce patch parce que je suis sous Solaris. Donc la première alternative a aidé à corriger le problème.